首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DirectX11阴影映射问题

DirectX11阴影映射问题
EN

Stack Overflow用户
提问于 2015-12-10 01:20:29
回答 2查看 1.3K关注 0票数 1

我试图添加方向阴影映射到我的地形项目,但我遇到了一些问题。作为参考,我正在学习RasterTek阴影教程。

本教程本质上遵循了以下过程:创建光线>创建基于灯光视图的深度纹理>渲染模型并应用阴影着色器。

我正在努力解决的主要问题是本教程如何处理光线。它本质上模拟了一个位置,并创建了一个正交和视图矩阵。从灯光的设置方式看,这个问题似乎正在升级。对于一个简单的测试,我创建了一个平面,并将光的方向直接向下设置,因此所有的东西都应该被点燃,然而,发生了以下情况:

当地形产生时:

下面是一些我认为有用的领域的代码:

光设置

代码语言:javascript
复制
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);

代码语言:javascript
复制
void GenerateOthoMatrix(float width, float nearClip, float farClip)
{
    mOrthoMatrix = XMMatrixOrthographicLH(width, width, nearClip, farClip);
}

代码语言:javascript
复制
XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
XMVECTOR pos = XMLoadFloat3(&mPosition);
XMVECTOR la = XMLoadFloat3(&mLookAt);

mViewMatrix = XMMatrixLookAtLH(pos, la, up);

深度渲染传递

代码语言:javascript
复制
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呈现调用只需将“info”设置映射到常量缓冲区,然后调用它们的相对顶点/像素着色器。

地形渲染调用只是设置索引/顶点缓冲区和拓扑,为着色DrawIndexed做好准备。

RenderTexture本质上是第二个视图,用于呈现和获取深度纹理。

主渲染传递

代码语言:javascript
复制
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());

深度顶点着色器

代码语言:javascript
复制
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;
}

深度象素着色器

代码语言:javascript
复制
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;
}

阴影顶点着色器

代码语言:javascript
复制
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;
}

阴影象素阴影

代码语言:javascript
复制
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;
}

对于大量的代码,我感到非常抱歉--我不确定哪些部分最有助于识别问题。如果有人能帮忙,或者提供影子映射资源,我将非常感激。似乎没有多少影子映射资源,或者至少我找不到很多。

EN

回答 2

Stack Overflow用户

发布于 2015-12-10 02:56:30

看起来你的深度阴影看起来不错。我注意到了你的阴影着色器的不同之处。我已经通过和完全两个系列的DirectX 10和11通过光栅。我将向您展示我的阴影着色器是什么样子;但是,我不记得它们是否从一个教训改变到另一个教训。我会把它们贴在这里供你比较。

Shadow.vsh

代码语言:javascript
复制
/////////////////////////////////////////////////
// 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

代码语言:javascript
复制
/////////////////////////////////////////////////
// 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 & .cpp着色文件与您的着色器中正确的输入和输出结构相匹配。在计算象素着色器中的光强时,似乎使用的是光的方向,而不是光的位置。你确实有更多的纹理添加到你的版本的着色器比我,但我不认为这会造成不同的情况。我没有权限查看您的整个解决方案,因此很难知道错误可能来自何处。我只希望他能帮你当向导。

票数 1
EN

Stack Overflow用户

发布于 2015-12-15 12:46:59

我很清楚这个问题..。我只是看了看图片,没有看你的长文。

我认为光并不能看到整个场景,只看到被照亮的部分。

有一些解决办法,但没有一个是很好的。这是一个典型的问题。

试着增加光视角的效果。XMMatrixOrthographicLH需要更大的宽度。增加光的观察结果减少了你的影子地图的细节。

没有perfekt的解决方案。您需要尝试哪些值适合您的问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34192133

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档