1. 程式人生 > >Unity3D學習筆記(三十五):Shader著色器(2)- 頂點片元著色器

Unity3D學習筆記(三十五):Shader著色器(2)- 頂點片元著色器

結構體 意義 float inline 有意義 pro spa ocl rcu

Alpha測試 AlphaTest Great:大於 AlphaTest Less:小於 AlphaTest Equal:等於 AlphaTest GEqual:大於等於 AlphaTest LEqual:小於等於 AlphaTest Never:全不渲染 AlphaTest Always:全部渲染 如果使用後兩項的命名的情況下,比較後的數字項沒有意義 AlphaTest 比較項 數字
AlphaTest Great 0.5 //表示只渲染alpha值大於0.5的部分
AlphaTest Less 0.5 //表示只渲染alpha值小於0.5的部分
混合命令 Blend SrcFactor DstFactor SrcFactor DstFactor 可以的取值 One表示1 Zero表示0 SrcColor當前的顏色 DstColor已經存在的顏色 SrcAlpha當前的透明度 DstAlpha已經存在的顏色的透明度 OneMinusSrcColor當前的顏色取反向 1-SrcColor OneMinusSrcAlpha當前的Alpha值取反向 1-SrcAlpha OneMinusDstColor已經存在的顏色取反向 1-DstColor OneMinusDstAlpha已經存在的顏色的透明度取反向 1-DstAlpha 最終顏色 = 新顏色 * SrcFactor + 舊顏色 * DstFactor 新顏色:即將寫入到顏色緩沖區的顏色 舊顏色:已經在顏色緩沖區的顏色 顏色運算法則(不同於向量運算法則) (r,g,b) * a = (r*a,g*a,b*a) (r,g,b) * (x,y,z) = (r*x,g*y,b*z) (r,g,b) + (x,y,z) = (r+x,g+y,b+z) A - (r,g,b) = (a-x,a-y,a-z) 例如
Blend Zero One //
僅僅顯示背景的顏色,自身的效果不會顯示 Blend One Zero //顯示貼圖的RGB顏色,即使有透明通道的部分也顯示原色,不會透過去 Blend One One //貼圖色與背景色疊加,沒有透明通道處理,結果可能更趨近於(1,1,1) Blend SrcAlpha Zero //沒有透明通道部分顯示的是貼圖的原色,有透明通道0的部分,顯示黑色,0.5部分更趨近於黑色 Blend SrcAlpha OneMinusSrcAlpha //最終顏色 = 新顏色 * 當前透明度 + 舊顏色 * (1 - 當前透明度),最常用的透明混合方式

Shader "Lesson/AlphaTest" {
    Properties {
        _Tex(
"紋理", 2D) = "white"{} _Alpha("透明度", Range(0,1)) = 0 } SubShader { Pass { //表示只渲染alpha值大於0.5的部分 AlphaTest Greater 0.5 AlphaTest Greater [_Alpha] //Blend SrcAlpha OneMinusSrcAlpha Blend SrcAlpha zero SetTexture[_Tex] { Combine texture } } } FallBack
"Diffuse" }
Cg語言,詳見PPT 頂點/片元著色器 核心: 頂點函數: 片元函數: 頂點函數在幾何階段,能從應用程序獲取頂點信息。這些信息就是通過頂點函數的參數傳遞進來的。頂點函數的返回值就是傳遞到片元函數裏的,片元函數也是通過參數去接收的 Float4 vertex:頂點坐標(模型空間下) Float4 normal:頂點的法線向量 Float4 tangent:頂點的切線向量 Float4 texcoord:第一UV顏色 Float4 texcoord1:第二UV顏色 Float4 color:頂點顏色 語義:語句的含義 頂點函數的形參後跟的語義:表示該形參的是接收應用程序傳遞來的是什麽。 對於頂點函數的方法後跟的語義:修飾的返回值,代表該返回值表示的是什麽。 對於片元函數的方法後跟的語義:修飾的是片元函數的返回值,代表的是告訴應該GPU是什麽 從應用程序階段到頂點函數階段 1.POSITION:表示應用程序把頂點坐標傳遞過來並且存儲在修飾的參數 2.NORMAL:表示法線,通常是float3 3TANGENT:表示切線 4.TEXCOORD0-N:從第1套UV到第7套UV 5.COLOR:頂點顏色 從頂點函數到片元函數能表示的語義 1.SV_POSITION:代表轉換之後的齊次空間坐標 2.COLOR0:代表一組顏色 2.COLOR1:代表一組顏色 4.TEXCOORD0-N:從第1套UV到第7套UV 從片元函數輸出的語義 SV_Target:輸出的值會渲染到屏幕上
// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,*)‘ with ‘UnityObjectToClipPos(*)‘
Shader "Lesson/VFColor" {
    Properties {
        _Color("顏色", Color) = (1,0,0,1)
    }
    SubShader {
       
        //1.頂點片元程序也要寫在Pass塊裏
        Pass
        {
            //2.把Cg語言的開始和結束寫出來
            //表示Cg語言程序的開始
            CGPROGRAM
            //3.定義頂點函數和片元函數的名字
            //#pragma 不變 vertex 關鍵字,後跟的是頂點函數的名字,vert頂點函數的名字
            #pragma vertex vert //定義函數名為vert的函數為頂點函數
            //#pragma 不變 fragment 關鍵字
            #pragma fragment frag //定義函數名為frag的函數為片元函數
            fixed4 _Color;//如果要在Cg語言中去使用屬性面板定義的一些變量,需要在Cg語言中進行重定義
            //4.實現頂點函數
            //POSITION修飾的是頂點函數參數vet,證明vet是頂點坐標
            //SV_POSITION修飾的是vet函數的返回值,證明返回值是轉換之後的坐標
            float4 vert(float4 vet : POSITION, float3 normal : NORMAL) : SV_POSITION
            {
                //頂點函數的核心作用必須做的是空間坐標轉換
                //mul是Cg語言的提供的API,計算向量與矩陣相乘
                float4 position = UnityObjectToClipPos(vet); //
                return position;
            }
            //5.實現片元函數
            fixed4 frag() : SV_Target
            {
                //最重要的必須的做到就是返回一個顏色
                return _Color;
            }
            //表示Cg語言程序的結束
            ENDCG
        }
    }
    FallBack "Diffuse"
}
Unity\Editor\Data\CGIncludes\UnityShaderUtilities.cginc裏的UnityObjectToClipPos()函數 UnityCG.cginc常用的API
#ifndef UNITY_SHADER_UTILITIES_INCLUDED
#define UNITY_SHADER_UTILITIES_INCLUDED
// This file is always included in all unity shaders.
#include "UnityShaderVariables.cginc"
// Tranforms position from object to homogenous space
inline float4 UnityObjectToClipPos(in float3 pos)
{
    // More efficient than computing M*VP matrix product
    return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0)));
}
inline float4 UnityObjectToClipPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders
{
    return UnityObjectToClipPos(pos.xyz);
}
#endif
UNITY_MATRIX_MVP的MVP是幾何階段的三次轉變 M模型到世界 V世界到觀察 P觀察到剪裁 技術分享圖片
// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,*)‘ with ‘UnityObjectToClipPos(*)‘
Shader "Lesson/VFNormal" {
    Properties {
    }
    SubShader {       
        Pass
        {
            CGPROGRAM
           
            #pragma vertex vert
            #pragma fragment frag
            //定義一個結構體,作為頂點函數的參數
            struct m2v
            {
                float4 vex : POSITION;//告訴應用程序把模型空間下的頂點坐標放在這
                float3 normal : NORMAL;//告訴應用程序把模型空間下的法線放在這
                float3 tangent : TANGENT;//告訴應用程序把模型空間下的切線放在這
            };
            //定義一個結構體,作為頂點函數的返回值和片元函數的參數
            struct v2f
            {
                float4 position : SV_POSITION;//轉換之後的頂點坐標
                float3 normal : COLOR0;//法線
                float3 tangent : COLOR1;//切線
            };
            //結構體作為參數和返回值
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex); //必須變換頂點坐標
                f.normal = v.normal;//法線賦值
                f.normal = mul(UNITY_MATRIX_M, v.normal);
                //f.tangent = v.tangent;//切線賦值
                return f;
            }
            fixed4 frag(v2f f) : SV_Target
            {
                return fixed4(f.normal.x, f.normal.y, f.normal.z, 1);//把法線作為顏色輸出
                //return fixed4(f.tangent.x, f.tangent.y, f.tangent.z, 1);//把切線作為顏色輸出
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

UV坐標,可以通過頂點的UV坐標去獲取紋理對應的顏色。對於圖片的紋理來說UV的(0,0)點在左下角,UV的(1,1)點在右上角

// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,*)‘ with ‘UnityObjectToClipPos(*)‘
Shader "Lesson/VFTexture" {
    Properties{
            //定義一個圖片
            _MainTex("紋理", 2D) = "white"{}
        }
    SubShader{
        //透明的紋理處理要把渲染隊列調高
        Tags{ "Queue" = "Transparent" }
        Pass
        {
            //Cull off
            //處理帶有透明通道貼圖的混合
            Blend SrcAlpha OneMinusSrcAlpha
       
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //重定義紋理
            sampler2D _MainTex;
       
            //定義結構體,作為頂點函數的參數
            struct m2v
            {
                float4 vex : POSITION;
                float2 uv : TEXCOORD0;//告訴應用程序要UV信息
            };
           
            //定義一個結構體,作為頂點函數的返回值和片元函數的參數
            struct v2f
            {
                float4 position : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
                   
            v2f vert(m2v v)
            {
                v2f f;
                //轉換頂點坐標
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
               
            fixed4 frag(v2f f) : SV_Target
            {
                //通過頂點的uv坐標去訪問紋理對應的顏色
                fixed4 color = tex2D(_MainTex, f.uv);
            //return fixed4(f.uv.x,f.uv.y, 0, 1);
            return color;
            }
        ENDCG
        }
    }
    FallBack "Diffuse"
}
屬性面板的變量,如果想在Cg程序中去使用,必須在Cg程序中重新定義: Color - fixed4或float4 Vector - float4 Float - float Range - float 2D - sampler2D Rect - samplerRect Cube - samplerCube 裁剪可以做場景切換的幕布效果 技術分享圖片
// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,*)‘ with ‘UnityObjectToClipPos(*)‘
Shader "Lesson/VFDiscard" {
    Properties{
        _MainTex("紋理", 2D) = "white"{}
        _Radius("半徑", Range(0, 0.75)) = 0
    }
    SubShader{
        Pass
        {
            CGPROGRAM
           
            #pragma vertex vert
            #pragma fragment frag
           
            sampler2D _MainTex;
            float _Radius;
           
            struct m2v
            {
                float4 vex : POSITION;
                float2 uv : TEXCOORD0;
            };
           
            struct v2f
            {
                float4 position : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
           
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
           
            fixed4 frag(v2f f) : SV_Target
            {
                //discard;//裁剪命令
                fixed4 color = tex2D(_MainTex, f.uv);
           
                //0.2圓的半徑
                //圓心是0.5 0.5
                float2 current = f.uv;
                float2 center = float2(0.5, 0.5);
               
                float dis = pow((current.x - center.x), 2) + pow((current.y - center.y), 2);
           
                if (dis < pow(_Radius, 2))
                {
                    //在圓內
                    discard;
                }
               
                return color;
            }
        ENDCG
        }
    }
        FallBack "Diffuse"
}
Emission,類似RawImage的UV Rect ----Tiling:圖片的左右偏移 ----Offset:圖片的大小比例 練習 - 實現西瓜的效果 技術分享圖片
Shader "Lesson/VFWatermelon" {
    Properties {
        _LightColor("淺色條紋", Color) = (1,1,1,1)
        _DarkColor("深色條紋", Color) = (1,1,1,1)
        _Number("深色條紋數量", int) = 3
        _Width("深色條紋寬度", Range(0.01, 0.2)) = 0.02
    }
    SubShader{
        Pass
        {
            CGPROGRAM
                  
            fixed4 _LightColor;
            fixed4 _DarkColor;
            int _Number;
            float _Width;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
           
            struct m2v
            {
                float4 vex : POSITION;
                float3 uv : TEXCOORD0;
            };
           
            struct v2f
            {
                float4 position : SV_POSITION;
                float3 uv : TEXCOORD0;
            };
           
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
           
            fixed4 frag(v2f f) : SV_Target
            {
                //實現1
                //淺色條紋的寬度
                float width = 1.0 / _Number - _Width;
                for (int i = 0; i < _Number; i++)
                {
                    if (f.uv.x > i * (width + _Width) && f.uv.x < width + i * (width + _Width))
                    {
                        return _DarkColor;
                    }
                }
                return _LightColor;
                /*
                //實現2
                //每對條紋的寬度(1深1淺)
                float wid = 1.0 / _Number;
                float x = fmod(f.uv.x, wid); //對wid取模(余)
                if (x < _Width)
                {
                    return _DarkColor;
                }
                return _LightColor;
                */
            }
       
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Unity3D學習筆記(三十五):Shader著色器(2)- 頂點片元著色器