For sun? Spotlight? Point light?
Anyways, the shadow map creation is the same for all of them, so let’s start with that.
You can basically work with the riemer’s tutorial …
Somewhere in your initialize or load you wanto to create a rendertarget for the shadow map.
Something like this
shadowMapRenderTarget = new RenderTarget2D(graphicsDevice, 2048, 2048, false, SurfaceFormat.Single, DepthFormat.Depth24, 0, RenderTargetUsage.PlatformContents);
We also need to load our shader, which we saved as an fx file (I’ll come to that later)
_ShadowMapGenerate = content.Load<Effect>("Shaders/ShadowMapsGenerate");
Then for each frame (or when the shadow caster moves) you need to set up your shadow matrices like this
Matrix lightView = Matrix.CreateLookAt(lightPosition,
lightPosition + _lightDirection,
Vector3.Up);
Matrix lightProjection = Matrix.CreateOrthographic(width, height, nearZ, farZ);
Note: Orthographic means it’s a directional light (for example sunlight). If you have point or spot lights you use a perspective projection.
Then we need to combine these two for our lightViewProjection.
Matrix lightViewProjection = lightView * lightProjection;
Ok. So we setup the basics - now onto drawing all our shadows into the shadowMapRenderTarget.
private void DrawShadows(... our entities)
{
graphicsDevice.SetRenderTarget(shadowMapRenderTarget);
... foreach of our entities we need the model and their position
...
foreach(entity...)
{
DrawShadowMap(model, modelworldmatrix)
}
}
private void DrawShadowMap(Model model, Matrix world)
{
for (int index = 0; index < model.Meshes.Count; index++)
{
ModelMesh mesh = model.Meshes[index];
for (int i = 0; i < mesh.MeshParts.Count; i++)
{
ModelMeshPart meshpart = mesh.MeshParts[i];
_ShadowMapGenerate.Parameters["WorldViewProj"].SetValue(world * LightViewProjection);
_ShadowMapGenerate.CurrentTechnique.Passes[0].Apply();
_graphicsDevice.SetVertexBuffer(meshpart.VertexBuffer);
_graphicsDevice.Indices = (meshpart.IndexBuffer);
int primitiveCount = meshpart.PrimitiveCount;
int vertexOffset = meshpart.VertexOffset;
int vCount = meshpart.NumVertices;
int startIndex = meshpart.StartIndex;
_graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, vertexOffset, startIndex,
primitiveCount);
}
}
}
Note that I use _ShadowMapGenerate here. I hope it’s somewhat clear so far. I think this should correspond to the Riemer’s tutorial.
Onto the shader.
matrix LightViewProj;
struct CreateShadowMap_VSOut
{
float4 Position : POSITION;
float Depth : TEXCOORD0;
};
// CREATE SHADOW MAP
CreateShadowMap_VSOut CreateShadowMap_VertexShader(float4 Position : SV_POSITION)
{
CreateShadowMap_VSOut Out;
Out.Position = mul(Position, mul(World, LightViewProj));
Out.Depth = Out.Position.z / Out.Position.w;
return Out;
}
float4 CreateShadowMap_PixelShader(CreateShadowMap_VSOut input) : COLOR
{
return float4(input.Depth, 0, 0, 0);
}
// Technique for creating the shadow map
technique CreateShadowMap
{
pass Pass1
{
VertexShader = compile vs_5_0 CreateShadowMap_VertexShader();
PixelShader = compile ps_5_0 CreateShadowMap_PixelShader();
}
}
That’s it!
If you want to draw the renderTarget in the output (for debug purposes, or just to check how it looks) you can put this at the end of your Draw() function
_graphicsDevice.SetRenderTarget(null);
_spriteBatch.Begin(0, BlendState.Opaque, SamplerState.AnisotropicClamp);
_spriteBatch.Draw(_shadowMapRenderTarget, new Rectangle(0, 0, width, height), Color.White);
_spriteBatch.End();
width and height being the output size obviously.
I hope this helps a bit. If you managed to make this work the rest (actual shadowing) is not too far off. Report back!