Shader 单对策和HLSL-点光源阴影贴图瑕疵

Shader 单对策和HLSL-点光源阴影贴图瑕疵,shader,monogame,hlsl,light,shadow-mapping,Shader,Monogame,Hlsl,Light,Shadow Mapping,我正在做一个单一游戏。我正在使用正向渲染,我决定编写一个着色器,使用Blinn phong着色模型调用lightning。我已经实现了这个模型来处理三种类型的光——平行光、点光源和聚光灯。在这之后,有时间给我们的游戏添加阴影。我决定使用阴影贴图和百分比过滤技术。我已经实现了它,但不幸的是,为点光源投射阴影存在问题。我正在从点光源透视(六个ViewProjectionMatrix,每个都面向一个方向)将场景渲染为立方体贴图,然后将其与当前渲染的对象进行比较。我面临两个问题: 平面边缘附近有一些奇怪

我正在做一个单一游戏。我正在使用正向渲染,我决定编写一个着色器,使用Blinn phong着色模型调用lightning。我已经实现了这个模型来处理三种类型的光——平行光、点光源和聚光灯。在这之后,有时间给我们的游戏添加阴影。我决定使用阴影贴图和百分比过滤技术。我已经实现了它,但不幸的是,为点光源投射阴影存在问题。我正在从点光源透视(六个ViewProjectionMatrix,每个都面向一个方向)将场景渲染为立方体贴图,然后将其与当前渲染的对象进行比较。我面临两个问题:

  • 平面边缘附近有一些奇怪的瑕疵。曲面有一个圆形部分,尽管被另一个曲面覆盖,但该部分未被遮挡。问题的屏幕截图:

  • 为了使阴影生效,我必须有一种灯光边界对象,它位于离点光源最远的位置,光线的平截头体可以看到点光源。如果我不画这个物体,它会引起某种反向阴影——我会看到表面上的光,在这个表面后面的另一个物体的位置上。更好理解的屏幕截图:

  • 这是我的HLSL代码(我将用简短的注释+此处替换与点光源直接无关的部分代码):

    有没有一个简单的方法或简单的解释为什么会发生这样的想法?有没有办法修复它,或者我会被迫尝试实现双抛物面阴影贴图?如果是这样,hlsl中是否有成功连接到monogame或xna的示例实现


    提前感谢您的建议和时间。

    我自己在实现阴影映射时遇到了第一个问题。原因是我在渲染阴影贴图时在顶点着色器(而不是片段着色器)中计算深度。因此,如果你有一个垂直于光源的多边形,每个顶点都会得到相同的深度。我通过使用一个变化的向量(世界片段位置)解决了这个问题,然后在片段着色器中设置深度。这不是最好的解决方案,因为这对性能来说是一个糟糕的做法。

    嗨,谢谢你的回答,这个问题相关的项目很久以前就停止了,但从那时起,我在计算机图形学领域获得了更多的经验,现在我看到了这一点,我认为你对第一个问题的解决方案可能是正确的,但是我不能再在这个项目上检查它了。而且,正如我现在看到的,我认为第二个问题的问题是我清理阴影贴图渲染目标的方式-因为我存储了非标准化的距离,我应该使用一些高值来清理它,而不是使用白色(值为1)。
    #define MAX_DIRECTIONAL_LIGHTS 3
    #define MAX_POINT_LIGHTS 4
    #define MAX_SPOT_LIGHTS 4
    
    matrix worldMatrix;
    matrix viewProjectionMatrix;
    matrix currentLightVievProjectionMatrix;
    float4 currentLightPosition;
    
    float4 cameraPosition;
    
    texture diffuseTexture;
    texture normalTexture;
    texture specularTexture;
    texture opacityTexture;
    
    float4 globalAmbient;
    
    //Directional Lights related variables here
    
    int currentPointLightsNumber;
    float4 pointLightPosition[MAX_POINT_LIGHTS];
    float4 pointLightAmbientColor[MAX_POINT_LIGHTS];
    float4 pointLightDiffuseColor[MAX_POINT_LIGHTS];
    float4 pointLightSpecularColor[MAX_POINT_LIGHTS];
    float pointLightRadius[MAX_POINT_LIGHTS];
    float pointLightTexelSize[MAX_POINT_LIGHTS];
    matrix pointLightViewProjection0;
    matrix pointLightViewProjection1;
    matrix pointLightViewProjection2;
    matrix pointLightViewProjection3;
    texture pointLightShadowMap0;
    texture pointLightShadowMap1;
    texture pointLightShadowMap2;
    texture pointLightShadowMap3;
    
    //Spot lights related variables here
    
    float materialShininessFactor;
    float DepthBias = float(0.0004F);
    
    sampler2D DiffuseMapSampler = sampler_state
    {
        Texture = <diffuseTexture>;
        MinFilter = Anisotropic;
        MagFilter = Linear;
        MipFilter = Linear;
        AddressU = wrap;
        AddressV = wrap;
        MaxAnisotropy = 16;
    };
    
    sampler2D NormalMapSampler = sampler_state
    {
        Texture = <normalTexture>;
        MinFilter = Anisotropic;
        MagFilter = Linear;
        MipFilter = Linear;
        AddressU = wrap;
        AddressV = wrap;
        MaxAnisotropy = 4;
    };
    
    sampler2D SecularMapSampler = sampler_state
    {
        Texture = <specularTexture>;
        MinFilter = Linear;
        MagFilter = Linear;
        MipFilter = Linear;
        AddressU = wrap;
        AddressV = wrap;
    };
    
    sampler2D OpacityMapSampler = sampler_state
    {
        Texture = <opacityTexture>;
        MinFilter = Linear;
        MagFilter = Linear;
        MipFilter = Linear;
        AddressU = wrap;
        AddressV = wrap;
    };
    
    //Directional light shadow map samplers here
    
    samplerCUBE PointLightShadowMapSampler0 = sampler_state
    {
        Texture = <pointLightShadowMap0>;
        MinFilter = Point;
        MagFilter = Point;
        MipFilter = None;
        AddressU = clamp;
        AddressV = clamp;
    };
    
    samplerCUBE PointLightShadowMapSampler1 = sampler_state
    {
        Texture = <pointLightShadowMap1>;
        MinFilter = Point;
        MagFilter = Point;
        MipFilter = None;
        AddressU = clamp;
        AddressV = clamp;
    };
    
    samplerCUBE PointLightShadowMapSampler2 = sampler_state
    {
        Texture = <pointLightShadowMap2>;
        MinFilter = Point;
        MagFilter = Point;
        MipFilter = None;
        AddressU = clamp;
        AddressV = clamp;
    };
    
    samplerCUBE PointLightShadowMapSampler3 = sampler_state
    {
        Texture = <pointLightShadowMap3>;
        MinFilter = Point;
        MagFilter = Point;
        MipFilter = None;
        AddressU = clamp;
        AddressV = clamp;
    };
    
    //Spot light shadow map samplers here
    
    struct BlinnPhongVertexShaderInput
    {
        float4 position : POSITION;
        float2 textureCoordinates : TEXCOORD;
        float3 normal : NORMAL;
        float3 tangent : TANGENT;
        float3 binormal : BINORMAL;
    };
    
    struct BlinnPhongPixelShaderInput
    {
        float4 position : SV_POSITION;
        float4 worldPosition : TEXCOORD0;
        float2 textureCoordinates : TEXCOORD1;
        float4 viewDirection : TEXCOORD2;
        float3 normal : TEXCOORD3;
        float3 tangent : TANGENT;
        float3 binormal : BINORMAL;
    };
    
    struct CreateShadowMapPixelShaderInput
    {
        float4 Position : POSITION;
        float Depth : TEXCOORD0;
    };
    
    //Vertex shader for directional and spot lights here
    
    CreateShadowMapPixelShaderInput CreateShadowMapForPointLightVertexShaderFunction(float4 Position : POSITION)
    {
        CreateShadowMapPixelShaderInput OUT;
        OUT.Position = mul(Position, worldMatrix);
        OUT.Depth = length(OUT.Position.xyz - currentLightPosition.xyz);
        OUT.Position = mul(OUT.Position, currentLightVievProjectionMatrix);
        return OUT;
    }
    
    float4 CreateShadowMapPixelShaderFunction(CreateShadowMapPixelShaderInput input) : COLOR
    {
        return float4(input.Depth, 0.0F, 0.0F, 0.0F);
    }
    
    BlinnPhongPixelShaderInput BlinnPhongVertexShaderFunction(BlinnPhongVertexShaderInput input)
    {
        BlinnPhongPixelShaderInput output;
    
        float4 worldPosition = mul(input.position, worldMatrix);
        output.position = mul(worldPosition, viewProjectionMatrix);
        output.worldPosition = worldPosition;
    
        output.textureCoordinates = input.textureCoordinates;
        output.viewDirection = cameraPosition - output.worldPosition;
    
        output.normal = mul(input.normal, (float3x3)worldMatrix);
        output.tangent = mul(input.tangent, (float3x3)worldMatrix);
        output.binormal = mul(input.binormal, (float3x3)worldMatrix);
    
        return output;
    }
    
    //ShadowMapLookups for directional and spot lights here
    
    float PointLightShadowMapLookup(samplerCUBE shadowMap, float3 shadowTexCoord, float3 offset, float ourDepth, float texelSize)
    {
        return (texCUBE(shadowMap, shadowTexCoord + offset * texelSize).r < ourDepth) ? 0.1f : 1.0f;
    }
    
    float4 BlinnPhongPixelShaderFunction(BlinnPhongPixelShaderInput input) : COLOR0
    {
        float4 color = globalAmbient;
        float4 specularColor = float4(0.0F, 0.0F, 0.0F, 0.0F);
    
        float3 V = normalize(input.viewDirection.xyz);
    
        float3 L;
        float3 H;
        float NDotL;
        float NDotH;
    
        float attenuation;
        float power;
    
        float4 normalMap = tex2D(NormalMapSampler, input.textureCoordinates);
        normalMap = (normalMap * 2.0F) - 1.0F;
    
        float3 N = normalize((normalMap.x * normalize(input.tangent)) + (normalMap.y * normalize(input.binormal)) + (normalMap.z * normalize(input.normal)));
    
        float4 specularMap;
        specularMap = tex2D(SecularMapSampler, input.textureCoordinates);
    
        float4 lightingPosition;
        float2 ShadowTexCoord;
        float3 PointLightShadowTexCoord;
        float ourdepth;
        float shadowOcclusion;
    
        //Directional lights lightning callculations here
    
        for (int j = 0; j < currentPointLightsNumber; ++j)
        {
            L = (pointLightPosition[j].xyz - input.worldPosition.xyz) / pointLightRadius[j];
            attenuation = saturate(1.0F - dot(L, L));
    
            L = normalize(L);
            H = normalize(L + V);
    
            NDotL = saturate(dot(N, L));
            NDotH = saturate(dot(N, H));
    
            power = (NDotL == 0.0F) ? 0.0F : saturate(pow(NDotH, materialShininessFactor / specularMap.a));
    
            ourdepth = length((pointLightPosition[j].xyz - input.worldPosition.xyz) * 0.98);
    
            PointLightShadowTexCoord = -normalize(pointLightPosition[j].xyz - input.worldPosition.xyz);
    
            shadowOcclusion = 0.0F;
    
            if (j == 0)
            {
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 0.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 0.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 0.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 1.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 1.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 1.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 2.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 2.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 2.0f, 0.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 0.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 0.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 0.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 1.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 1.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 1.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 2.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 2.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 2.0f, 1.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 0.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 0.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 0.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 1.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 1.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 1.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
    
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(0.0f, 2.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(1.0f, 2.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
                shadowOcclusion += PointLightShadowMapLookup(PointLightShadowMapSampler0, PointLightShadowTexCoord, float3(2.0f, 2.0f, 2.0f), ourdepth, pointLightTexelSize[j]);
            }
            else if (j == 1)
            {
                //Same code for second point light
            }
            else if (j == 2)
            {
                //Same code for third point light
            }
            else
            {
                //Same code for fourth point light
            }
    
            shadowOcclusion /= 27.0F;
    
            color += (pointLightAmbientColor[j] * attenuation) + (pointLightDiffuseColor[j] * NDotL * attenuation * shadowOcclusion);
            specularColor += (pointLightSpecularColor[j] * power * attenuation * specularMap * shadowOcclusion);
        }
    
        //Spot lights lightning callculations here
    
        color = saturate(color * tex2D(DiffuseMapSampler, input.textureCoordinates) + specularColor);
        color.a = (float1)tex2D(OpacityMapSampler, input.textureCoordinates);
        return color;
    }
    
    //technique for directional and spot lights shadow mapping here
    
    technique CreateShadowMapForPointLight
    {
        pass Pass1
        {
            VertexShader = compile vs_4_0 CreateShadowMapForPointLightVertexShaderFunction();
            PixelShader = compile ps_4_0 CreateShadowMapPixelShaderFunction();
        }
    }
    
    technique BlinnPhong
    {
        pass Pass1
        {
            VertexShader = compile vs_4_0 BlinnPhongVertexShaderFunction();
            PixelShader = compile ps_4_0 BlinnPhongPixelShaderFunction();
        }
    }
    
    RenderTargetCube ShadowMapRenderTarget = new RenderTargetCube(GameObject.Scene.SceneManager.GameEngine.GraphicsDevice,
                                1024,
                                false,
                                SurfaceFormat.Single,
                                DepthFormat.Depth24);
    ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 1.0F, 0.1F, Radius) * Matrix.CreateScale(-1, 1, 1);
    
    public void CreateViewMatrix(Vector3 targetVector)
    {
         Vector3 upVector;
         if (targetVector.Y > 0)
         {
             upVector = Vector3.Forward;
         }
         else if (targetVector.Y < 0)
         {
             upVector = Vector3.Backward;
         }
         else
         {
             upVector = Vector3.Up;
         }
         ViewMatrix = Matrix.CreateLookAt(GameObject.Transform.Position,GameObject.Transform.Position + targetVector, upVector);
    }
    
    public override void CreateViewProjectionMatrix()
    {
        ViewProjectionFrustum.Matrix = ViewMatrix * ProjectionMatrix;
    }
    
            foreach (PointLight pointLight in PointLights)
            {
                foreach (CubeMapFace cubeMapFace in Enum.GetValues(typeof(CubeMapFace)))
                {
                    pointLight.CreateViewMatrix(cubeMapFace.GetDirection());
                    pointLight.CreateViewProjectionMatrix();
                    SceneManager.GameEngine.GraphicsDevice.SetRenderTarget(pointLight.ShadowMapRenderTarget, cubeMapFace);
                    SceneManager.GameEngine.GraphicsDevice.Clear(Color.White);
                    foreach (DrawShadowMapDelegateType DrawComponent in ComponentsDrawShadowMapForPointLightMethods)
                    {
                        DrawComponent(pointLight);
                    }
                }
            }