I've been trying to implement Volumetric Lighting using the code from this tutorial but I've run into some issues, even after basically copypasting the shader code.
I'll just show you what's going wrong.
As you can see, the models seem to be "projected" in the space. At first I tried tinkering with the various variables that the shader requires, but to no avail. In the screenshot I used 0.5f for the decay, exposure, weight and density, with a sample amount of 64.
Any ideas on what might be causing this?
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
base.Draw(gameTime, spriteBatch);
//Set the rendertarget to draw the Blinn-Phong shaded scene to
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
Material material = new Material();
material.DiffuseColor = Color.Red;
material.AmbientColor = Color.Red;
material.AmbientIntensity = 0.2f;
material.SpecularColor = Color.White;
material.SpecularIntensity = 2.0f;
material.SpecularPower = 25.0f;
//Draw all the models
foreach (ModelData m in models)
{
ModelMesh mesh = m.Model.Meshes[0];
Effect e = mesh.Effects[0];
e.CurrentTechnique = e.Techniques[m.Technique];
material.SetEffectParameters(e);
this.camera.SetEffectParameters(e);
e.Parameters["World"].SetValue(world * m.Transform);
e.Parameters["WorldInverseTransposed"].SetValue(Matrix.Transpose(Matrix.Invert(world * m.Transform)));
e.Parameters["CameraEye"].SetValue(new Vector4(this.camera.Eye, 0));
// TODO: LightSource Color + Intensity
e.Parameters["LightSources"].SetValue(lightPositions);
mesh.Draw();
}
//Restore the rendertarget to the backbuffer and clear it.
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.Black);
//Pass the standard variable to the spriteBatch vertex shader.
//The vertex shader isn't used (for as far as I can tell at least) but because the standard
//vertex shader for spriteBatch is compiled in 2_0 and the God Ray shader in 3_0 I had to implement it
//manually in order to compile it in 3_0.
Matrix projection = Matrix.CreateOrthographicOffCenter(0,
GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
postProcessing.Parameters["MatrixTransform"].SetValue(halfPixelOffset * projection);
//Setup all the required data for the shader
postProcessing.CurrentTechnique = postProcessing.Techniques["Technique1"];
Vector3 lightPosition = Vector3.Transform(lightPositions[0], world * camera.ViewMatrix * camera.ProjectionMatrix);
postProcessing.Parameters["lightPosition"].SetValue(new Vector2(lightPosition.X, lightPosition.Y));
postProcessing.Parameters["Tex"].SetValue(renderTarget);
postProcessing.Parameters["exposure"].SetValue(0.5f);
postProcessing.Parameters["decay"].SetValue(0.5f);
postProcessing.Parameters["weight"].SetValue(0.5f);
postProcessing.Parameters["density"].SetValue(0.5f);
//Draw the renderTarget to the screen at the size of the viewport so it fits the screen
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, postProcessing);
spriteBatch.Draw(renderTarget, new Rectangle(spriteBatch.GraphicsDevice.Viewport.X, spriteBatch.GraphicsDevice.Viewport.Y, spriteBatch.GraphicsDevice.Viewport.Width, spriteBatch.GraphicsDevice.Viewport.Height), Color.White);
spriteBatch.End();
//Restore some of the changes spriteBatch.Begin() made to the graphics device so the 3D render won't break
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
}
sampler2D renderTarget;
#define SAMPLE_AMOUNT 64
Texture2D Tex;
float2 lightPosition;
float exposure;
float decay;
float weight;
float density;
SamplerState State = sampler_state
{
Texture = <Tex>;
MipFilter = Point;
MinFilter = Linear;
MagFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
float4x4 MatrixTransform;
//The default vertex shader of the spriteBatch, implemented manually so it can be compiled in 3_0
void SpriteVertexShader(inout float4 color : COLOR0,
inout float2 texCoord : TEXCOORD0,
inout float4 position : SV_Position)
{
position = mul(position, MatrixTransform);
}
//Copypasted from the tutorial, only changed some variable names
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
// Calculate vector from pixel to light source in screen space.
half2 deltaTexCoord = (texCoord - lightPosition.xy);
// Divide by number of samples and scale by control factor.
deltaTexCoord *= 1.0f / SAMPLE_AMOUNT * density;
// Store initial sample.
half3 color = tex2D(State, texCoord);
// Set up illumination decay factor.
half illuminationDecay = 1.0f;
// Evaluate summation from Equation 3 NUM_SAMPLES iterations.
for (int i = 0; i < SAMPLE_AMOUNT; i++)
{
// Step sample location along ray.
texCoord -= deltaTexCoord;
// Retrieve sample at new location.
half3 sample = tex2D(State, texCoord);
// Apply sample attenuation scale/decay factors.
sample *= illuminationDecay * weight;
// Accumulate combined color.
color += sample;
// Update exponential decay factor.
illuminationDecay *= decay;
}
// Output final color with a further scale control factor.
return float4( color * exposure, 1);
}
technique Technique1
{
pass Pass1
{
VertexShader = compile vs_3_0 SpriteVertexShader();
PixelShader = compile ps_3_0 main();
}
}