找回密码
 立即注册
查看: 327|回复: 0

[简易教程] Notes : Unity Shader

[复制链接]
发表于 2022-10-17 11:52 | 显示全部楼层 |阅读模式
【教程】Unity Shader系列教程  (广东话版Cantonese)_哔哩哔哩_bilibili
<hr/>#001- Intro

reference


  • Cg_language
  • CgTutorial



rengdering API / shading language

recommend setting:




大部分操作都在右边三个窗口,project窗口可调整为单排

项目设置部分:



meta文件存储着组件的各种设置



这样便于用文本查看文件修改了什么设置



可以在本地找到这个 UnityCG.cginc,查看里面的 function

pixel shader




教程先讲了pixel shader 部分,也就是 fragment shader



注释方式是和C++一样的



常用的数据类型



shader的暴露参数方式



UV颜色tex coord的原理示意

tex coord


texture offset


texture rotation



旋转矩阵的公式

Shader "MyShader/001"
{
    Properties
    {
        testFloat("testFloat", range(0,360)) = 1
        testColor("testColor", Color) = (1, 1, 1, 1)
        testVec("testVec", vector) = (0, 0, 0, 0)
        testTex("testTexture", 2D) = "white" // "black"
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            // varying
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            v2f vs_main (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.color = v.color;
                o.uv = v.uv;
                return o;
            }

            // uniform
            float testFloat;
            float my_time;
            float4 testColor;
            float4 testVec;

            sampler2D testTex;

            float4 ps_main(v2f i) : SV_Target
            {
               
                //先把旋转中心点移动到想要为轴心的位置后,在最终结果再变回去
                float x = i.uv.x - 0.5;
                float y = i.uv.y - 0.5;
               
                //float r = testFloat / 360.0 * 2 * 3.1416;
                float r = radians(testFloat);

                float a = cos(r);
                float b = -sin(r);
                float c = sin(r);
                float d = cos(r);

                float nx = a * x + b * y + 0.5;
                float ny = c * x + d * y + 0.5;

                //float4 o = tex2D(testTex, float2(nx, ny));
               
                //--- calc by matrix

                float2x2 rotateMat = float2x2(cos(r), -sin(r),
                    sin(r), cos(r));

                float2 uv = mul(rotateMat, i.uv - 0.5) + 0.5;

                // ------------
                float4 o = tex2D(testTex, uv);
                return o;
            }
            ENDCG
        }
    }
}

<hr/>#002 Testure Effect

doc : Accessing shader properties in Cg/HLSL


暴露材质纹理的tilling和offset参数 :



Shader "MyShader/002"
{
    Properties
    {
        testTex("testTexture", 2D) = "white" // "black"
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            // varying
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            v2f vs_main (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.color = v.color;
                o.uv = v.uv;
                return o;
            }

            sampler2D testTex;
            float4    testTex_ST;
            //OpenGL的3Dtexture coordinate用RST,等同于Maya用UVW,或XYZ

            float4 ps_main(v2f i) : SV_Target
            {
                float2 tiling = testTex_ST.xy;
                float2 offset = testTex_ST.zw;
               
                float4 o = tex2D(testTex, i.uv * tiling + offset);
                return o;
            }
            ENDCG
        }
    }
}
色相分离




UV offset per channel

Shader "MyShader/002 - Tex Effects"
{
    Properties
    {
        testFloat("testFloat", range(0,0.1)) = 0
        testTex("testTexture", 2D) = "white" // "black"
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            // vertex shader
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            v2f vs_main (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.color = v.color;
                o.uv = v.uv;
                return o;
            }
            
            //pixel shader
            sampler2D testTex;
            float4    testTex_ST;

            float     testFloat;

            float4 ps_main(v2f i) : SV_Target
            {
                float4 o ;
                o.r = tex2D(testTex, i.uv - float2(testFloat, 0)).r;
                o.g = tex2D(testTex, i.uv).g;
                o.b = tex2D(testTex, i.uv - float2(testFloat, 0)).b;
                o.a = 1;

                return o;
            }
            ENDCG
        }
    }
}
Gray Scale

眼睛对于红绿蓝三个色的敏感度不一样, 所以用(R+G+B)/3会导致图像失真, 需要用一定的比例算出来更自然的效果.


lerp & clamp

Shader "MyShader/002 - Tex Effects"
{
    Properties
    {
        testFloat("testFloat", range(0,0.1)) = 0
        texWeight("texWeight", range(-1,1)) = 0

        testTex("testTexture", 2D) = "white"
        testTex2("testTexture2", 2D) = "white"
        testMask("testMask",2D) = "white"
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            // vertex shader
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 color  : COLOR;
                float2 uv  :  TEXCOORD0;
            };

            v2f vs_main (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.color = v.color;
                o.uv = v.uv;
                return o;
            }
            
            //pixel shader
            sampler2D testTex;
            sampler2D testTex2;
            sampler2D testMask;
            float     texWeight;

            float     testFloat;

            //gray scale
            float4 grayScale(float4 v) {
                float g = v.r * 0.299 + v.g * 0.587 + v.b * 0.114;
                return float4(g, g, g, v.a);
            }

            float4 ps_main(v2f i) : SV_Target
            {
                float4 a ;
                a.r = tex2D(testTex, i.uv - float2(testFloat, 0)).r;
                a.g = tex2D(testTex, i.uv).g;
                a.b = tex2D(testTex, i.uv - float2(testFloat, 0)).b;
                a.a = 1;

                float4 b = tex2D(testTex2, i.uv);

                float4 mask = tex2D(testMask, i.uv);

                float w = mask + texWeight;

                //if (w < 0) w = 0;
                //if (w > 0) w = 1;
                w = clamp(w, 0, 1);

                //float4 o = a * (1 - w) + b * w;
                float4 o = lerp(a, b, w);

                //o = grayScale(o);
                return o;
            }
            ENDCG
        }
    }
}
doc : Built-in shader variables
5th channel

(...突然遇到曾经面试题的答案)
一张mask有四个通道, 利用R+G+B+A=1这个特性, 可以获得第五个通道 5th channel=1-(R+G+B+A)
<hr/>#003 Culling, Depth Test, Blending, Flow Map

doc : Unity - Manual: ShaderLab: Pass
Face Culling

判断面的正反, 主要通过这个面上的点, 是顺时针绘制还是逆时针绘制的.



Depth Offset

artifact : 同一平面的两个面片会闪烁, 即使把其中一个稍向前移, 当离镜头较远时闪烁依然会出现(当然距离拉得很大能解决)
how : 在计算完物体的深度后再通过DepthOffset进行位移, 这样的话就不会造成越远精密越不够.
why : 因为在计算出一个像素的XYZ后需要除以它的深度W, 越远精细度不够误差就会比较大. 所以在shader里用 Depth Offset 会比较稳妥.





Blending

doc : ShaderLab: Blending



常见的混合类型写法, 及解释

半透明次序问题 : unity在绘制时会先将实心的物体先画, 然后再绘制半透的物体



若想要在半透物件中区分顺序, 可用+1的方式



多个透明物件用 ZWrite Off 可关闭深度写入

Flow Map

对纹理×2再-1的原因

  • 纹理在PS里面是0~255的值, 经过shader后我们把它normalize到0~1, offset是float2值域为-1~1
  • 此时纹理和offset的值域是不同的, 会导致效果出错. ( 想象颜色RG为坐标XY, 正常情况下是可以四个方向自由移动的, 但颜色0~1和位移-1~1的值域,在相乘后去掉了XY坐标中的所有负值. )
  • 需要对纹理进行×2再-1的操作, 将纹理的值域变成-1~1


SIGGRAPH 2010 - Water Flow in Portal 2 : https://cdn.cloudflare.steamstatic.com/apps/valve/2010/siggraph2010_vlachos_waterflow.pdf
Portal 2 制作方式 : 使用两层来回混合



<hr/>#004 Vertex Shader

Deformation 变换

doc : Built-in shader variables
Space
identity


transpose 形变



Vertex Normal

doc :  Normal Transformation



<hr/>#005 Basic Lighting, Toon Shading

叉积(cross product)


  • 在3维空间中建立一个直角坐标系
  • 判定左/右
  • 判定内/外
点积(dot product)


  • 计算两个方向有多么接近
  • 前与后的信息
  • compose a vector


ambient 环境光

  • 不计算间接光照
  • 注意区分 ambient occlusion : 寻找有多接近一个面, 并且多有机会被一个面挡住
diffuse 漫反射
点积 法线 和 光源 , 可以计算出表面的光滑程度, 角度越小越光滑.
specular 高光反射

  • 会受view angle影响
  • 会受观察射线和光线反弹射线的夹角影响 (上图V和R的夹角)
Shader "MyShader/005_Lighting"
{
    Properties
    {
        ambientColor("Ambient Color",Color)=(0,0,0,0)
        diffuseColor("Duffuse Color",Color)=(1,1,1,1)
        specularColor("Specular Color",Color)=(1,1,1,1)
        specularShininess("Specular Shininess",Range(1,128))=10
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            Cull Off


            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main

            #include "UnityCG.cginc"
            #define M_PI 3.14

            struct appdata
            {
                float4 pos    : POSITION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };
   
            // vertex shader
            struct v2f
            {
                float4 pos    : SV_POSITION;
                float3 wpos   : POSTION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };

            v2f vs_main(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);
                o.wpos=mul(UNITY_MATRIX_M,v.pos).xyz;
               
                o.color = v.color;
                o.uv = v.uv;
                o.normal = mul((float3x3)UNITY_MATRIX_M,v.normal);
                return o;
            }

            float4 MyLightPos;
            
            float4 ambientColor;
            float4 diffuseColor;
            float4 specularColor;
            float specularShininess;

            float4 basicLighting(float3 wpos,float3 normal)
            {
                float3 N = normalize(normal);
                float3 L = normalize(MyLightPos - wpos);//计算入射光线, 光源位置减去物体表面位置, 然后归一到单位向量
                float3 V = normalize(wpos - _WorldSpaceCameraPos);//眼睛的位置减去物体表面的位置
               
                float3 R = reflect(L,N);
                //Same as float3 R = L - dot(N,L) * 2 * N;

                float4 ambient = ambientColor;
                float4 diffuse = diffuseColor * max(0,dot(N,L));
                //基础色乘以光照, 点积法线和光源可以计算出表面的光滑程度, 角度越小越光滑.

                float specularAngle = max(0,dot(R,V));
                float4 specular = specularColor * pow(specularAngle,specularShininess);//模拟高光部分

                float4 color = 0;
                color += ambient;
                color += diffuse;
                color += specular;
               
                return color;
            }

            float4 ps_main (v2f i) : SV_Target
            {
                return basicLighting(i.wpos, i.normal);
            }
            ENDCG
        }
    }
}
unity 将不是光照的部分抽离出来让使用者自定义 : Writing Surface Shaders


Shader "MyShader/005_Toon"
{
    Properties
    {
        toonAngle0("Toon Angle 0", Range(-1,1))=-0.6
        toonColor0("Toon Color 0",Color)=(0,0,1,0)
        
        toonAngle1("Toon Angle 1", Range(-1,1))=0.5
        toonColor1("Toon Color 1",Color)=(0,1,0,0)
        
        toonAngle2("Toon Angle 2", Range(-1,1))=0.9
        toonColor2("Toon Color 2",Color)=(1,0,0,0)
        
        toonColor3("Toon Color 3",Color)=(0.2,0.2,0.2,0.2)
        
        toonOutlineWidth("Toon Outline Width",Range(0,1))=0.04
        toonOutlineColor("Toon Outline Color0",Color)=(0,0,0,0)
      
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        //outline pass
        Pass
        {
            Cull front//描边的重点就是这里,不画正面

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

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos    : POSITION;
                float3 normal : NORMAL;
            };
   
            // vertex shader
            struct v2f
            {
                float4 pos    : SV_POSITION;
            };

            float toonOutlineWidth;
            float4 toonOutlineColor;

            v2f vs_main(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);//此处的pos已经是屏幕空间的了, 所以下面位移只用了XY

                float3 N = mul ((float3x3)UNITY_MATRIX_MV,v.normal);
                float2 offset =mul((float2x2)UNITY_MATRIX_P,N.xy);//描边重点, 位移
                o.pos.xy += offset * toonOutlineWidth;
            
                return o;
            }
            
            float4 frag (v2f i) : SV_Target
            {
                return toonOutlineColor;
            }
            ENDCG
        }
        
        //color pass
        Pass
        {
            Cull Off
            
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main
            
            #include "UnityCG.cginc"
            #define M_PI 3.14

            struct appdata
            {
                float4 pos    : POSITION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };

             // vertex shader
            struct v2f
            {
                float4 pos    : SV_POSITION;
                float3 wpos   : POSTION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };

             v2f vs_main(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);
                 o.wpos=mul(UNITY_MATRIX_M,v.pos).xyz;
               
                o.color = v.color;
                o.uv = v.uv;
                o.normal = mul((float3x3)UNITY_MATRIX_M,v.normal);
                return o;
            }

            float4 MyLightPos;

            float toonAngle0;
            float4 toonColor0;

            float toonAngle1;
            float4 toonColor1;

            float toonAngle2;
            float4 toonColor2;
            
            float4 toonColor3;

            float4 toonShading(float3 pos,float3 normal)
            {
                float3 N = normalize(normal);
                float3 L = normalize(MyLightPos-pos);

                float angle = max(0,dot(N,L));

                if (angle > toonAngle2)
                    return toonColor2;

                if (angle > toonAngle1)
                    return toonColor1;

                if (angle > toonAngle0)
                    return toonColor0;

                return toonColor3;
             }

            float4 ps_main(v2f i) : SV_Target
            {
                return toonShading(i.wpos,i.normal);
            }
            ENDCG
             }
        }
    }


Shader "MyShader/005_ToonTexture"
{
    Properties
    {
        toonOutlineWidth("Toon Outline Width",Range(0,1))=0.04
        toonOutlineColor("Toon Outline Color0",Color)=(0,0,0,0)
        toonTexture("Toon Texture",2D)="white"
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            Cull front

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos    : POSITION;
                float3 normal : NORMAL;
            };
   
            // vertex shader
            struct v2f
            {
                float4 pos    : SV_POSITION;
            };

            float toonOutlineWidth;
            float4 toonOutlineColor;

            v2f vs_main(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);

                float3 N = mul ((float3x3)UNITY_MATRIX_MV,v.normal);
                float2 offset=mul((float2x2)UNITY_MATRIX_P,N.xy);
                o.pos.xy += offset * toonOutlineWidth;
            
                return o;
            }
            
            float4 frag (v2f i) : SV_Target
            {
                return toonOutlineColor;
            }
            ENDCG
        }
        
        //color pass
        pass
        {
            Cull Off
            
            CGPROGRAM
            #pragma vertex vs_main
            #pragma fragment ps_main
            
            #include "UnityCG.cginc"
            #define M_PI 3.14

            struct appdata
            {
                float4 pos    : POSITION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };

             // vertex shader
            struct v2f
            {
                float4 pos    : SV_POSITION;
                float3 wpos   : POSTION;
                float4 color  : COLOR;
                float2 uv     : TEXCOORD0;
                float3 normal : NORMAL;
            };

             v2f vs_main(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);
                 o.wpos=mul(UNITY_MATRIX_M,v.pos).xyz;
               
                o.color = v.color;
                o.uv = v.uv;
                o.normal = mul((float3x3)UNITY_MATRIX_M,v.normal);
                return o;
            }

            float4 MyLightPos;
            sampler2D toonTexture;

            float4 toonShading(float3 pos,float3 normal)
            {
                float3 N = normalize(normal);
                float3 L = normalize(MyLightPos-pos);
                float angle = max(0,dot(N,L)*0.5+0.5);

                return tex2D(toonTexture,float2(0.5,angle));
             }

            float4 ps_main(v2f i) : SV_Target
            {
                return toonShading(i.wpos,i.normal);
            }
            ENDCG
             }
        }
    }


<hr/>#006 MatCap,Normal Map,Deferred Shading

MatCap : material capture



非常节省性能, 看背面物体的话会有些许问题( 适合相对固定视角的物件 )


Shader "MyShader/006_MatCap"
{
    Properties
    {
        matCapTex("MatCap Texture", 2D)="black"
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            //定义了 program / unity 送到 vertex shader 里面有什么
            struct appdata
            {
                float4 pos    : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };
   
            // 定义了 vertex shader 送到 pixel shader 有什么
            struct v2f
            {
                float4 pos    : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;

                float3 viewDir : TEXCOORD4; //texture coordinate相较于color会更加精确
                float3 viewNormal : TEXCOORD5;
            };

           sampler2D matCapTex;

            v2f vert(appdata v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.pos);
                o.uv = v.uv;
                o.normal = v.normal;

                o.viewDir = normalize(mul( UNITY_MATRIX_MV, v.pos));
                o.viewNormal = mul((float3x3)UNITY_MATRIX_MV, v.normal);
            
                return o;
            }

            float4 matCap(float3 viewNormal, float3 viewDir)
            {
                float3 N = normalize(viewNormal);
                float3 V = normalize(viewDir);

                N -= V * dot(V,N);
                float2 uv = N.xy * 0.5 * 0.99 + 0.5;
                // × 0.5 + 0.5 : 将法线的 -1 ~1的阈值变为 0~1
                // ×0.99 是为了避免纹理的边缘是烂边, 避免得到不好的效果

                return tex2D(matCapTex, uv);
            }

            // pixel shader
            float4 frag (v2f i) : SV_Target
            {
                float4 o = 0;
                o += matCap(i.viewNormal, i.viewDir);

                return o;
            }
            ENDCG
             }
        }
    }
Normal Map


  • 通过法线来制造假的深度和反射
  • 进阶版本是 Parallax Mapping


Shader "MyShader/006_NormalMap"
{
    Properties
    {
        ambientColor("Ambient Color", Color) = (0,0,0,0)
        diffuseColor("Diffus Color", Color) = (1,1,1,1)
        specularColor("Specular Color", Color) = (1,1,1,1)
        specularShininess("Specular Shininess", Range(0,128)) = 10
        
        diffuseMap("Diffuse Map",2D)="white"
        specularMap("Specular Map",2D)="white"
        normalMap("Normal Map",2D)="white"
        
        uvRepeat("UV Repeat",Vector)=(1,1,1,1)
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            //定义了 program / unity 送到 vertex shader 里面有什么
            struct appdata
            {
                float4 pos    : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 uv : TEXCOORD0;
            };
   
            // 定义了 vertex shader 送到 pixel shader 有什么
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                float4 pos    : SV_POSITION;
                float4 color : COLOR;
               
                float3 worldSpaceNormal : TEXCOORD5;
                float3 worldSpaceTangent : TEXCOORD6;
                float3 worldSpacePos : TEXCOORD7;
            };

            float4 MyLightPos;
            float4 ambientColor;
            float4 diffuseColor;
            float4 specularColor;
            float specularShininess;
        
            sampler2D diffuseMap;
            sampler2D specularMap;
            sampler2D normalMap;
        
            float4 uvRepeat;

            float4 basicLighting(float3 pos, float3 normal, float3 tangent, float2 uv)
            {
                float3 N = normalize(normal);
                float3 L = normalize(MyLightPos-pos);//计算入射光线, 光源位置减去物体表面位置, 然后归一到单位向量
                float3 V = normalize(pos - _WorldSpaceCameraPos);//眼睛的位置减去物体表面的位置

                float3 T = normalize(tangent);//如果左右的法线都是有倾斜角度的, 中间计算出来的法线有可能会短一截, 所以需要归一到单位长度
                float3x3 TBN = float3x3(T, cross(N,T),N);//通过 normal和 tangent叉积出来 binormal
                //TBN = transpose(TBN);

                //normal map
                N = tex2D(normalMap, uv).xyz *2 - 1;// 0..1 -> -1..1
                N.y = -N.y;

                N = mul(TBN,N);//tangent space  -> world space TBN是刚刚计算出来的切线空间的一个3×3的数组

                float3 R = reflect(L,N);

                float4 ambient = ambientColor;
                float4 diffuse = diffuseColor * tex2D(diffuseMap,uv) * dot(N,L);
                float specularAngle = max(0,dot(R,V));
                float4 specular = specularColor * tex2D(specularMap,uv)* pow(specularAngle,specularShininess);

                float4 color = 0;
                color += ambient;
                color += diffuse;
                color += specular;
               
                return color;
            }

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.uv = v.uv * uvRepeat.xy;
                o.normal = v.normal;
                o.color = 1;

                o.worldSpacePos = mul(UNITY_MATRIX_M, v.pos).xyz;
                o.worldSpaceNormal = mul((float3x3)UNITY_MATRIX_M, v.normal);//normal has no translation,that's why
                o.worldSpaceTangent = mul((float3x3)UNITY_MATRIX_M,v.tangent.xyz);

                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                float4 o = i.color;
                o = basicLighting(i.worldSpacePos, i.worldSpaceNormal, i.worldSpaceTangent, i.uv);
                return o;
            }
            ENDCG
             }
        }
    }

  • NormalMap 的 alpha 通道可以用来储存 specular 信息
  • NormalMap 的 B 通道可以通过 RG 通道算出, 所以B通道也可以用来存储别的信息


Defered Rendering


  • G - Buffer : geometry buffer
  • GPU 的 MRT ( multiple render target )
  • 简单来说是把光照放在后面做, 以节省每个物件都要做一次光照的计算
  • 但是无法处理透明物体, 透明物体需要用 forward rendering 来做
PBR

pixel(2D) 和 voxel(3D)
<hr/>#007 Post Processing, Blur, Bloom

Doc : MonoBehaviour.OnRenderImage(RenderTexture,RenderTexture)



可自定义每个脚本运行的次序

挂在相机上的脚本


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ex007_GrayScale_Camera : MonoBehaviour
{
    public Material grayScaleMat;

    private void OnRenderImage(RenderTexture src, RenderTexture dst)
    {
        if (!grayScaleMat)
            return;
        Graphics.Blit(src, dst, grayScaleMat);
    }
}
去色shader


Shader "MyShader/Ex007_GrayScale"
{
    Properties
    {
        _MainTex("Base(RGB)",2D)="white"{}
        intensity("intensity", Range(0,1)) = 1
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Cull off
        ZTest Always
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            //定义了 program / unity 送到 vertex shader 里面有什么
            struct appdata
            {
                float4 pos    : POSITION;
                float2 uv : TEXCOORD0;
            };
   
            // 定义了 vertex shader 送到 pixel shader 有什么
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos    : SV_POSITION;
            };
            
            float intensity;
            sampler2D _MainTex;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.uv = v.uv;
                return o;
            }

            float4 grayScale(float4 v)
            {
                float g = v.r * 0.299 + v.g * 0.587 + v.b *0.114;
                return float4(g,g,g,v.a);
            }
            
            float4 frag (v2f i) : SV_Target
            {
                float4 c = tex2D(_MainTex, i.uv);
                return lerp(c,grayScale(c),intensity);
            }
            ENDCG
             }
        }
    }
静态画面扰动shader


Shader "MyShader/Ex007_Distortion"
{
    Properties
    {
        _MainTex ("Base(RGB)",2D)="white"{}
        intensity("intensity", Range(0,1)) = 1
        FlowMap  ("FlowMap", 2D) = "black"
    }
   
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Cull off
        ZTest Always
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            //定义了 program / unity 送到 vertex shader 里面有什么
            struct appdata
            {
                float4 pos    : POSITION;
                float2 uv : TEXCOORD0;
            };
   
            // 定义了 vertex shader 送到 pixel shader 有什么
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos    : SV_POSITION;
            };
            
            float intensity;
            sampler2D _MainTex;
            sampler2D FlowMap;
            float4 FlowMap_ST;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.pos);
                o.uv = v.uv;
                return o;
            }
            
            float4 frag (v2f i) : SV_Target
            {
                float4 flow = tex2D(FlowMap, i.uv * FlowMap_ST.xy + FlowMap_ST.zw) * 2 -1;

                float4 c = tex2D(_MainTex, i.uv + flow * intensity);
                return c;
            }
            ENDCG
             }
        }
    }

to be continue
0:10:20

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-27 12:20 , Processed in 0.110147 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表