SurfaceShader学习

  • 标准表面着色器输出结构
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"
    }
    
    

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

参考一

参考二

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容