应该在每个渲染通道中重新计算顶点位置吗?

huangapple go评论54阅读模式
英文:

Should I recalculate vertex position for each pass?

问题

我目前正在学习HLSL和着色器语言,我在想是否应该为每个通道重新计算位置,还是是否有一种绕过的方法,因为我觉得这样做会有很多冗余计算。

下面是问题的示例,在这段代码中,我实例化了许多树形网格,并根据它们的实例ID计算每个树的随机位置。但我必须在前向通道和阴影投射通道中都计算它们的位置。非常感谢您的时间。 (+ 对代码的任何反馈将不胜感激)

Shader "Tree Shader"
{
    CGINCLUDE
    #include "UnityCG.cginc"
    #include "UnityLightingCommon.cginc"
    #pragma vertex vertex_shader
    #pragma fragment fragment_shader
    #pragma target 5.0
    uniform float _Radius;
    uniform float _WaveStartHeight;
    uniform int _InstanceCount;
    uniform sampler2D _MainTex;
    uniform float waveAmount;
    ENDCG

    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
    
    SubShader
    {
        Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }

        // 前向渲染通道
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Cull Off
            CGPROGRAM
            #pragma multi_compile_fwdbase

            struct APPDATA
            {
                half4 vertex : POSITION;
                half2 uv : TEXCOORD0;
                uint instanceID : SV_InstanceID;
                half3 normal : NORMAL;
            };

            struct SHADERDATA
            {
                half4 vertex : SV_POSITION;
                half2 uv : TEXCOORD0;
                fixed4 diff : COLOR0;
            };

            half4 ComputeScreenPos(half4 p)
            {
                half4 o = p * 0.5;
                return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
            }

            half3 GenerateRandomPosition(fixed instanceID)
            {
                half3 position;
                position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
                position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
                position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
                return position * _Radius;
            }

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half3 randomPosition = GenerateRandomPosition(data.instanceID);
                half waveAmount = 0.0;

                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                vs.uv = data.uv;
                half3 worldNormal = UnityObjectToWorldNormal(data.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                vs.diff = nl * _LightColor0;
                vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
                return vs;
            }

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                half4 color = tex2D(_MainTex, ps.uv);
                return color;
            }
            ENDCG
        }
        
        // 阴影投射通道
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }
            Cull Off
            ZWrite On
            ZTest LEqual
            Blend Zero One

            CGPROGRAM
            #pragma multi_compile_shadowcaster

            struct APPDATA
            {
                half4 vertex : POSITION;
                uint instanceID : SV_InstanceID;
            };

            struct SHADERDATA
            {
                half4 vertex : SV_POSITION;
            };

            half3 GenerateRandomPosition(fixed instanceID)
            {
                half3 position;
                position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
                position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
                position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
                return position * _Radius;
            }

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half3 randomPosition = GenerateRandomPosition(data.instanceID);
                half waveAmount = 0.0;
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                return vs;
            }

            half4 fragment_shader() : SV_Target
            {
                return half4(0, 0, 0, 0);
            }
            ENDCG
        }
    }
}
英文:

im currently learning HLSL and shader language in general, and I was wondering if I should recalculate position for each pass or if there was a way around because it seems to me like a lot of redundant calculation.

Bellow is an exemple of the problem, in this code I instantiate a lot of tree mesh and calculate a random position for each of them based on there instance ID. But I have to calculate there position both in the forward pass and in the shadow casting pass. Thank you in advance for your time. (+ Any feedback on the code would be highly appreciated)

Shader "Tree Shader"
{
    CGINCLUDE
    #include "UnityCG.cginc"
    #include "UnityLightingCommon.cginc"
    #pragma vertex vertex_shader
    #pragma fragment fragment_shader
    #pragma target 5.0
    uniform float _Radius;
    uniform float _WaveStartHeight;
    uniform int _InstanceCount;
    uniform sampler2D _MainTex;
    uniform float waveAmount;
    ENDCG

        Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
        SubShader
    {
        Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }

        // Forward Rendering Pass
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Cull Off
            CGPROGRAM
            #pragma multi_compile_fwdbase

            struct APPDATA
            {
                half4 vertex : POSITION;
                half2 uv : TEXCOORD0;
                uint instanceID : SV_InstanceID;
                half3 normal : NORMAL;
            };

            struct SHADERDATA
            {
                half4 vertex : SV_POSITION;
                half2 uv : TEXCOORD0;
                fixed4 diff : COLOR0;
            };

            half4 ComputeScreenPos(half4 p)
            {
                half4 o = p * 0.5;
                return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
            }

            half3 GenerateRandomPosition(fixed instanceID)
            {
                half3 position;
                position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
                position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
                position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
                return position * _Radius;
            }

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half3 randomPosition = GenerateRandomPosition(data.instanceID);
                half waveAmount = 0.0;

                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                vs.uv = data.uv;
                half3 worldNormal = UnityObjectToWorldNormal(data.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                vs.diff = nl * _LightColor0;
                vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
                return vs;
            }

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                half4 color = tex2D(_MainTex, ps.uv);
                return color;
            }
            ENDCG
        }
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }
            Cull Off
            ZWrite On
            ZTest LEqual
            Blend Zero One

            CGPROGRAM
            #pragma multi_compile_shadowcaster

            struct APPDATA
            {
                half4 vertex : POSITION;
                uint instanceID : SV_InstanceID;
            };

            struct SHADERDATA
            {
                half4 vertex : SV_POSITION;
            };

            half3 GenerateRandomPosition(fixed instanceID)
            {
                half3 position;
                position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
                position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
                position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
                return position * _Radius;
            }

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half3 randomPosition = GenerateRandomPosition(data.instanceID);
                half waveAmount = 0.0;
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                return vs;
            }

            half4 fragment_shader() : SV_Target
            {
                return half4(0, 0, 0, 0);
            }
            ENDCG
        }
    }
}

答案1

得分: 0

如果您想要正确的阴影效果,那么需要重新计算顶点位置。您可以将通用代码提取到SubShader中,并将其包装在CGINCLUDE/ENDCG内。

英文:

If you want correct shadows, then the vertex position recaculation is necessary. You can extract the common code into SubShader and wrap it inside CGINCLUDE/ENDCG.

答案2

得分: 0

我修复了你在评论中粘贴的代码中的错误。

Shader "Tree Shader"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
    SubShader
    {   
        Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
 

        CGINCLUDE

        #include "UnityCG.cginc"
        #include "UnityLightingCommon.cginc"
        struct APPDATA
        {
            half4 vertex : POSITION;
            half2 uv : TEXCOORD0;
            uint instanceID : SV_InstanceID;
            half3 normal : NORMAL;
        };
 

        struct SHADERDATA
        {
            half4 vertex : POSITION;
            half2 uv : TEXCOORD0;
            fixed4 diff : COLOR0;
        };
        
        ENDCG

        // Forward Rendering Pass
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Cull Off
            CGPROGRAM
            #pragma target 5.0
            #pragma multi_compile_fwdbase
            #pragma vertex vertex_shader
            #pragma fragment fragment_shader

            
            uniform float _Radius;
            uniform float _WaveStartHeight;
            uniform int _InstanceCount;
            uniform sampler2D _MainTex;
            uniform float waveAmount;

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half waveAmount = 0.0;
 
                half3 randomPosition = half3(
                    frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
                    frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
                    frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
                );
            
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                vs.uv = data.uv;
                half3 worldNormal = UnityObjectToWorldNormal(data.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                vs.diff = nl * _LightColor0;
                vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
                return vs;
            }

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                half4 color = tex2D(_MainTex, ps.uv);
                return color;
            }
            ENDCG
        }
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }
            Cull Off
            ZWrite On
            ZTest LEqual
            Blend Zero One
 

            CGPROGRAM
            #pragma target 5.0
            #pragma multi_compile_shadowcaster
            #pragma vertex vertex_shader
            #pragma fragment fragment_shader

            uniform float _Radius;
            uniform float _WaveStartHeight;
            uniform int _InstanceCount;
            uniform sampler2D _MainTex;
            uniform float waveAmount;
            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs = (SHADERDATA)0;
                half waveAmount = 0.0;
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
            
                half3 randomPosition = half3(
                    frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
                    frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
                    frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
                );
                vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                return vs;
            }

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                return half4(0, 0, 0, 0);
            }
            ENDCG
        }
    }
}
英文:

I fixed the errors in your code that you paste in the comment.

Shader "Tree Shader"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
    SubShader
    {   
        Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
 

        CGINCLUDE

        #include "UnityCG.cginc"
        #include "UnityLightingCommon.cginc"
        struct APPDATA
        {
            half4 vertex : POSITION;
            half2 uv : TEXCOORD0;
            uint instanceID : SV_InstanceID;
            half3 normal : NORMAL;
        };
 

        struct SHADERDATA
        {
            half4 vertex : POSITION;
            half2 uv : TEXCOORD0;
            fixed4 diff : COLOR0;
        };
        
        ENDCG

        // Forward Rendering Pass
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Cull Off
            CGPROGRAM
            #pragma target 5.0
            #pragma multi_compile_fwdbase
            #pragma vertex vertex_shader
            #pragma fragment fragment_shader

            
            uniform float _Radius;
            uniform float _WaveStartHeight;
            uniform int _InstanceCount;
            uniform sampler2D _MainTex;
            uniform float waveAmount;

            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs;
                half waveAmount = 0.0;
 
                half3 randomPosition = half3(
                    frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
                    frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
                    frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
                );
            
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
                vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                vs.uv = data.uv;
                half3 worldNormal = UnityObjectToWorldNormal(data.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                vs.diff = nl * _LightColor0;
                vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
                return vs;
            }
 

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                half4 color = tex2D(_MainTex, ps.uv);
                return color;
            }
            ENDCG
        }
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }
            Cull Off
            ZWrite On
            ZTest LEqual
            Blend Zero One
 

            CGPROGRAM
            #pragma target 5.0
            #pragma multi_compile_shadowcaster
            #pragma vertex vertex_shader
            #pragma fragment fragment_shader

            uniform float _Radius;
            uniform float _WaveStartHeight;
            uniform int _InstanceCount;
            uniform sampler2D _MainTex;
            uniform float waveAmount;
            SHADERDATA vertex_shader(APPDATA data)
            {
                SHADERDATA vs = (SHADERDATA)0;
                half waveAmount = 0.0;
                if (data.vertex.y >= _WaveStartHeight)
                {
                    half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
                    half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
                    half fade = max(fadeX, fadeZ);
                    fade = saturate(fade * 2.0 - 1.0);
                    waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
                }
            
                half3 randomPosition = half3(
                    frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
                    frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
                    frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
                );
                vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
                return vs;
            }
 

            half4 fragment_shader(SHADERDATA ps) : SV_Target
            {
                return half4(0, 0, 0, 0);
            }
            ENDCG
        }
    }
}

huangapple
  • 本文由 发表于 2023年7月3日 04:11:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76600605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定