gaoyuhao 发表于 2024-7-15 17:44

基础且直白的Unity衬着-进行URP和默认管线的shader彼此转换-----(Unit和单盏灯光的shader)

正式记录之前想问大师一个问题。此刻大师的项目都是在用哪一个管线进行制作呢。如果可以的话但愿看到笔者文章的同志们能在答复给不才一个答复,谢谢啦。
首先不管是哪个管线其实都是基于SRP(Scriptable Render Pipeline)可编译管线进行的拓展和担任。我们经常说的URP其实是早些年Unity制作的LWRP的升级版。相较于之前的版赋性能,上手度,可拓展性都有了较大的提升(虽然我依旧是感觉其实就是改了改名字而已)HDRP则是专门为高精度衬着和高精度的游戏所筹备的一个超级功能调集体。可以说Unity现有的所有最先进的效果和技术城市在HDRP傍边。自然其复杂度也是成倍的提升。
URP的Shader基础书写格式:

相较于默认管线的shaderlab分歧。URP和HDRP使用的是HLSL的书写方式和方式。可能和咱们之前熟shaderlab有一些小区别。但其实内核都是相通的。只要掌握了此中规律很快就能学会书写的方式,更何况我们还有万能的知乎和youtube呢。
书写一个HLSL的Unit:(对比默认CGLAB的写法会发现部门格式有较大改动)

Shader ”Unlit/URPUnitShader”
{
    Properties
    {
      _MainTex (”Texture”, 2D) = ”white” {}
      _BaseColor(”BaseColor”, Color) = (1,1,1,1)
    }
    SubShader
    {
      Tags { ”RenderPipline” = ”UniversalRenderPipline” ”RenderType”=”Opaque” }
      LOD 100
      //替换为HLSLINCLUDE
      HLSLINCLUDE
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

      struct a2v
      {
            float4 positionOS:POSITION;
            float4 normalOS:NORMAL;
            float2 texcoord:TEXCOORD;
      };

      struct v2f
      {
            float4 positionCS:SV_POSITION;
            float2 texcoord:TEXCOORD;
      };

      CBUFFER_START(UnityPerMaterial)

      float4 _MainTex_ST;
      float4 _BaseColor;
      CBUFFER_END

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      ENDHLSL


      Pass
      {
         HLSLPROGRAM
         #pragma vertex Vert
         #pragma fragment Frag

         v2f Vert(a2v i)
         {
               v2f o;
               o.positionCS = TransformObjectToHClip(i.positionOS.xyz);
               o.texcoord = TRANSFORM_TEX(i.texcoord,_MainTex);
               return o;

         }

         half4 Frag(v2f i):SV_TARGET
         {
               half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,i.texcoord)*_BaseColor;
               return tex;

         }
         ENDHLSL

      }


    }
}对比一些默认管线的shader。
Shader ”Unlit/DefUnitShader”
{
    Properties
    {
      _MainTex (”Texture”, 2D) = ”white” {}
    }
    SubShader
    {
      Tags { ”RenderType”=”Opaque” }
      LOD 100

      Pass
      {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include ”UnityCG.cginc”

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
      }
    }
}对比会发现其实答题的布局没有改变但是在声明变量的时候多了新的声明方式
      CBUFFER_START(UnityPerMaterial)

      float4 _MainTex_ST;
      float4 _BaseColor;
      CBUFFER_END

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      ENDHLSL和默认的有斗劲大的区别。这里需要记一下。容易犯错。接下来给shader加上雾效。
Shader ”Unlit/URPUnitShader”
{
    Properties
    {
      _MainTex (”Texture”, 2D) = ”white” {}
      _BaseColor(”BaseColor”, Color) = (1,1,1,1)
      
    }
    SubShader
    {
      Tags { ”RenderPipline” = ”UniversalRenderPipline” ”RenderType”=”Opaque” }
      LOD 100
      //替换为HLSLINCLUDE
      HLSLINCLUDE
      //插手雾气
      #pragma multi_compile_fog
      #define FOG 1
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

      struct a2v
      {
            float4 positionOS:POSITION;
            float4 normalOS:NORMAL;
            float2 texcoord:TEXCOORD;



      };

      struct v2f
      {
            float4 positionCS:SV_POSITION;
            float2 texcoord:TEXCOORD;
            //URP的雾气需要手动去给一个TEXCOORD。
            #ifdef FOG
            float fogFactor : TEXCOORD1;
            #endif
      };

      CBUFFER_START(UnityPerMaterial)

      float4 _MainTex_ST;
      float4 _BaseColor;
      CBUFFER_END

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      ENDHLSL


      Pass
      {
         Name ”Forward”
         Tags{”LightMode” = ”UniversalForward”}
         HLSLPROGRAM


         #pragma vertex Vert
         #pragma fragment Frag

         v2f Vert(a2v i)
         {
               v2f o;
               o.positionCS = TransformObjectToHClip(i.positionOS.xyz);
               o.texcoord = TRANSFORM_TEX(i.texcoord,_MainTex);
               #ifdef FOG
               o.fogFactor = ComputeFogFactor(o.positionCS.z);
               #endif

               return o;

         }

         half4 Frag(v2f i):SV_TARGET
         {
               half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,i.texcoord)*_BaseColor;

               #ifdef FOG
               tex = float4(MixFog(tex.rgb,i.fogFactor),1);
               #endif
               return tex;

         }
         ENDHLSL

      }


    }
}对比于默认管线的雾气书写方式更加自定义。(变体可以按照需要增加或者删减。)
给URP的shader增加简易的光照和影子:

了解了基本的书写格式后面可以开始进行进一步的书写。加上简单的光照和影子。其实和默认管线的写法类似。
Shader ”Unlit/URPLambertShader”
{
    Properties
    {
      _MainTex (”Texture”, 2D) = ”white” {}
      _BaseColor(”BaseColor”, Color) = (1,1,1,1)
      
    }
    SubShader
    {
      Tags { ”RenderPipline” = ”UniversalRenderPipline” ”RenderType”=”Opaque” }
      LOD 100
      //替换为HLSLINCLUDE
      HLSLINCLUDE
      //插手雾气
      #pragma multi_compile_fog
      #define FOG 1
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

      struct a2v
      {
            float4 positionOS:POSITION;
            float4 normalOS:NORMAL;
            float2 texcoord:TEXCOORD;



      };

      struct v2f
      {
            float4 positionCS:SV_POSITION;
            float2 texcoord:TEXCOORD0;
            float3 normal: TEXCOORD1;
            //URP的雾气需要手动去给一个TEXCOORD。
            #ifdef FOG
            float fogFactor : TEXCOORD2;
            #endif
      };

      CBUFFER_START(UnityPerMaterial)

      float4 _MainTex_ST;
      float4 _BaseColor;
      CBUFFER_END

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      ENDHLSL


      Pass
      {
         Name ”Forward”
         Tags{”LightMode” = ”UniversalForward”}
         HLSLPROGRAM


         #pragma vertex Vert
         #pragma fragment Frag

         v2f Vert(a2v i)
         {
               v2f o;
               o.positionCS = TransformObjectToHClip(i.positionOS.xyz);
               o.texcoord = TRANSFORM_TEX(i.texcoord,_MainTex);
               o.normal = TransformObjectToWorldNormal(i.normalOS.xyz,true);
               #ifdef FOG
               o.fogFactor = ComputeFogFactor(o.positionCS.z);
               #endif

               return o;

         }

         half4 Frag(v2f i):SV_TARGET
         {
               half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,i.texcoord)*_BaseColor;

               //调用Lighting.hlsl中提供的函数体。
               Light light = GetMainLight();
               real4 lightColor = real4(light.color, 1);
               float3 lightDir = normalize(light.direction);
               float lightAtenuation = dot(lightDir, i.normal);

               //Lambert
               tex *= lightAtenuation*lightColor;
               //HalfLambert
               //tex *= lightAtenuation*lightColor*0.5+0.5
               

               #ifdef FOG
               tex = float4(MixFog(tex.rgb,i.fogFactor),1);
               #endif
               return tex;

         }
         ENDHLSL

      }


    }
}CBUFFER_START和CBUFFER_END,对于变量是单个材质独有的时候建议放在这里面,以提高性能。CBUFFER(常量缓冲区)的空间较小,不适合存放纹理贴图这种大量数据的数据类型。HLSL贴图的采样函数和采样器函数,TEXTURE2D (_MainTex)和SAMPLER(sampler_MainTex)。
继续加上自暗影:(暂时只加一盏灯光的。)

Shader ”Unlit/URPLambertShader”
{
    Properties
    {
      _MainTex (”Texture”, 2D) = ”white” {}
      _BaseColor(”BaseColor”, Color) = (1,1,1,1)
      _BaseShadowContral(”DarkPlaceContral”, float) = 0.5
      _SelfShadowPower(”SelfShadow”, Range(0,1)) = 0.5
      _SelfShadowColor(”SelfShadowColor”, Color) = (1,1,1,1)
      
    }
    SubShader
    {
      Tags { ”RenderPipline” = ”UniversalRenderPipline” ”RenderType”=”Opaque” }
      LOD 100
      //替换为HLSLINCLUDE
      HLSLINCLUDE
      //插手雾气
      #pragma multi_compile_fog
      #define FOG 1
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
      #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
      #include”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”

      struct a2v
      {
            float4 positionOS:POSITION;
            float4 normalOS:NORMAL;
            float2 uv:TEXCOORD;
            float4 tangentOS : TANGENT;



      };

      struct v2f
      {
            float4 positionCS:SV_POSITION;
            float3 positionWS : TEXCOORD0;
            float2 uv:TEXCOORD1;
            float3 normalWS: TEXCOORD2;
            //URP的雾气需要手动去给一个TEXCOORD。
            #ifdef FOG
            float fogFactor : TEXCOORD3;
            #endif

            //URP的自暗影需要手动给一个TEXCOORD.

      };

      CBUFFER_START(UnityPerMaterial)
      float _BaseShadowContral;
      float4 _MainTex_ST;
      float4 _BaseColor;
      float _SelfShadowPower;
      float4 _SelfShadowColor;
      CBUFFER_END

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      ENDHLSL


      Pass
      {
         Name ”Forward”
         Tags{”LightMode” = ”UniversalForward”}
         HLSLPROGRAM
         
         #pragma vertex Vert
         #pragma fragment Frag

            
         //插手暗影
         #pragma multi_compile _ADD_LIGHT_ON _ADD_LIGHT_OFF
         #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
         #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
         #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
         #pragma multi_compile _ _SHDOWS_SOFT

         //插手新的光照结算(暂时停用)。
         real3 ShadeSingleLight(Light light, half3 normalWS, bool isAdditionalLight, half3 MainColor)
         {
               //半兰伯特计算。
               half NdotL = saturate(dot(normalWS, light.direction) *_BaseShadowContral+(1-_BaseShadowContral));
               half3 diffuseColor = light.color * (NdotL * light.distanceAttenuation) * MainColor.rgb;

               half Atten = clamp(light.shadowAttenuation +_SelfShadowPower, 0,1);
               half3 AttenColor = _SelfShadowColor * (1-Atten) + Atten;
               //返回最后的颜色
               return diffuseColor * AttenColor;
            }


         v2f Vert(a2v i)
         {
               v2f o;

               VertexPositionInputs positionInputs = GetVertexPositionInputs(i.positionOS.xyz);
               o.positionCS = positionInputs.positionCS;
               o.positionWS = positionInputs.positionWS;
               
               VertexNormalInputs normalInput = GetVertexNormalInputs(i.normalOS, i.tangentOS);
               o.normalWS = NormalizeNormalPerVertex(normalInput.normalWS);

               o.uv = TRANSFORM_TEX(i.uv,_MainTex);

               #ifdef FOG
               o.fogFactor = ComputeFogFactor(o.positionCS.z);
               #endif
               //插手自暗影绘制回调。
               return o;

         }

         half4 Frag(v2f i):SV_TARGET
         {
               half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,i.uv)*_BaseColor;
               //设置需要的基础属性
               half3 normalWS = NormalizeNormalPerPixel(i.normalWS);
               //get shadow coordinate
               float4 shadowCoord = TransformWorldToShadowCoord(i.positionWS);

               Light mainLight = GetMainLight();
               mainLight.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
               half3 mainLightResult = ShadeSingleLight(mainLight, normalWS, false,tex.rgb);
               //自暗影计算


               //调用Lighting.hlsl中提供的函数体。
               float4 color = float4(mainLightResult,1);
               
               #ifdef FOG
               color = float4(MixFog(color.rgb,i.fogFactor),1);
               #endif





               return color;

         }
         ENDHLSL

      }
      //使用Unity提供的shadowcaster;UsePass不知道为啥会掉效
      UsePass ”Universal Render Pipeline/Lit/ShadowCaster”



    }
}URP的HLSL语言中大量运用了变体来开启或封锁功能。非常的便利。(终于可以直接拿现有的功能模块在shader中调用了)不外相对的。也会限制制作者的阐扬。有空的话最好还是从0开始本身全部实现一遍,斗劲项目需求千变万化。
多展灯光的记录后续再补充吧。下次吧shadow和shadowcaster自定义一遍便利后续进行特定改削。

                                                                                                            记录日期: 2022/9/15
页: [1]
查看完整版本: 基础且直白的Unity衬着-进行URP和默认管线的shader彼此转换-----(Unit和单盏灯光的shader)