如何在阴影贴图中使用二维纹理数组

后端开发 2026-07-10

关于阴影贴图的 文档 指示我需要包含

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

关于2D数组的 [文档] 使用 UNITY\_DECLARE\_TEX2DARRAY,需要 #include "UnityCG.cginc"。但当我把它们同时包含时,它们似乎会冲突,导致编译错误:

redefinition of 'PackHeightmap' at

无论我使用CGPROGRAM还是HSLSLPROGRAM,问题都一样。

我尝试使用基于 #include "Lighting.cginc" 的较旧API,但到目前为止在任何地方都看不到阴影(但使用默认的Lit材质时会看到阴影)

Shader "Proc Env/Terrain"
{
    Properties
    {
        _TerrainLayers ("Layers", 2DArray) = "" {}
        _LayerWeights("Weight Map", 2D) = "white" {}
        _UVScale ("UVScale", Float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }
        Pass
        {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // texture arrays are not available everywhere,
            // only compile shader on platforms where they are
            #pragma require 2darray

            // compile shader into multiple variants, with and without shadows
            // (we don't care about any lightmaps yet, so skip these variants)
            #pragma multi_compile_fwdbase // nolightmap nodirlightmap nodynlightmap novertexlight
            //#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
            //#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            // shadow helper functions and macros like SHADOW_COORDS, TRANSFER_SHADOW
            #include "AutoLight.cginc"

            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 positionWorld : TEXCOORD1;
                SHADOW_COORDS(3) // put shadows data into TEXCOORD3
                //float4 shadowCoords : TEXCOORD3;
                float3 normal: NORMAL;
            };


            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = UnityObjectToClipPos(IN.positionOS);
                //OUT.positionHCS = TransformObjectToHClip(IN.positionOS);
                OUT.uv = IN.uv;
                OUT.positionWorld = IN.positionOS;
                OUT.normal = IN.normal;
                //VertexPositionInputs positions = GetVertexPositionInputs(IN.positionOS.xyz);
                //float4 shadowCoordinates = GetShadowCoord(positions);
                // Pass the shadow coordinates to the fragment shader
                //OUT.shadowCoords = shadowCoordinates;
                TRANSFER_SHADOW(OUT);
                return OUT;
            }

            UNITY_DECLARE_TEX2DARRAY(_TerrainLayers);

            half4 frag (Varyings IN) : SV_Target
            {
                // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
                half shadowAmount = SHADOW_ATTENUATION(IN);
                //half shadowAmount = MainLightRealtimeShadow(IN.shadowCoords); 
                return UNITY_SAMPLE_TEX2DARRAY(_TerrainLayers, float3(IN.positionWorld.x, IN.positionWorld.z, 2)) * shadowAmount;
            }
            ENDCG
        }

        // shadow casting support
        UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
    }
}

当我添加

Tags {"LightMode" = "LightweightForward"}

时,整个材质变成洋红色。我在Unity 6.4的 URP中使用。

我差点就把它调通了

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Proc Env/Terrain"
{
    Properties
    {
        _TerrainLayers ("Layers", 2DArray) = "" {}
        _LayerWeights("Weight Map", 2D) = "white" {}
        _UVScale ("UVScale", Float) = 1.0
    }
    SubShader
    {
         Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma require 2darray
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 positionWorld : TEXCOORD1;
                float4 shadowCoords : TEXCOORD3;
                float3 normal: NORMAL;
            };


            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS);
                OUT.uv = IN.uv;
                OUT.positionWorld = IN.positionOS;
                OUT.normal = IN.normal;
                VertexPositionInputs positions = GetVertexPositionInputs(IN.positionOS.xyz);
                float4 shadowCoordinates = GetShadowCoord(positions);
                OUT.shadowCoords = shadowCoordinates;\
                return OUT;
            }

            TEXTURE2D_ARRAY(_TerrainLayers);
            SAMPLER(sampler_TerrainLayers);

            half4 frag (Varyings IN) : SV_Target
            {
                half shadowAmount = MainLightRealtimeShadow(IN.shadowCoords); 
                return SAMPLE_TEXTURE2D_ARRAY(_TerrainLayers, sampler_TerrainLayers, IN.positionWorld.xz, 2) * shadowAmount;
            }
            ENDHLSL
        }

    }
}

但它仍然产生了一些怪异的伪影。我觉得我完全按照官方示例来做。

在此输入图片描述

我稍微查了一下,似乎是URP的一个bug

https://esotericsoftware.com/forum/d/15003-urp-shader-bug-when-on-edge-of-shadow-cascades/2

解决方案

原来这个问题的原因是在顶点着色器中计算shadowCoord,但如果在片段着色器中进行计算,一切都能正常工作。以下是完整代码

Shader "Proc Env/Terrain"
{
    Properties
    {
        _TerrainLayers ("Layers", 2DArray) = "" {}
        _LayerWeights("Weight Map", 2D) = "white" {}
        _UVScale ("UVScale", Float) = 1.0
    }
    SubShader
    {
         Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma require 2darray
            // this will allow for shadow cascades
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
            // this will make the shadows soft
            #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 positionWorld : TEXCOORD1;
                float3 normal: NORMAL;
            };


            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS);
                OUT.uv = IN.uv;
                OUT.positionWorld = IN.positionOS;
                OUT.normal = IN.normal;

                return OUT;
            }

            TEXTURE2D_ARRAY(_TerrainLayers);
            SAMPLER(sampler_TerrainLayers);

            half4 frag (Varyings IN) : SV_Target
            {
                VertexPositionInputs positions = GetVertexPositionInputs(IN.positionWorld);
                // compute shadow coords in fragment to avoid artifacts!
                float4 shadowCoords = GetShadowCoord(positions);
                half shadowAmount = MainLightRealtimeShadow(shadowCoords); 
                return SAMPLE_TEXTURE2D_ARRAY(_TerrainLayers, sampler_TerrainLayers, IN.positionWorld.xz, 2) * shadowAmount;
            }
            ENDHLSL
        }

    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章