Reputation: 771
I'm attempting to add directional shadow mapping to my terrain project, but I'm encountering a few issues. For reference, I'm following the RasterTek shadows tutorial.
The tutorial essentially follows the process of: Create a light > Create a depth texture based on the lights view > Render models and apply shadow shader.
The main issue I'm struggling with is how the tutorial handles the light. It essentially simulates a position and creates an ortho and view matrix. The issue seems to be escalating from how the light is set up. For a simple test, I created a plane, and set the light direction directly down, so everything should be lit, however, the following happens:
And when terrain is generated:
Here is code from a few areas that I think would be useful:
Light set up
mLight->SetPosition(XMFLOAT3(10.0f, 30.0f, -0.1f));
mLight->SetLookAt(XMFLOAT3(-10.0f, 0.0f, 0.0f));
mLight->GenerateOthoMatrix(40.0f, 1.0f, 50.0f);
Light GenerateOthoMatrix
void GenerateOthoMatrix(float width, float nearClip, float farClip)
{
mOrthoMatrix = XMMatrixOrthographicLH(width, width, nearClip, farClip);
}
Light GenerateViewMatrix
XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
XMVECTOR pos = XMLoadFloat3(&mPosition);
XMVECTOR la = XMLoadFloat3(&mLookAt);
mViewMatrix = XMMatrixLookAtLH(pos, la, up);
Depth Render Pass
mRenderTexture->SetRenderTarget(mGraphicsDevice->GetContext());
mRenderTexture->ClearRenderTarget(mGraphicsDevice->GetContext());
mLight->GenerateViewMatrix();
mDepthShader.Info.worldMatrix = mTerrain->GetWorldMatrix();
mDepthShader.Info.viewMatrix = mLight->GetViewMatrix();
mDepthShader.Info.projMatrix = mLight->GetOrthoMatrix();
mTerrain->Render(mGraphicsDevice->GetContext());
mDepthShader.Render(mGraphicsDevice->GetContext(), mTerrain->GetIndexCount());
mGraphicsDevice->ResetBackBuffer();
mGraphicsDevice->ResetViewport();
Shader Render calls simply map the 'info' settings to constant buffers and then call their relative vertex/pixel shaders.
Terrain Render calls just setup Index/Vertex buffers and topology, ready for the shader DrawIndexed.
RenderTexture is essentially a second viewport to render to and get a depth texture from
Main Render Pass
mTerrain->Render(mGraphicsDevice->GetContext());
mLight->GenerateViewMatrix();
mShader.Info.lightProj = mLight->GetOrthoMatrix();
mShader.Info.lightView = mLight->GetViewMatrix();
mShader.Info.depthTex = mRenderTexture->GetSRV();
mShader.Render(mGraphicsDevice->GetContext(), mTerrain->GetIndexCount());
Depth Vertex Shader
cbuffer SPerFrameCB : register(b0)
{
matrix worldMatrix;
matrix viewMatrix;
matrix projMatrix;
};
struct VertexIn
{
float4 Pos : POSITION;
};
struct VertexOut
{
float4 Pos : SV_POSITION;
float4 DPos : TEXTURE0;
};
VertexOut main(VertexIn vin)
{
VertexOut vout;
vin.Pos.w = 1.0f;
vout.Pos = mul(vin.Pos, worldMatrix);
vout.Pos = mul(vout.Pos, viewMatrix);
vout.Pos = mul(vout.Pos, projMatrix);
vout.DPos = vout.Pos;
return vout;
}
Depth Pixel Shader
struct PixelIn
{
float4 Pos : SV_POSITION;
float4 DPos : TEXTURE0;
};
float4 main(PixelIn pin) : SV_Target
{
float depthVal = pin.DPos.z / pin.DPos.w;
float4 colour = float4(depthVal, depthVal, depthVal, 1.0f);
return colour;
}
Shadow Vertex Shader
cbuffer SPerFrameCB : register(b0)
{
matrix worldMatrix;
matrix viewMatrix;
matrix projMatrix;
matrix lightViewMatrix;
matrix lightProjMatrix;
};
struct VertexIn
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float3 Normal : NORMAL;
};
struct VertexOut
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Normal : NORMAL;
float4 LightV : TEXCOORD1;
};
VertexOut main(VertexIn vin)
{
VertexOut vout;
vin.Pos.w = 1.0f;
float4 worldPos = mul(vin.Pos, worldMatrix);
vout.Pos = worldPos;
vout.Pos = mul(vout.Pos, viewMatrix);
vout.Pos = mul(vout.Pos, projMatrix);
vout.LightV = worldPos;
vout.LightV = mul(vout.LightV, lightViewMatrix);
vout.LightV = mul(vout.LightV, lightProjMatrix);
vout.Tex = vin.Tex;
vout.Normal = mul(vin.Normal, (float3x3)worldMatrix);
vout.Normal = normalize(vout.Normal);
return vout;
}
Shadow Pixel Shader
Texture2D shaderTexture;
Texture2D lowerTex : register(t0);
Texture2D mediumTex : register(t1);
Texture2D higherTex : register(t2);
Texture2D depthTex : register(t3);
SamplerState SampleTypeClamp : register(s0);
SamplerState SampleTypeWrap : register(s1);
cbuffer SPerLightCB : register(b0)
{
float4 ambientColour;
float4 diffuseColour;
float3 lightDirection;
float padding;
};
struct PixelIn
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Normal : NORMAL;
float4 LightV : TEXCOORD1;
};
float4 main(PixelIn pin) : SV_Target
{
float bias = 0.001f;
float3 lightDir = -lightDirection;
float4 colour = ambientColour;
float2 projTexCoord;
projTexCoord.x = pin.LightV.x / pin.LightV.w / 2.0f + 0.5f;
projTexCoord.y = -pin.LightV.y / pin.LightV.w / 2.0f + 0.5f;
if ((saturate(projTexCoord.x) == projTexCoord.x) && (saturate(projTexCoord.y) == projTexCoord.y))
{
float depthVal = depthTex.Sample(SampleTypeClamp, projTexCoord).r;
float lightDepthVal = pin.LightV.z / pin.LightV.w;
lightDepthVal -= bias;
if (lightDepthVal < depthVal)
{
float lightIntensity = saturate(dot(pin.Normal, lightDir));
if (lightIntensity > 0.0f)
{
colour += diffuseColour * lightIntensity;
colour = saturate(colour);
}
}
}
float4 lowerColour = lowerTex.Sample(SampleTypeWrap, pin.Tex);
float4 mediumColour = mediumTex.Sample(SampleTypeWrap, pin.Tex);
float4 higherColour = higherTex.Sample(SampleTypeWrap, pin.Tex);
float4 texColour;
float slope = 1.0f - pin.Normal.y, bVal;
if (slope < 0.4f)
{
bVal = slope / 0.4f;
texColour = lerp(lowerColour, mediumColour, bVal);
}
if (slope >= 0.4f && slope < 0.6f)
{
bVal = (slope - 0.4f) * (1.0f / (0.6f - 0.4f));
texColour = lerp(mediumColour, higherColour, bVal);
}
if (slope >= 0.6f)
{
texColour = higherColour;
}
colour *= texColour;
return colour;
}
I'm very sorry for the large amounts of code - I'm not sure which sections would help best in identifying the issue. If anyone could help, or provide a shadow mapping resource I would be very grateful. There doesn't seem to be many shadow mapping resources, or at least I haven't been able to find many.
Upvotes: 1
Views: 1874
Reputation: 1009
I know this Problem very well... I just looked at the pictures, didnt read your long text.
I think the light does not see the whole scene, just the parts that are illuminated.
There are some solutions but none is pretty good. Thats a typical problem.
Try to increase The frustum of The light perspective. XMMatrixOrthographicLH needs a greater width. Increasing The viewing frustum of light decreases The details of your shadow map.
There is not the perfekt solution... You need to try what values fit to your Problem.
Upvotes: 0
Reputation: 7905
It appears that your Depth Shaders looks good. I've noticed differences in your Shadow shaders though. I have went through and completely both series for DirectX 10 & 11 through rastertek. I'll show you what my shadow shaders look like; however I do not remember if they have been changed from one lesson to another. I'll post them here for you to compare to.
Shadow.vsh
/////////////////////////////////////////////////
// Filename: shadow.vsh
/////////////////////////////////////////////////
/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
matrix lightViewMatrix;
matrix lightProjectionMatrix;
};
//////////////////////
// CONSTANT BUFFERS //
//////////////////////
cbuffer LightBuffer2
{
float3 lightPosition;
float padding;
};
//////////////
// TYPEDFES //
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
float4 lightViewPosition : TEXCOORD1;
float3 lightPos : TEXCOORD2;
};
/////////////////////////////////////////////////
// Vertex Shader
/////////////////////////////////////////////////
PixelInputType ShadowVertexShader( VertexInputType input )
{
PixelInputType output;
float4 worldPosition;
// Change The Position Vector To Be 4 Units For Proper Matrix Calculations
input.position.w = 1.0f;
// Calculate The Position Of The Vertex Against The World, View And Projection Matrices
output.position = mul( input.position, worldMatrix );
output.position = mul( output.position, viewMatrix );
output.position = mul( output.position, projectionMatrix );
// Calculate The Position Of The Vertex As Viewed By The Light Source
output.lightViewPosition = mul( input.position, worldMatrix );
output.lightViewPosition = mul( output.lightViewPosition, lightViewMatrix );
output.lightViewPosition = mul( output.lightViewPosition, lightProjectionMatrix );
// Store The Texture Coordinate For The Pixel Shader
output.tex = input.tex;
// Calculate The Normal Vector Against The World Matrix Only
output.normal = mul( input.normal, (float3x3)worldMatrix );
// Normalize The Normal Vector
output.normal = normalize( output.normal );
// Calculate The Position Of The Vertex In The World
worldPosition = mul( input.position, worldMatrix );
// Determine The Light Position Based On The Position Of The Light And The Position Of The Vertex In The World
output.lightPos = lightPosition.xyz - worldPosition.xyz;
// Normalize The Light Position Vector
output.lightPos = normalize( output.lightPos );
return output;
} // ShadowVertexShader
Shadow.psh
/////////////////////////////////////////////////
// Filename: shadow.ps
/////////////////////////////////////////////////
//////////////
// TEXTURES //
Texture2D depthMapTexture : register(t0);
///////////////////
// SAMPLE STATES //
///////////////////
SamplerState SampleTypeClamp : register(s0);
//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
float4 lightViewPosition : TEXCOORD1;
float3 lightPos : TEXCOORD2;
};
/////////////////////////////////////////////////
// Pixel Shader
/////////////////////////////////////////////////
float4 ShadowPixelShader( PixelInputType input ) : SV_TARGET
{
float bias;
float4 color;
float2 projectTexCoord;
float depthValue;
float lightDepthValue;
float lightIntensity;
// Set The Bias Value For Fixing The Floating Point Precision Issues
bias = 0.001f;
// Set The Default Output Color To Be Black (Shadow)
color = float4( 0.0f, 0.0f, 0.0f, 1.0f );
// Calculate The Projected Texture Coordinates
projectTexCoord.x = input.lightViewPosition.x / input.lightViewPosition.w / 2.0f + 0.5f;
projectTexCoord.y = -input.lightViewPosition.y / input.lightViewPosition.w / 2.0f + 0.5f;
// Determine If The Projected Coordinates Are In The [0,1] Range. If So Then This Pixel Is In The View Of The Light
if ( (saturate( projectTexCoord.x) == projectTexCoord.x) && (saturate(projectTexCoord.y) == projectTexCoord.y) )
{
// Sample The Shadow Map Depth Value From The Depth Texture Using The Sampler At The Projected Texture Coordinate Location
depthValue = depthMapTexture.Sample( SampleTypeClamp, projectTexCoord).r;
// Calculate The Depth Of The Light
lightDepthValue = input.lightViewPosition.z / input.lightViewPosition.w;
// Subtract The Bias From The LightDepthValue
lightDepthValue = lightDepthValue - bias;
// Compare The Depth Of The Shadow Map Value And The Depth Of The Light To Determine Whether To Shadow Or To Light This Pixel
// If The Light Is In Front Of The Object Then Light The Pixel, If Not Then Shadow This Pixel Since An Object (Occluder) Is Casting A Shadow On It
if ( lightDepthValue < depthValue )
{
// Calculate The Amount Of Light On This Pixel
lightIntensity = saturate( dot( input.normal, input.lightPos ) );
// If This Pixel Is Illuminated Then Set It To Pure White (Non-Shadow)
if ( lightIntensity > 0.0f )
{
// Determine The Final Diffuse Color Based On The Diffuse Color And The Amount Of Light Intensity
color = float4( 1.0f, 1.0f, 1.0f, 1.0f );
}
}
}
return color;
} // ShadowPixelShader
Also make sure that your corresponding .h & .cpp Shader files match the correct input and output structures that are in your shaders. It appears that you are using the light direction as opposed to the light position when calculating the light intensity in your pixel shader. You do have more textures added into your version of the shader than I but I don't think that would make the difference in this case. I do not have access to see your entire solution, so it is hard to tell where the error may be coming from. I just hope that his helps to serve you as a guide.
Upvotes: 2