欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Shader表面着色器结构分析

程序员文章站 2022-06-10 21:06:03
...

1:表面着色器包括4个函数:  

(1): 顶点变换函数; (可选参数)

(2): 表面着色函数;    

(3): 光照模型;   (可选参数)

(4): 最终颜色修改函数; (可选参数)

2: 表面着色器最终会被编译为一个复杂的顶点着色程序

3.定义入口函数

1:#pragma surface +入口函数名称 +光照模型  +[Options]

2: #pragma surface 后面跟 表面着色的入口函数 ,例如: surf(Input IN, inout SurfaceOutput o);

3: 光照模型:      

(1)系统内置: Lambert(漫反射光照) ,BlinnPhong (高光光照)   

(2)自定义光照模型: 函数名=Lighting+模型Name            

half4 Lighting<Name>(SurfaceOutput s, half3 lightDir, half atten);          

例子:

Shader "Example/Diffuse Texture" {
        Properties {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
          #pragma surface surf SimpleLambert
  
          half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
              half NdotL = dot (s.Normal, lightDir);
              half4 c;
              c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
              c.a = s.Alpha;
              return c;
          }
  
        struct Input {
            float2 uv_MainTex;
        };
        
        sampler2D _MainTex;
        
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        }
        ENDCG
        }
        Fallback "Diffuse"
    }

half4 Lighting<Name>(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);  

例子:

    ...ShaderLab code...
    CGPROGRAM
    #pragma surface surf SimpleSpecular

    half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
        half3 h = normalize (lightDir + viewDir);

        half diff = max (0, dot (s.Normal, lightDir));

        float nh = max (0, dot (s.Normal, h));
        float spec = pow (nh, 48.0);

        half4 c;
        c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * atten;
        c.a = s.Alpha;
        return c;
    }

    struct Input {
        float2 uv_MainTex;
    };
    
    sampler2D _MainTex;
    
    void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    }
    ENDCG
    ...ShaderLab code...

        

half4 Lighting<Name>(SurfaceOutput s, half4 light);

half4 Lighting<Name> (SurfaceOutput s, UnityGI gi);用于前向渲染,不依赖视线

half4 Lighting<Name> (SurfaceOutput s, half3 viewDir, UnityGI gi);用于前向渲染,依赖视线

例子:

    Shader "Example/CustomGI_ToneMapped" {
        Properties {
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            
            CGPROGRAM
            #pragma surface surf StandardDefaultGI
    
            #include "UnityPBSLighting.cginc"
    
            sampler2D _MainTex;
    
            inline half4 LightingStandardDefaultGI(SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
            {
                return LightingStandard(s, viewDir, gi);
            }
    
            inline void LightingStandardDefaultGI_GI(
                SurfaceOutputStandard s,
                UnityGIInput data,
                inout UnityGI gi)
            {
                LightingStandard_GI(s, data, gi);
            }
    
            struct Input {
                float2 uv_MainTex;
            };
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
            }
            ENDCG
        }
        FallBack "Diffuse"

half4 Lighting<Name>_Deferred (SurfaceOutput s, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal);用于延迟(deferred)渲染

half4 Lighting<Name>_PrePass (SurfaceOutput s, half4 light);用于传统light prepass (legacy deferred) 

[Options] 可选参数:

4: vertex: 后面跟顶点变换入口函数的Name,注意冒号后面有空格

void <Name> (inout appdata_full v) 只需改顶点着色器中的输入顶点数据;

half4 <Name>(inout appdata_full v, out Input o) 修改输入顶点数据,以及为表面着色器传递数据;

例子:

Shader "Example/Normal Extrusion" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Amount ("Extrusion Amount", Range(-1,1)) = 0.5
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert vertex: vert //注意冒号后面有空格
      struct Input {
          float2 uv_MainTex;
      };
      float _Amount;
      void vert (inout appdata_full v) {
          v.vertex.xyz += v.normal * _Amount;
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

5: finalcolor: 后面跟最终颜色修改函数的Name:    

void <Name>(Input IN, SurfaceOutput o, inout fixed4 color);

例子:

Shader "Example/Tint Final Color" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _ColorTint ("Tint", Color) = (1.0, 0.6, 0.6, 1.0)
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert finalcolor:mycolor
      struct Input {
          float2 uv_MainTex;
      };
      fixed4 _ColorTint;
      void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
      {
          color *= _ColorTint;
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

4.其它可选参数

1:alpha: Alpha 混合模式,用户半透明着色器;

2: alphatest: varirableName Alpha测试模式,用户透明镂空着色器。

3: exclude_path:prepass 使用指定的渲染路径;

4: addshadow: 添加阴影投射器和集合通道;

5: dualforward: 将双重光照贴图用于正向渲染路径中;

6: fullforwardshadows 在正向渲染路径中支持的所有的阴影类型;

7: decal: add 附加印花着色器;

8: decal: blend 附加半透明印花着色器;

9: softvegetation 使用表面着色器,仅在Soft Vegetation 开启时被渲染;

10: noambient 不使用任何光照

11: novertexlights 在正向渲染中不适用球面调和光照或逐点光照;

12: nolightmap 在这个着色器上禁用光照贴图;

13: nodirlightmap 在这个着色器上禁用方向光照贴图;

14: noforwardadd 禁用正向渲染添加通道;

15: approxview: 对于有需要的着色器,逐顶点而不是逐像素计算规范化视线方向。

16: halfasview:  将半方向传递到光照函数中。

5.Input 结构附加数据

Input:包含着色所需要的纹理坐标 uv纹理名字;使用第二张纹理是uv2纹理名字; 附加数据:

1:float3 viewDir  视图方向。

2:float4 color 每个顶点的颜色插值,需要声明语义:COLOR;

3: float4 screenPos 屏幕空间中的位置。

4: float3 worldPos 世界坐标空间;  

5: float3 worldRef1 世界空间中的反射向量;

6: float3 worldNormal 世界空间中的法线向量;

7: float3 worldRef1; INTERNAL_DATA 世界坐标反射向量, 但必须表面着色写入o.Normal参数;

8: float3 worldNormal; INTERNAL_DATA 世界坐标法线向量, 但必须表面着色写入o.Normal参数;

6.SurfaceOutput 结构体 

SurfaceOutput:见Writing Surface Shaders

1: half3 Albedo: 漫反射的颜色值;

2: half3 Normal: 法线坐标;

3: half3 Emission; 自发光颜色;

4: half Specular;  镜面反射系数;

5: half Gloss; 光泽系数;

6: half Alpha; 透明度系数; SurfaceOutputStandard:

7: half Smoothness;    // 0=粗糙, 1=光滑

8: half Metallic;    // 0=非金属, 1=金属

SurfaceOutputStandardSpecular:    

fixed3 Albedo;        

fixed3 Specular;        

fixed3 Normal;        

half3 Emission;      

half Smoothness;    // 0=粗糙, 1=光滑      

half Occlusion;  // 遮挡(默认1)      

fixed Alpha;  

7.Unity坐标系转换

1: transform.localToWorldMatrix   局部转世界的矩阵;

2: transfrom.worldToLocalMatrix  世界坐标转局部坐标矩阵;    

3: MultiplyPoint, MultiplyPoint3x4 MultiplayVector 来进行坐标变换; 4: shader中 左乘unity_WorldToObject矩阵来实现世界坐标转局部坐标变换;

5: shader中左乘unity_ObjectToWorld矩阵来实现局部转世界的转换;

6: UNITY_MATRIX_MV 基本变换矩阵 x 摄像机矩阵;

7: UNITY_MATRIX_MVP 基本变换矩阵x摄像机矩阵x投影矩阵;

8: UNITY_MATRIX_V 摄像机矩阵;

9: UNITY_MATRIX_P 投影矩阵;

10: UNITY_MATRIX_VP摄像机矩阵x投影矩阵;

11: UNITY_MATRIX_T_MV (基本变换矩阵 x 摄像机矩阵) 转置矩阵;

12: UNITY_MATRIX_IT_MV(基本变换矩阵 x 摄像机矩阵) 的逆转置矩阵;

13: UNITY_MATRIX_TEXTURE0 纹理变化矩阵;

最后附上Unity自带surface shader范本:

Shader "Custom/sf" {
    Properties {   //属性,显示在面板上的,可以调值的
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5 //浮点值,高光的光泽度
        _Metallic ("Metallic", Range(0,1)) = 0.0 //金属光泽
    }
    SubShader {
          //surface shader 中不需要编写pass通道,是对vertex shader和fragment shader的一种包装 
        Tags { "RenderType"="Opaque" }   //tags 渲染类型的描述,opaque表示不透明
        LOD 200  //层级细节

        CGPROGRAM   //代表使用CG语言编写shader直到ENDCG结束
        // Physically based Standard lighting model, and enable shadows on all light types
        //#pragma表示一个编译指令 ;surface表示该shader类型是surface shader ;
         // surf表示一个入口函数名称,在下面的代码中编写这个函数;Standard 表示一种光照模型(函数)注意大小写,unity内有lightingStandard这个函数(5.0以前版本是lambert)
         //fullforwardshadows是一种阴影类型,该类型支持所有的阴影类型在forward渲染路径下,shder阴影类型
         //还有addshadow和tessellate类型
        #pragma surface surf Standard fullforwardshadows 

        // Use shader model 3.0 target, to get nicer looking lighting
        //这个指令代表使用3.0的光照,默认是3.0,越高光照效果越好
        #pragma target 3.0

        sampler2D _MainTex; //纹理单位sampler2D
        //输入结构体,描述uv纹理坐标 ,注意这个uv纹理变量必须是小写uv + sampler2D的变量名,uv不能少,unityshader官方如此表述
        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness; //对应于properties中的属性在函数体内的声明,注意变量类型关键字不一样了
        half _Metallic;  //2d--sampler2D; color--fixed4; Range--half
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_CBUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_CBUFFER_END
        //inout该函数表示即时输入也是输出
        //surf函数两个参数,一个Input,SurfaceOutputStandard表示5.0以后版本中基于物理的光照模型的结构体,对应光照模型Standard,如果使用Lambert或BlinnPhong模型,可以使用SurfaceOutput结构体
        //之前是SurfaceOutput结构体(固定名称)
        void surf (Input IN, inout SurfaceOutputStandard o) {  
                                                                  
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;//tex2D是CG中的一个函数,主要用来使用纹理坐标从纹理中得到数据,
            //然后赋值给SurfaceOutputStandard中的Albedo,Metallic,Smoothness,Alpha
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse" //上面的shader都不管用时,就默认使用diffuse shader渲染物体,扮演备胎的角色
}

 

相关标签: shader