Hi there mates, I’m rather new to HLSL and monogame. I’m following this tutorial, but the result isn’t quite what I expected and I’m struggling to figure out why.
Game1.cs:
protected override void Draw(GameTime gameTime)
{
// Create a Light Mask to pass to the pixel shader
GraphicsDevice.SetRenderTarget(lightsTarget);
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
spriteBatch.Draw(lightMask, new Vector2(0, 0), Color.White);
spriteBatch.End();
// Draw the main scene to the Render Target
GraphicsDevice.SetRenderTarget(mainTarget);
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(surge, new Vector2(0, 0), Color.White);
spriteBatch.End();
// Draw the main scene with a pixel
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
lightingEffect.Parameters["lightMask"].SetValue(lightsTarget);
lightingEffect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Draw(mainTarget, Vector2.Zero, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
LightEffect.fx:
sampler s0;
texture lightMask;
sampler lightSampler = sampler_state{Texture = (lightMask); AddressU = CLAMP; AddressV = CLAMP;};
float4 PixelShaderLight(float2 coords: TEXCOORD0) : COLOR0
{
float4 color = tex2D(s0, coords);
float4 lightColor = tex2D(lightSampler, coords);
return color * lightColor;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_4_0_level_9_1 PixelShaderLight();
}
}
Resulting Screen:
Any guidance would be greatly appreciated!
EDIT: This is the expected positioning without the effect. In the previous image, the screen is split in 4, rotated 180 degrees and scaled down. The mouse also moves invertedly.
What is the result you’re expecting? The screenshot you posted looks fine to me.
I edited the post to show the expected result.
What is your rendertarget’s size? Is it possible it’s bigger then your resulotion? E.g. window is 800,600. Rendertarget is 1280, 768. That would explain the offset.
Because to me the code looks fine
Both the render targets are 800x480:
var pp = GraphicsDevice.PresentationParameters;
lightsTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight);
mainTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight);
EDIT
Additionally, if I change the SpriteSortMode of the third sprite batch to anything other than immediate, it draws correctly but the black overlay and lighting effect are lost.
I had an similar issue. Try to add a Vertex-Shader-Function too.
float4x4 World;
float4x4 View;
float4x4 Projection;
struct VertexShaderInput
{
float2 TexCoord : TEXCOORD0;
float4 Position : SV_Position0;
float4 Color : COLOR0;
};
struct VertexShaderOutput
{
float2 TexCoord : TEXCOORD0;
float4 Position : SV_Position0;
float4 Color : COLOR0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
output.Color = input.Color;
return output;
}
technique ShaderName
{
pass ShaderName
{
VertexShader = compile VS_SHADERMODEL VertexShaderFunction();
PixelShader = compile PS_SHADERMODEL PixelShaderFunction();
}
}
and pass variables to the shader:
// Für den Vertex-Shader-Teil
this.effect.Parameters[“View”].SetValue(Matrix.Identity);
this.effect.Parameters[“World”].SetValue(Matrix.Identity);
this.effect.Parameters[“Projection”].SetValue(Matrix.CreateOrthographicOffCenter(0, this.Camera.Viewport.Width, this.Camera.Viewport.Height, 0, 0, -1));
Edit: I hate that formating for code here… it is realy annoying
@EnemyArea Seeing as the Sprite Sort Mode affects the positioning, I don’t think the shader is the problem, unless I am missing something :?
Shaders only work in SpriteSortMode.Immediate, so I would say its a shader problem. Have you give it a try ?
Ah I wasn’t aware of that. I tried it but it just shows a cornflower blue screen.
Solved it! Here’s the article that helped. It also explains why adding a vertex shader solved it for you @EnemyArea. The problem was with the PixelShaderLight constructor.
Here is my final .fx file:
sampler s0;
texture lightMask;
sampler lightSampler=sampler_state { Texture=<lightMask>; };
float4 PixelShaderLight(float4 pos: SV_POSITION, float4 color1: COLOR0, float2 coords: TEXCOORD0): SV_TARGET0
{
float4 color=tex2D(s0, coords);
float4 lightColor=tex2D(lightSampler, coords);
return color * lightColor;
}
technique Technique1
{
pass P0 {
PixelShader=compile ps_4_0_level_9_1 PixelShaderLight();
}
}
And here’s the desired result:
Thanks mates!
This is not true; I have shaders working with other modes. From what I know, SpriteSortMode.Immediate doesn’t do any batching and, hence the name, immediately draws what you tell it to the screen. Since you need to change shader properties per Begin-End call with other modes, it appears that it won’t work since it’s applying the current state of the shader to everything in the batch until it’s drawn via End().