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.
答案 0 :(得分:1)
您的深度着色器看起来很好看。我注意到你的阴影着色器存在差异。我已经完成了DirectX 10&amp;的两个系列。 11到rastertek。我会告诉你我的阴影着色器是什么样的;但是我不记得他们是否从一堂课改为另一堂课。我会把它们发布在这里供你比较。
<强> 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
同时确保您的相应.h&amp; .cpp着色器文件匹配着色器中正确的输入和输出结构。在计算像素着色器中的光强度时,您似乎正在使用光线方向而不是光线位置。您的着色器版本中添加的纹理比我更多,但我不认为这会在这种情况下产生差异。我无权查看您的整个解决方案,因此很难分辨出错误的来源。我只希望他能帮助你作为指导。
答案 1 :(得分:0)
我非常清楚这个问题......我只看了一下图片,没看过你的长篇文章。
我认为光线看不到整个场景,只看到被照亮的部分。
有一些解决方案,但没有一个很好。这是一个典型的问题。
尝试增加光透视的截头体。 XMMatrixOrthographicLH需要更大的宽度。增加光的视锥体减少阴影贴图的细节。
没有perfekt解决方案......您需要尝试适合您的问题的值。