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

SurfaceShader学习

程序员文章站 2022-03-30 08:25:28
...
  • 标准表面着色器输出结构
struct SurfaceOutput
{
    fixed3 Albedo;  // diffuse color,反射率,纹理颜色
    fixed3 Normal;  // tangent space normal, if written,法线
    fixed3 Emission;  //自发光
    half Specular;  // specular power in 0..1 range 镜面反射度
    fixed Gloss;    // specular intensity 光泽度    
    fixed Alpha;    // alpha for transparencies 透明度
};

Unity5中,也可以使用基于物理的照明模型。

struct SurfaceOutputStandard
{
    fixed3 Albedo;      // base (diffuse or specular) color
    fixed3 Normal;      // tangent space normal, if written
    half3 Emission;
    half Metallic;      // 0=non-metal, 1=metal
    half Smoothness;    // 0=rough, 1=smooth
    half Occlusion;     // occlusion (default 1)
    fixed Alpha;        // alpha for transparencies
};
struct SurfaceOutputStandardSpecular
{
    fixed3 Albedo;      // diffuse color
    fixed3 Specular;    // specular color
    fixed3 Normal;      // tangent space normal, if written
    half3 Emission;
    half Smoothness;    // 0=rough, 1=smooth
    half Occlusion;     // occlusion (default 1)
    fixed Alpha;        // alpha for transparencies
};
  • 使用方式:
//表面着色函数的编写  
void surf (Input IN, inout SurfaceOutput o)  
{  
    //反射率,也就是纹理颜色值赋为(0.6, 0.6, 0.6)  
       o.Albedo= 0.6;  
}  
  • Surface Shader 编译指令,表面着色器放置在CGPROGRAM...ENDCG块内

    • 必须放置在subShader块内,不在Pass内。

    • 必须使用#pragma surface ...表示它是一个表面着色器

      #pragma surface surfaceFunction lightModel[optionalparams]
      
      • surfaceFunction指明那个Cg函数是表面着色器代码,函数的形式应该是void surf (Input IN, inout SurfaceOutput o),其中Input是您定义的结构。输入应该包含表面函数所需的任何纹理坐标和额外的参数。
      • lightModel - 照明模式使用。内置的有基于物理的Standard和StandardSpecular,以及简单的非基于物理的Lambert(漫射)和BlinnPhong(镜面)。
        • Standard光照模型使用SurfaceOutputStandard输出结构,并与Unity中的标准(metallic )着色器匹配。
        • StandardSpecular光照模型使用SurfaceOutputStandardSpecular输出结构,并匹配Unity中的标准(Specular)着色器。
        • Lambert、BlinnPhong照明模型不是基于物理的(来自Unity 4.x),但是使用它们的着色器可以在低端硬件上更快地渲染。
    • Input Structure

        struct Input {
            float2 uv_MainTex;
            float2 uv_BumpMap;
            float3 worldPos;
        };
      

      Input 这个输入结构通常拥有着色器需要的所有纹理坐标(texture coordinates)。纹理坐标(Texturecoordinates)必须被命名为“uv”后接纹理(texture)名字。(或者uv2开始,使用第二纹理坐标集)。
      另外还有一些额外的参数可以添加:

      • float3 viewDir - 视图方向( view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim lighting)等,需要包含视图方向( view direction)值。
      • float4 with COLOR semantic -每个顶点(per-vertex)颜色的插值。
      • float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位置信息。比如在Dark Unity中所使用的 WetStreet着色器。
      • float3 worldPos - 世界空间中的位置。
      • float3 worldRefl - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。 请参考这个例子:Reflect-Diffuse 着色器。
      • float3 worldNormal - 世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
      • float3 worldRefl; INTERNAL_DATA - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal))。请参考这个例子: Reflect-Bumped着色器。
      • float3 worldNormal; INTERNAL_DATA -世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的法线向量(normal vector)需要使用世界法线向量(WorldNormalVector (IN, o.Normal))。
  • CG函数

    • UnpackNormal() UnpackNormal接受一个fixed4的输入,并将其转换为对应的法线值(fixed3),并将其赋予输出的Normal。
    o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));
    
    • saturate() 取值控制在[0,1]
      • 如果x取值小于0,则返回值为0.
      • 如果x取值大于1,则返回值为1.
      • 若x在0到1之间,则直接返回x的值。
    • dot() 点积操作
      实现:
      float dot(float4 a, float4 b)  
      {  
          return a.x*b.x +a.y*b.y + a.z*b.z + a.w*b.w;  
      }  
      
    • pow(x,y) 求幂 x的y次幂
    • tex2D() 2D纹理采样
    float4 tex2D(sampler2D samp, float2 s)
    float4 tex2D(sampler2D samp, float2 s, inttexelOff)
    float4 tex2D(sampler2D samp, float3 s)
    float4 tex2D(sampler2D samp, float3 s, inttexelOff)
    float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy)
    float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)
    float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy)
    float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy, int texelOff)
    int4 tex2D(isampler2D samp, float2 s)
    int4 tex2D(isampler2D samp, float2 s, inttexelOff)
    int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy)
    int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)
    unsigned int4 tex2D(usampler2D samp, float2s)
    unsigned int4 tex2D(usampler2D samp, float2s, int texelOff)
    unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy)
    unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy,int texelOff)
    

    参数简介:
    samp-需要查找的采样对象,也就是填个纹理对象在这里。
    s-需进行查找的纹理坐标。uv左边
    dx-预计算的沿X轴方向的导数。
    dy-预计算的沿Y轴方向的导数。
    texelOff-添加给最终纹理的偏移量

    void surf (Input IN, inout SurfaceOutput o) {
        // Albedo comes from a texture tinted by color
        o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;
        //设置细节纹理  
        o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb * 2;   
        o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));
        //从_RimColor参数获取自发光颜色  
        half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  
        o.Emission = _RimColor.rgb * pow (rim, _RimPower);  
    }
    
  • 表面着色器照明

    • GI
      • half4 Lighting<Name> (SurfaceOutput s, UnityGI gi):在不依赖于视图方向(view direction)的轻型模型的正向渲染路径(forward rendering path)中使用此方法,比如漫反射(diffuse)
      • half4 Lighting<Name> (SurfaceOutput s, half3 viewDir, UnityGI gi); 在光模型正向渲染路径(forward rendering path)使用此方法,依赖于视图方向(view direction)。
      • half4 Lighting<Name>_Deferred (SurfaceOutput s, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal); 在延期的照明路径中使用这个。
    • 没有GI
      • half4 Lighting<Name>_PrePass (SurfaceOutput s, half4 light); 在轻度预备(传统延期)照明路径中使用此功能。
      • half4 LightingName (SurfaceOutput s, half3 lightDir, half atten):此种形式的函数可以表示在正向渲染路径(forward rendering path)中的光照模式,且此函数不取决于视图方向(view direction)。例如:漫反射(diffuse)。
      • half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten):此种形式的函数可以表示在正向渲染路径(forward rendering path)中使用的光照模式,且此函数包含了视图方向(view direction)。
      • half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal):这种形式也是不依赖于视图方向(view direction)的光照模式。例如:漫反射(diffuse)。
      • half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, half3 viewDir, bool surfFuncWritesNormal,out half3 specColor):这是使用的依赖于视图方向(view direction)的光照模式(light model)。
一个光照模式(lighting model)要么使用视图方向(view direction)要么不使用。同样的,如果光照模式(lightingmodel)在延时光照(deferred lighting)中不工作,只要不声明成 _PrePass,就是行的。
  • 不使用GI

    Shader "Custom/WrapLambert" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
            
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf WrapLambert
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
            sampler2D _MainTex;
            half4 LightingWrapLambert(SurfaceOutput s,half3 lightDir, half atten){
                fixed diff = max(0,dot(s.Normal,lightDir));
                // diff = diff * 0.5 + 0.5;
                fixed4 c;
                c.rgb = s.Albedo * _LightColor0.rgb*(diff);
                c.a = s.Alpha;
                return c;
            }
            struct Input {
                float2 uv_MainTex;
            };
    
            fixed4 _Color;
    
            void surf (Input IN, inout SurfaceOutput o) {
                // Albedo comes from a texture tinted by color
                fixed4 color = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = color.rgb;
                // Metallic and smoothness come from slider variables
                o.Alpha = color.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    
  • 使用GI

    Shader "Custom/SurfaceShaderGI" {
        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 {
            Tags { "RenderType"="Opaque" }
            LOD 200
            
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf StandardDefaultGI
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
            #include "UnityPBSLighting.cginc"
    
            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);
            }   
            sampler2D _MainTex;
    
            struct Input {
                float2 uv_MainTex;
            };
    
            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
    
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // Albedo comes from a texture tinted by color
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                // Metallic and smoothness come from slider variables
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    

很多基础知识还是不会的,接下来需要恶补。

参考一

参考二