Unity shader 学习笔记(初级篇)

这一章节学习的较慢,呜呜呜呜泪目,但感觉战线拉长不利于掌握,后期尽快提升进度。

2 初级篇

2.5 开始Unity的学习之旅

2.5.1 本书使用的软件和环境

本书基于mac编写的

2.5.2 最简单的顶点/片元着色器

  1. 顶点片元着色器的基本结构

    Shader"MyShaderName"{
        Properties{
        //属性
        }
        SubShader{
            Pass{
                CGPROGAM
                ......
                ENDCG
            }
        }
    ​
        fALLBACK"VertexLit"
    }

    最重要的是pass语义快

    这里做一个实例

    分析代码块:

    我们没有在shader里面设置任何tages和rendersetup,在pass里面也没有设置,采取的是默认tages和rendersetup,

            #pragma vertex vert
            #pragma fragment frag

    告诉unity哪一个函数包括顶点着色器或者片元着色器的代码

    float4 vert(float4 v :POSITION) : SV_POSITION{
                    return UnityObjectToClipPos(v);
                    //float4 m1 = UNITY_MATRIX_MVP;
                    //return mul (m1,v);
                }

    如上是vert即是顶点着色器的代码,逐顶点执行,这一句的含义是指把顶点坐标从模型空间转换到裁剪空间,float4类型的变量,position语义是指告诉unity把模型的顶点坐标输入到v中,而sv_position语义是指告诉unity顶点着色器函数是输出裁剪空间中的顶点坐标。

    fixed4 frag() : SV_Target{
                    return fixed4(1.0,1.0,1.0,1.0);
                }

    这里输出一个fixed4类型的变量,sv_target语义是指告诉渲染器把用户的输出颜色存储入一个渲染目标中,这里默认存储在帧缓存中,(0,0,0,0)表示黑色,(1,1,1,1)表示白色

    Shader "Custom/Chapter5-SimpleShader"
    {
            SubShader{
                Pass{
                    CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    ​
                float4 vert(float4 v :POSITION) : SV_POSITION{
                    return UnityObjectToClipPos(v);
                }
                fixed4 frag() : SV_Target{
                    return fixed4(1.0,1.0,1.0,1.0);
                }
                ENDCG
            }
        }
    }

 

  1. 模型数据从哪里来

    我们需要知道更多模型的数据,上述例子我们通过position得知模型的顶点坐标,我们现在定义结构体来实现多属性的访问。

    Shader "Custom/Chapter5-SimpleShader"
    {
        SubShader{
            Pass{
                CGPROGRAM
    ​
                #pragma vertex vert
                #pragma fragment frag
    ​
                //用一个结构体来定义顶点着色器的输入
                struct a2v {
                //告诉unity用模型空间的顶点坐标填充vertex变量
                float4 vertex : POSITION;
                //告诉unity用模型空间的法线方向填充normal变量
                float3 normal : NORMAL;
                //告诉unity用模型的第一套纹理坐标填充texcoord变量
                float4 texcoord : TEXCOORD0;
    ​
                };
    ​
                float4 vert(a2v v) : SV_POSITION{
                return  UnityObjectToClipPos(v.vertex);
                }
                fixed4 frag() : SV_Target{
                    return fixed4(1.0,1.0,1.0,1.0);
                }
                ENDCG
            }
        }
    }

    我们定义结构体,利用结构体来访问模型空间内的相关属性,对于顶点着色器的输入,unity支持的语义有:position,tangent,normal,texcood0,texcood1,texcood2,texcood3,color等。

    结构体的通项公式

    struct structname{
        type name : semantic;
        type name : semantic;
                
                ......
    }

    语义是不可以缺少的

    a2v是什么意思?

    a是指application,是指应用,v是指vertex shader,这里是指把数据从应用阶段传入到顶点着色器当中,这些数据是从哪里来的捏,是由mesh render提供的,每一帧调用draw call时候,mesh render会把负责渲染的模型数据发送给unity shader。

  2. 顶点着色器和片元着色器的通信

    在实际操作中,我们希望顶点着色器可以把模型的法线,纹理坐标传递给片元着色器,这就涉及到了顶点着色器和片元着色器之间的通信。

    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    ​
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    ​
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    ​
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    ​
    Shader "Custom/Chapter5-SimpleShader"
    {
        SubShader{
            Pass{
                    
                CGPROGRAM
                        
                #pragma vertex vert
                #pragma fragment frag
    ​
    ​
                //用一个结构体来定义顶点着色器的输入
                struct a2v {
                //POSITION告诉unity用模型空间的顶点坐标填充vertex变量
                float4 vertex : POSITION;
                //NORMAL告诉unity用模型空间的法线方向填充normal变量
                float3 normal : NORMAL;
                //TEXCOORD0告诉unity用模型的第一套纹理坐标填充texcoord变量
                float4 texcoord : TEXCOORD0;
    ​
                };
    ​
                //使用一个结构体来定义顶点着色器的输出
        struct v2f {
            //SV_POSITION告诉unity在pos中包含顶点在裁剪空间中的信息
            float4 pos : SV_POSITION;
            //COLOR0用于存储颜色信息
            fixed3 color :COLOR0;
        };
    ​
                v2f vert(a2v v) {
                    //声明输出结构
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    // v.normal 包含了顶点的法线方向,其分量范围在[-1.0,1.0]
                    //下面的代码把分量范围映射到[0.0,1.0]
                    //存储到o.color中传递给片元着色器
                    o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
                    return o;
                }
    ​
                fixed4 frag(v2f i) : SV_Target{
                    return fixed4(i.color,1.0);
                }
                ENDCG
            }
        }
    }
    ​

     

    注意,这里我们通过定义v2f来定义从顶点着色器到片元着色器的转换过程,同时也需要定义结构体来满足变量的语义要求,片元和顶点的区别在于片元把顶点的数据进行了插值。

  3. 如何使用属性

    在properties中定义属性,并在pass中同样定义同名称同类型的属性

2.5.3 强大的援手:unity提供的内置文件和变量

unityCG.cginc包含许多结构体以及函数方便我们调用

2.5.4 unity提供的CG/HLSL语义

  1. 什么是语义

    语义简单理解为让shader知道从哪里读取数据,并把数据输出到哪里,unity并不包含所有的shader

    系统数值语义,以SV开头,这种语义是不能随便赋值,不同平台对语义存在不同的兼容性,这一点需要我们注意。

  2. unity支持的语义

    • 应用阶段传递数据给顶点着色器

      • position:模型空间顶点的位置:float4

      • normal:顶点法线:float3

      • tangent:顶点切线:float4

      • texcoordn:顶点纹理坐标:float2/float4

      • color:顶点颜色fixed4/float4

    • 顶点着色器到片元着色器传递数据

      • sv_position:裁剪空间的顶点坐标

      • color0:通常用于输出第一组顶点颜色

      • color1:常用于输出第二组顶点颜色

      • texcoordn:通常用于输出纹理坐标

      一般来说我们使用texcoord来存储自定义的变量

    • 片元着色器输出语义

      sv_target:输出值将会存储到渲染目标中,类似于color

  3. 如何定义复杂的变量模型

2.5.5 Debug

unity shader的调试方法

  1. 使用假彩色图像

    通过将假彩色图像映射到(0,1),区间然后和真彩色逐像素进行对比,来实现debug

  2. 利用visual studio

    Graphics debugger

  3. 帧调试器

2.5.6 渲染平台的差异

  1. 渲染纹理坐标差异

    一般来说unity帮助我们处理了反转情况,但是当我们打开抗锯齿的时候,并且需要同时渲染多张图像的时候,我们需要自己在顶点着色器主动开启翻转技术

    #if UNITY_UV_STARTS_AT_TOP
    if (_MainTex_TexelSize.y < 0)
      uv.y = 1-uv.y;
      #endif

    噪声纹理一般不需要进行反转处理

2.5.7 shader的整洁之道

float:32位

half:16位 -6000到6000

fixed:11位 -2.0到2.0

PC端上GPU处理后的精度很难看出区别,所以我们一般通过观察移动端来判断精度,fixed和half基本相同目前来说,尽可能使用精度较低的模型,这样有助于优化shader的性能,一般使用fixed来存储颜色和单位矢量

我们要避免不必要的计算

谨慎使用循环选择语句

  • 分支判断语句中使用条件变量最好是常数,在shader运行当中不会发生变化

  • 分支当中包含的操作指令数尽量减少

  • 分支的嵌套尽可能减少

不要 除于零

2.6 Unity中的基础光照

  • 像素的可见性

  • 像素的光照计算

2.6.1 如何看到世界

  • 光线是从光源发射出来

  • 光线和物体相交,一些被吸收,一些被反射

  • 摄像机吸收一些光,产生图像

  1. 光源

    辐照度:垂直于光线方向的单位面积上单位时间穿过的能量来描述

    利用光源方向和面的法线方向的角度余弦值来描述

  2. 吸收和散射

    散射改变光线的方向不改变光线的其他属性:包括折射以及反射

  3. 着色

    根据材质属性以及光源信息等,使用一个等式来计算出射度过程,即为光照模型

  4. BRDF模型

2.6.2 标准光照模型

  • 自发光:不使用全局光照技术,自发光将不会照亮周围物体

  • 高光反射:phong模型,通过计算高光的反射方向,结合高光反射颜色等性质计算高光反射。blinn phong模型改善phong,不用计算反射角度,通过计算入射光线和视线之合的1/2,来取代更复杂就计算。blinn模型适合静态计算,phong模型适合动态计算

  • 漫反射:符合兰伯特定律:反射光线的强度和表面法线与光源方向的夹角的cos正比

  • 环境光:描述所有间接光照

片元着色器:逐像素计算

顶点着色器:逐顶点计算,在顶点计算光照,渲染图元内部插值,是非线性的会容易出现棱角现象,因为图元内部的颜色一般会暗于顶点颜色

菲涅尔反射无法用blinn phong来表示,其次blinn phong模型是各项同性

2.6.3 unity中的环境光和自发光

 

2.6.4 在unity shader中实现漫反射光照模型

四个变量

入射光线的颜色和强度,材质的漫反射系数,表面法线以及光源方向

Cg提供了函数来实现漫反射

函数:saturate(x) 饱和的意思

参数:x:用于操作的标量或者矢量

描述:把x截取在[0,1]范围,如果x是一个矢量,那么会对它的每一个分量进行这样的操作

  • 实践:逐顶点光照

    // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    ​
    // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    ​
    Shader "Custom/Chapter6-DiffuseOixelLevel"
    { Properties
        {
           _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
    }
    SubShader
        {
            Pass{
            Tags { "LightMode" = "ForwardBase" }
    ​
            CGPROGRAM
    ​
            #pragma vertex vert
            #pragma fragment frag
    ​
            # include "Lighting.cginc"
            fixed4 _Diffuse;
    ​
        struct a2v {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
        };
    ​
    ​
        struct v2f {
            float4 pos : SV_POSITION;
            float3 worldNormal : TEXCOOD0;
        };
    ​
        v2f vert(a2v v) {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
    ​
            o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
    ​
            return o;
        }
    ​
        fixed4 frag(v2f i) : SV_Target{
    ​
            fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    ​
            fixed3 worldNormal = normalize(i.worldNormal);
    ​
            fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
    ​
    ​
            fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
    ​
            fixed3 color = ambient + diffuse;
    ​
            return fixed4(color, 1.0);
        }
            ENDCG
            }
    ​
    }
    FallBack "Diffuse"
    }
    ​

  • 实践:逐像素光照

    // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    ​
    Shader "Custom/Chapter6-Diffuse VertexLevel"
    {
        Properties
        {
           _Diffuse("Diffuse",Color) = (1,1,1,1)
        }
            SubShader
        {
            Pass{
            Tags { "LightMode" = "ForwardBase" }
    ​
            CGPROGRAM
    ​
            #pragma vertex vert
            #pragma fragment frag
    ​
            # include "Lighting.cginc"
            fixed4 _Diffuse;
    ​
        struct a2v {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
        };
    ​
    ​
        struct v2f {
            float4 pos : SV_POSITION;
            fixed3 color : COLOR;
        };
    ​
        v2f vert(a2v v) {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
    ​
            fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
    ​
            fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    ​
            fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
    ​
            fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
    ​
            o.color = ambient + diffuse;
    ​
            return o;
        }
    ​
        fixed4 frag(v2f i) : SV_Target{
            return fixed4(i.color, 1.0);
        }
            ENDCG
            }
           
        }
        FallBack "Diffuse"
    }
    ​

     

半勃兰特模型

Shader "Custom/333"
{
    
        Properties
        {
             _Diffuse("Diffuse",Color) = (1,1,1,1)
        }
            SubShader
        {
​
​
            Pass
            {
              Tags{"LightMode" = "ForwardBase"}
​
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
​
                #include "Lighting.cginc"
​
            //定义和properties语义块中属性类型相匹配的变量
            fixed4 _Diffuse;
​
            struct a2v
            {
                float4 vertex : POSITION;
                //定义变量,并通过语义告知unity将法线信息存储到normal变量中
                float3 normal : NORMAL;
            };
​
            struct v2f
            {
                //SV_POSITION语义告诉Unity,pos 里包含了顶点在裁剪空间中的位置信息
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
            };
​
            v2f vert(a2v v)
            {
                v2f o;
​
                o.pos = UnityObjectToClipPos(v.vertex);//把顶点位置从模型空间转到裁剪空间
​
                o.worldNormal = UnityObjectToWorldNormal(v.normal);//法线转换到世界空间
​
                return o;
            }
​
            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//获得环境光
​
                fixed3 worldNormal = normalize(i.worldNormal);//法线转换到世界空间
​
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//获得光源方向
​
                fixed halfLambert = dot(worldNormal, worldLight) * 0.5 + 0.5;
​
                //使用半兰伯特模型计算光照 
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;//saturate防止点积为负
​
                fixed3 color = ambient + diffuse;
​
                return fixed4(color,1.0);
            }
​
                ENDCG
​
         }
​
​
​
        }
            Fallback "Diffuse"
    }
​
​

 

2.6.5 在unity shader 中实现高光反射光照模型

四个要素

入射光线的颜色强度,材质的高光反射系数,视角方向以及反射方向

逐顶点光照

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
​
Shader "Custom/1"
{
    properties{
       _Diffuse("Diffuse",Color) = (1,1,1,1)
       _Specular("Specular",Color) = (1,1,1,1)
       _Gloss("Gloss",Range(8.0,256)) = 20
    }
​
        subshader{
        pass{
        Tags {"LightMode" = "ForwardBase"}
       
            CGPROGRAM
​
        #pragma vertex vert
        #pragma fragment frag
        #include "Lighting.cginc"
​
        fixed4 _Diffuse;
        fixed4 _Specular;
            float _Gloss;
​
            struct a2v {
                float4 vertex :POSITION;
                float3 normal :NORMAL;
​
        };
            struct v2f {
                float4 pos : SV_POSITION;
                fixed3 color : COLOR;
            };
​
            v2f vert(a2v v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
​
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
​
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
​
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
​
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
​
                fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
​
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
​
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
​
                o.color = ambient + diffuse + specular;
​
                return o;
                
            }
​
            fixed4 frag(v2f i) : SV_Target{
                return fixed4(i.color,1.0);
            }
                ENDCG
    }
    }
        Fallback"Specular"
}
​

逐像素光照

// Upgrade NOTE: replaced 'Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced 'World2Object' with 'unity_WorldToObject'

Shader "Custom/2" { properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color) = (1,1,1,1) _Gloss("Gloss",Range(8.0,256)) = 20 }

        subshader{
        pass {
        Tags {"LightMode" = "ForwardBase"}
​
            CGPROGRAM
​
        #pragma vertex vert
        #pragma fragment frag
        #include "Lighting.cginc"
​
        fixed4 _Diffuse;
        fixed4 _Specular;
            float _Gloss;
​
            struct a2v {
                float4 vertex :POSITION;
                float3 normal :NORMAL;
​
        };
            struct v2f {
                float4 pos : SV_POSITION;
                float3 worldNormal :TEXCOORD0;
                float3 worldPos : TEXCOOD1;
            };
​
            v2f vert(a2v v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
​
                o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
​
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
​
                return o;
            }
​
            fixed4 frag(v2f i) : SV_Target{
                
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
​
                fixed3 worldNormal = normalize(i.worldNormal);
​
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
​
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
​
                fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
​
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
​
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
​
                return fixed4 (ambient + diffuse + specular,1.0) ;
            }
                ENDCG
    }
    }
        Fallback"Specular"
}

blinn phong光照模型

 

2.6.6 使用Unity内置函数

内置函数:

float3 WorldSpaceViewDir(float4 v):输入模型空间中顶点的位置,返回世界空间该点到摄像机观察的方向

float3 UnityWorldSpaceViewDir(float4 v):输入世界空间顶点位置,返回世界空间该点到摄像机观察的方向

float3 ObjSpaceViewDir(float4 v):输入模型空间顶点位置,返回模型空间该点到摄像机观察的方向

float3 WorldSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入模型空间顶点位置,返回世界空间该点到光源的方向(没有归一化)

float3 UnityWorldSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入世界空间顶点位置,返回世界空间该点到光源的方向(没有归一化)

float3 ObjSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入模型空间顶点位置,返回模型空间该点到光源的方向(没有归一化)

float3 UnityObjectToWorldNormal:(float3 norma):把法线方向从模型空间转换到世界空间当中

float3 UnityObjectToWorldDir:(float3 dir):把方向矢量从模型空间转换到世界空间当中

float3 UnityWorldToObjectDir:(float3 dir):把方向矢量从世界空间转换到模型空间当中

2.7 基础纹理

纹理的含义就是我们希望用一张图片来贴在物体表面,逐纹素控制模型的颜色

利用纹理展开技术来把纹理坐标存储在每一个点上,纹理映坐标定义了该顶点在纹理中对应的2

d坐标(u,v)通常把纹理坐标称其为UV坐标,通常我们都会归一化纹理映射坐标,但不归一化有时十分好用,后续章节会详细讨论

2.7.1 单张纹理

使用blinn phong模型来计算光照

 

 

 

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
​
Shader "Custom/Chapter7"
{
    Properties
    {
        _Color("Color Tint",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(8.0,256)) = 20
        _MainTex("MainTex",2D) = "white"{}
    }
    SubShader
    {
        Pass{
            Tags{"LightMode"="ForwardBase"}
             CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag 
        #include "Lighting.cginc"
​
        fixed4 _Color;
        sampler2D _MainTex;
        float4 _MainTex_ST;
        fixed4 _Specular;
        float4 _Gloss;
​
        struct a2v{
        float4 vertex : POSITION;
        float3 normal : NORMAL;
        float4 texcoord : TExCOORD0;
        };
​
        struct v2f{
        float4 pos : SV_POSITION;
        float3 worldNormal : TEXCOORD0;
        float3 worldPos : TEXCOORD1;
        float2 uv :TEXCOORD2;
        };
​
        v2f vert(a2v v){
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.worldNormal = UnityObjectToWorldNormal(v.normal);
        o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
​
        o.uv = v.texcoord.xy *_MainTex_ST.xy +_MainTex_ST.zw;
​
        return o;
        }
​
        fixed4 frag(v2f i) : SV_Target{
        fixed3 worldNormal = normalize(i.worldNormal);
        fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
​
        fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb;
        fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
        fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
        fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
        fixed3 halfDir = normalize(worldLightDir + viewDir);
        fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
 
        return fixed4(ambient+diffuse + specular, 1.0);
        }
        ENDCG
}
       
    }
    Fallback "Specular"
}
​

2.7.2 凹凸映射

使用纹理来修改模型表面的法线,让模型提供更多细节

  1. 高度纹理

    模拟表面位移,得到修改后的法线值,也称作高度映射 高度图存储强度值,表示模型表面的海拔高度:颜色越浅,向外凸起,颜色越深,向里凹。但是计算复杂

  2. 法线纹理

    直接存储表面法线,法线映射

2.7.3 渐变纹理

略(已经看完)

2.7.4 遮罩纹理

略(已经看完)

2.8 透明效果

Shader "Custom/Chapter8-AlphaBlend"
{
    Properties
    {
       _Color ("Main Tint",Color)=(1,1,1,1)
       _MainTex("Main Tex",2D)="white"{}
       _AlphaScale("Alpha Scale",Range(0,1))=1
​
    }
    SubShader
    {
​
            Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
​
            
​
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            Cull Front 
            Zwrite Off
            Blend SrcAlpha OneMinusSrcAlpha
                        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "LIghting.cginc"
​
            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;
​
            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };
​
            struct v2f
            {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                    float2 uv : TEXCOORD2;
            };      
​
            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
​
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
​
                fixed4 texColor = tex2D(_MainTex, i.uv);
                
                fixed3 albedo = texColor.rgb * _Color.rgb;
    
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                
                fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir));
​
                return fixed4(ambient + diffuse,texColor.a*_AlphaScale);
;           }
            ENDCG
        }
​
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            Cull Back
            Zwrite Off
            Blend SrcAlpha OneMinusSrcAlpha
                        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "LIghting.cginc"
​
            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;
​
            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };
​
            struct v2f
            {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                    float2 uv : TEXCOORD2;
            };      
​
            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
​
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
​
                fixed4 texColor = tex2D(_MainTex, i.uv);
                
                fixed3 albedo = texColor.rgb * _Color.rgb;
    
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                
                fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir));
​
                return fixed4(ambient + diffuse,texColor.a*_AlphaScale);
;           }
            ENDCG
        }
    }
​
    Fallback"Transparent/Vertexlit"
​
}
​

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值