小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Unity Shader 基礎(chǔ)教程

 taotao_2016 2020-05-24

在Github上看到一篇關(guān)于Unity-Shader的教程,感覺還不錯,作者寫的很好,很適合Unity-Shader的基礎(chǔ)入門,我在這里翻譯一下,分享給大家,英文水平很爛,大致能明白Unity-Shader是什么,渲染管線的工作流程,以及Unity Shader的一些類型和怎樣編寫Unity Shader。

原文鏈接

第一部分:什么是Shader?

Shader是計算機圖形渲染管線的一部分,它是一小段應(yīng)用程序,告訴計算機在場景中怎樣對物體渲染和著色。這個過程包括計算顏色和光照值,并將其給予對象,以至于對象被顯示在屏幕上。和上面一樣,Shader也被用來創(chuàng)建游戲中的一些特殊的和后期處理效果。

在現(xiàn)代游戲引擎中(包括Unity),Shader運行在可編程的GPU渲染管道中,在GPU中允許并行運行,并且能夠很快速的進行許多著色計算。

第二部分:渲染管道

為了學(xué)習(xí)Shader,我們將簡單的了解渲染管道,我們將在本教程中討論下面這張圖片:

image

我更加傾向把Shader看做是由一種信息類型(模型數(shù)據(jù)、顏色等等)到另外一種信息類型(像素/片元)的變換,對象數(shù)據(jù)繼承與對象本身,例如模型中的點、法線、三角形、UV坐標(biāo)等等。我們可以把自定義數(shù)據(jù)/傳遞到shader中使用,顏色、紋理、數(shù)字等等這些。

著色器流水線的第一步是頂點函數(shù)。正如你所知的,頂點就是一些點。頂點函數(shù)將處理模型中的一些點(連同其它的一些數(shù)據(jù)諸如法線)并將它們渲染流水線的下一個階段,片元函數(shù)。

片元函數(shù)將使用這些頂點,并對它們著色。將它想象為一個畫家和他們的畫筆,它最終以(R,G,B,A)的格式輸出像素數(shù)據(jù)。

最后,將像素添加到幀緩沖中,在幀緩沖中這些數(shù)據(jù)有可能被進一步處理,直到這些數(shù)據(jù)被繪制到屏幕上。

第三部分:Scene 配置

在開始寫Shader代碼之前,需要在Unity中配置一下我們的場景。在Unity中創(chuàng)建一個工程,并導(dǎo)入所有的資源。

  • Bowl Model(碗模型)

  • Noise Texture(噪聲紋理)

  • Bowl texture(碗模型紋理)

在新場景中添加一個Cube、Sphere和Bowl Model(碗模型),并保存場景,之后,你的場景將向下面這樣:

image

接下來,在Project視圖中單擊右鍵(或者點擊Create)并添加一個新的Unlit Shader(無光照著色器),將其命名為Tutorial_Shader.

如果你對其它類型的shaders好奇的話,我會在文章的末尾談?wù)撍?/p>

image

然后在剛才創(chuàng)建的shader上點擊右鍵Create>Material 創(chuàng)建一個材質(zhì)球,Unity將自動創(chuàng)建一個材質(zhì)球并使用剛才創(chuàng)建的著色器的名字。

Note:一個“Material”在Unity中僅僅是著色器的一個實例,它僅保存自定義數(shù)據(jù)/屬性的值。

image

最后,通過單擊或者拖動的方式將材質(zhì)賦予我們在場景中創(chuàng)建的所有對象上。

之后場景中的每個對象看起來是這樣的,白色,并且沒有陰影或者shading:

image

第四部分:一個Unlit Shader(無光照著色器)的大致骨架

終于到了開始寫我們自己的shader的時候了,在寫之前,首先打開之前創(chuàng)建的Tutorial_Shader文件,你將看到Unity自動生成了一些代碼供我們使用。為了繼續(xù)本教程,刪除所有代碼并使文件變空白。

Note:所有的shader在Unity中使用的是一種被稱為shaderlab的語言寫的。Shadrlab是HLSL/CG語法的包裝器,為了使Unity能夠跨平臺編譯Shader代碼并且在Inspector面板中暴露一些屬性結(jié)點。

我們將添加一些初始代碼,如下:

Shader "Unlit/Tutorial_Shader"{
    ...
}

這行代碼的作用是指定著色器代碼存放在什么位置。雙引號中的字符串告訴Unity在哪里查找Shader.

例如:

Shader "A/B/C/D/E_Shader"{
    ...
}

image

如果你保存你的shader代碼,并切回到Unity中,你將注意到所有使用這個材質(zhì)的對象都已經(jīng)變成了粉紅色。

當(dāng)你的著色器中有錯誤時,Unity中將調(diào)用FallBack著色器,你將會得到一個粉紅色的物體。你可以在Project中點擊shader文件查看相應(yīng)的錯誤。目前,我們得到一個粉紅色的物體,因為我們的shader文件還沒有完成。

接下來是屬性塊,如下:

Shader "Unlit/Tutorial_Shader"{
    Properties{
        ...
    }
}

在屬性塊中,我們可以傳遞一些自定義數(shù)據(jù)。我們在這里聲明的數(shù)據(jù)將被顯示在Unity Editor面板中,在Editor中更改也會驅(qū)動腳本更改。

Shader "Unlit/Tutorial_Shader"{
    Properties{
        ...
    }
    SubShader{
        ...
    }
}

每一個shader有一個或者多個subshaders,如果你的應(yīng)用將被部署到多種平臺(移動、PC、主機),添加多個Subshader是非常有用的。例如:你可能想要寫為PC/Desktop寫一個高質(zhì)量的Subshader,為移動端寫一個低質(zhì)量,但速度更快的Subshader.

pass語句塊:

Shader "Unlit/Tutorial_Shader"{
    Properties{
        ...
    }
    Subshader{
        Pass{
            ...
        }
    }
}

每個Subshader至少有一個pass語句塊,它實際上是對象渲染的位置。一些特效要求有多個pass語句塊,目前,我們僅僅專注于一個。

在pass語句塊中,是一些實際渲染的代碼:

Shader "Unlit/Tutorial_Shader"{
    Properties{
        
    }
    Sunshader{
        pass{
            CGPROGRAM
                ...
            ENDCG
        }
    }
}

我們實際寫的所有Shader代碼都在CGPROGRAM和ENDCG中,對于Unity來說,shaderlab是HLSL和CG的變體。

下面,我們需要告訴Unity,頂點函數(shù)和片元函數(shù)是什么:

CGPROGRAM
    #pragma vertex vertexFunction
    #pragma fragment fragmentFunction
ENDCG

這里,我們將vertex函數(shù)聲明為vertexFunction,fragment函數(shù)聲明為fragmentFunction.

我們也將定義這些函數(shù):

CGPROGRAM 
    #pragma vertex vertexFunction
    #pragma fragment fragmentFunction
    
    void vertexFunction(){
        
    }
    void fragmentFunction(){
        
    }
ENDCG

在開始著色之前,我們需要設(shè)置一些數(shù)據(jù)結(jié)構(gòu)和兩個函數(shù),這樣,我們就可以使用Unity給定的數(shù)據(jù),并把數(shù)據(jù)返回到Unity中。首先,添加UnityCG.cginc語句塊,我們可以使用這個文件中包含的一些助手函數(shù)。

我們將添加一個數(shù)據(jù)結(jié)構(gòu)a2v(此處和原文不一致),并修改頂點函數(shù),將a2v作為參數(shù)傳遞給頂點函數(shù)。

CGPROGRAM
    #pragma vertex vertexFunction
    #pragma fragment fragmentFunction
    
    #include "UnityCG.cginc"
    
    struct a2v{
        
    };
    void vertexFunction(a2v v){
        
    }
    void fragmentFunction(){
        
    }
ENDCG

當(dāng)傳遞一個參數(shù)到vertexFunction中時,Unity將解析這個函數(shù)的結(jié)構(gòu),并基于正在繪制的對象模型傳遞值。我們可以傳遞一些自定義的數(shù)據(jù),如下面聲明的那樣:

[type] [name] :[semantic]

例如,可以要求Unity獲取模型對象的頂點坐標(biāo),如下:

flot4 vertex:POSITION;

我們也可以從Unity中獲取頂點坐標(biāo)和UV紋理坐標(biāo),如下:

struct a2v{
    float4 vertex:POSITION;
    float2 uv:TEXCOORD0;
}

最后配置頂點函數(shù),創(chuàng)建一個結(jié)構(gòu)體,并將其命名v2f(代表從vertex to fragment,頂點數(shù)據(jù)傳遞到片元),將vertex中包含的數(shù)據(jù)傳遞到片元函數(shù),同時確保vertexFunction 返回 v2f的數(shù)據(jù)類型,在我們使用它時,創(chuàng)建并返回一個空白數(shù)據(jù)。

CGPROGRAM
    #pragma vertex vertexFunction
    #pragma fragment fragmentFunction
    #include "UnityCG.cginc"
    
    struct a2v{
        float4 vertex:POSITION;
        float2 uv:TEXCOORD0;
    };
    struct v2f{
        
    };
    v2f vertexFunction(a2v v){
        v2f o;
        return o;
    }
    void fragmentFunction(){
        
    }

ENDCG

像之前一樣,我們可以在v2f結(jié)構(gòu)體中定義一些數(shù)據(jù),我們可能想要把這些數(shù)據(jù)從頂點函數(shù)傳遞到片元函數(shù)。

struct v2f{
    float4 position:SV_POSITION;
    float2 uv:TEXCOORD0;
}

如果你對SV_POSITION和POSITION 感到好奇,SV代表“system value”,在v2f結(jié)構(gòu)中表示最終渲染的頂點的位置。

現(xiàn)在基本準(zhǔn)備好了,我們僅僅需要編輯片元函數(shù),使它接受一個v2f結(jié)構(gòu)并返回一個fixed4的值。

fixed4 fragmentFunction(v2f i){
    
}

輸出的片元函數(shù)將是一個有(R,G,B,A)代表的顏色值

最后,我們將為片元函數(shù)添加一個SV_TARGET的輸出語義,如下:

fixed4 fragmentFunction(v2f i):SV_TARGET{
    
}

這個過程告訴Unity我們將輸出一個color去渲染,現(xiàn)在準(zhǔn)備開始實際的編碼了,肉和土豆使我們的vertex和fragment函數(shù),到這個點,大致的骨架已經(jīng)出來了

Shader "Unlit/Tutorial_Shader"{
    Properties{
        
    }
    Subshader{
        Pass{
            CGPROGRAM
            #pragma vertex vertexFunction
            #pragma fragment fragmentFunction
            #include "UnityCG.cginc"
            
            struct a2v{
                float4 vertex:POSITION;
                float2 uv:TEXCOORD0;
            };
            struct v2f{
              float4 position:SV_POSITION;
              float2 uv:TEXCOORD0;
            };
            v2f vertexFunction(a2v v){
                v2f o;
                return o;
            }
            fixed4 fragmentFunction(v2f i):SV_TARGET{
                
            }
            ENDCG
        }
    }
}

第五部分:Shader 基礎(chǔ)

首選我們要做的是獲取頂點的正確位置,使用Unity中提供的UnityObjectToClipPos()函數(shù)(這個函數(shù)的作用是將世界空間的模型坐標(biāo)轉(zhuǎn)換到裁剪空間,函數(shù)內(nèi)部封裝了實現(xiàn)頂點坐標(biāo)變換的具體細(xì)節(jié),如矩陣變換等等),如下:

v2f vertexFunction(a2v v){
    v2f o;
    o.position=UNnityObjectToClipPos(v.vertex);
    return o;
}

這個函數(shù)將在局部空間中表示的頂點,變換到渲染相機的裁剪空間。注意,我們通過設(shè)置o.position的位置來傳遞轉(zhuǎn)換的點。接下來,給片元函數(shù)一個輸出。

fixed4 fragmentFunction(v2f i):SV_TARGET{
    return fixed4(0,1,0,1);
}

現(xiàn)在,等待一會兒。保存你的shader并且返回到Unity,你將看到我們的精美的綠色的物體。如下:

image

當(dāng)然,這對你來說可能印象并不深刻,因此,讓我們繼續(xù)構(gòu)建,而不是返回一個基本的綠色,可能我們想要編輯shader使得其能返回一個我們想要的顏色,為了做到這一點,我們需要回到開始的自定義屬性。

我們可以使用如下語法添加一些屬性:

name ("display name",type)=default value

如下,我們將暴露出一個顏色值,如下:

Properties{
    _Color("Totally Rad Color",Color)=(1,1,1,1)
}

在這里定義了一個顏色供我們使用,將其稱之為_Color并且它將顯示為 “Totally Rad Color!”,在Unity面板中。我們也將給予一個默認(rèn)白色的值,現(xiàn)在保存并返回Unity,在Inspect的材質(zhì)面板中,你將看到如下:

image

在我們使用這個color之前,我們需要把它傳遞到CG代碼中,Unity會通過變量的名字進行自動綁定,如下:

CGPROGRAM
    #pragma vertex vertexFunction
	#pragma fragment fragmentFunction

	#include "UnityCG.cginc"
	
	struct a2v{
	    float4 vertex:POSITION;
	    float2 uv:TEXCOORD0;
	};
	struct v2f{
	    float4 position:SV_POSITION;
	    float2 uv:TEXCOORD0;
	};
	//從CG中獲取屬性
	float4 _Color;
	v2f vertexFunction(a2v v){
	    v2f o;
	    o.position=UnityObjectToClipPos(v.vertex);
	    return o;
	}
	fixed4 fragmentFunction(v2f i):SV_TARGET{
	    return fixed4(0,1,0,1);
	}
ENDCG

現(xiàn)在,可以在片元函數(shù)中使用_Color值了,讓它返回我們期待的顏色值,而不是返回一個綠色:

fixed4 fragmentFunction(v2f i):SV_TARGET{
    return _Color;
}   

現(xiàn)在,保存并返回到Unity中,如果你在Inspect中的Material中改變_Color的值,你應(yīng)該能看到所有對象做出了相應(yīng)的改變。

image

現(xiàn)在我們知道了如何添加屬性,讓我們嘗試添加一張標(biāo)準(zhǔn)的紋理貼圖,這里需要添加一個新的屬性給我們的紋理:

Properties{
    _Color("_Color",Color)=(1,1,1,1)
    _MainTexture("Mian Texture",2D)="white"{}
}

注意它的類型是2D,默認(rèn)給它一張白色的紋理,我們還需要獲取這個屬性在CG片段中使用它:

float4 _Color;
sampler2D _MainTexTure;

然后,需要從模型傳遞UV紋理坐標(biāo)到片元函數(shù),我們可以通過返回頂點函數(shù)并將其傳遞v2f中,如下:

v2f vertexFunction(a2v v){
    v2f o;
    o.position=UnityObjectToClipPos(v.vertex);
    o.ov=v.uv;
    return o;
}

為了能在片元函數(shù)中使用紋理的顏色,我們需要對紋理進行采樣。謝天謝地,CG中已經(jīng)有一個tex2D()函數(shù)幫我們做了一切。

fixed4 fragmentFunction(v2f i):SV_TARGET{
    return tex2D(_MainTexture,i.uv);
}

tex2D獲取我們想要采樣的紋理以及我們想要采樣的UV坐標(biāo),在這種情況下。我們提供了它的主紋理并給定模型的點,我們可以得到我們想要的顏色,最后返回的是最終的顏色?,F(xiàn)在,保存并返回到Unity 的material insepct面板中,選擇bowel紋理賦予"Main Texture"",你會發(fā)現(xiàn),模型發(fā)生了改變,尤其是碗的模型看起來尤其像一碗湯。

image

提示:我們可以改變紋理在Unity中的采樣方式,通過選擇紋理文件并在Inspector面板中改變filter mode(過濾模式):

imageimage

第六部分:試著改變Shader

現(xiàn)在,我們已經(jīng)大致了解了一些基礎(chǔ),我們可以做一些有趣的效果并做一些簡單的特效。首先,我們將使用一張噪聲貼圖實現(xiàn)“溶解” 或者“切斷”效應(yīng),首先我們將添加另一個紋理屬性和一個float 屬性,如下:

Properties{
    _Color("Color",Color)=(1,1,1,1)
    _MainTexture("Main Texture",2D)="white"{}
    _DissolveTexture("Dissolve Texture",2D)="white"{}
    _DissolveCutoff("Dissolve Cutoff",Range(0,1)=1
}

注意這里是如何設(shè)置_DissolveCutoff 為一個Range(0,1),它代表一個從(0,1)(包含)的float值,并且這種計數(shù)法允許我么容易的使用slider(滑動條)來設(shè)置值,接下來,讓我們在CGPROGRAM中添加他們。

float4 _Color;
sampler2D _MainTexture;
sampler2D _DissolveTexture;
float _DissolveCutoff;

現(xiàn)在能在片元函數(shù)中對溶解紋理采樣:

fixed4 fragmentFunction(v2f i):SV_TARGET{
    float4 textureColor=tex2D(_MainTexture,i.uv);
    float4 dissolveColor=tex2D(_DissolveCutoff,i.uv);
    return textureColor;
}

提示:我們將為我們的主紋理使用相同的UV紋理坐標(biāo),接下里,魔術(shù)發(fā)生了:

fixed4 fragmentFunction(v2f i):SV_TARGET{
    float4 textureColor=tex2D(_MainTexture,i.iv);
    float4 dissolveColor=tex2D(_DissolveTexture,i.uv);
    clip(dissolveColor.rgb-_DissolveCutoff);
    return textureColor;
}

clip 函數(shù)檢查這個給定的值是否小于0.如果小于0,我們將丟棄這個像素并且不繪制它。如果大于0,繼續(xù)保持像素、正常的渲染,我們的代碼的工作方式如下:

  1. 對主紋理的顏色進行采樣

  2. 對紋理顏色進行裁剪采樣

  3. 從裁剪紋理中減去裁剪值

  4. 如果小于0,不進行繪制

  5. 否則,返回主紋理采樣顏色

現(xiàn)在,保存并返回Unity,回到材質(zhì)面板,賦予“Dissolve Texture"我們的noise紋理,移動”Dissolve Cutoff" 滑動條,你應(yīng)該會看到一個效果,向下面這樣:

image

很酷吧? 我們也能做更多。在將其傳遞給fragment函數(shù)之前,讓我們嘗試更改這些頂點,在Inspector面板中暴露出一些結(jié)點屬性。

Properties{
    _Color("Color",Color)=(1,1,1,1)
    _MainTexture("Main Texture",2D)="white"{}
    _DissolveTexture("Dissolve Texture",2D)="white"{}
    _DissolveCuroff("Dissolve Cutoff",Range(0,1))=1
    _ExtrudeAmount("Extrue Amount",float)=0
}
...

float4 _Color;
sampler2D _MainTexture;
sampler2D _DissolveTexture;
float _DissolveCutoff;
float _ExtrudeAmount;

我們還將使用模型中的法線信息,因此,讓我們添加這個字段到a2v的結(jié)構(gòu)體中,以至于我們能訪問它。

struct a2v{
    float4 vertex:POSITION;
    float2 uv:TEXCOORD0;
    float3 normal:NORMAL;
};

現(xiàn)在,添加一個單行到頂點函數(shù)中:

v2f vertexFunction(a2v v){
    v2f o;
    v.vertex.xyz+=v.normal.xyz*_ExtrudeAmount;
    o.position=UnityObjectToClipPos(v.vertex);
    o.uv=v.uv;
    return o;
}

我么在這里做的是,在將頂點轉(zhuǎn)換為局部模型空間之前,我們將通過增加他們的法線方向時間來抵消它們的外加量,法線是一個向量代表頂點面向的方向,現(xiàn)在保存并返回Unity中,改變"Extrude Amount"的值,你應(yīng)該看到下面這樣的效果:

image

我們也能為這些屬性制作動畫:

v2f vertexFunction(a2v v){
    v2f o;
    v.vertex.xyz+=v.normal.xyz*_ExtrudeAmount*sin(_Time.y);
    o.position=UnityObjectToClipPos(v.vertex);
    o.uv=v.uv;
    return o;
}

_Time是一個代表時間的變量被包含在UnityCH.cginc中,y值代表秒,確?!癆nimated Materials” 在場景視圖中被勾選,如下:

image

下面是我們最終的代碼:

Shader "Unlit/Tutorial_Shader"{
    Properties{
        _Color("Color",Color)=(1,1,1,1)
        _MainTexture("Main Texture",2D)="white"{}
        _DissolveTexture("Dissolve Texture",2D)="white"{}
        _DissolveCutoff("Dissolve Cutoff",Range(0,1))=1
        _ExtrudeAmount("Extrue Amount",float)=0
    }
    Subshader{
        Pass{
            CGPROGRAM
                #pragma vertex vertexFunction
                #pragma fragment fragmentFunction
                #include "UnityCG.cginc"
                
                struct a2v{
                    float4 vertex:POSITION;
                    float2 uv:TEXCOORD0;
                    float3 normal:NORMAL;
                };
                struct v2f{
                    float4 position:SV_POSITION;
                    flaot2 uv:TEXCOORD0;
                };
                float4 _Color;
                sampler2D _MainTexture;
                sampler2D _DissolveTexture;
                float _DissolveCutoff;
                float _ExtrudeAmount;
                
                v2f vertexFunction(a2v v){
                    v2f o;
                    v.vertex.xyz+=v.normal.xyz*_ExtrudeAmount*sin(_Time.y);
                    o.position=UnityObjectToClipPos(v.vertex);
                    o.uv=v.uv;
                    return o;
                }
                
                fixed4 fragmentFunction(v2f i):SV_TARGET{
                    float4 textureColor=tex2D(_MainTexture,i.uv);
                    float4 dissolveColor=tex2D(_DissolveTexture,i.uv);
                    clip(dissolveColor.rgb-_DissolveCutoff);
                    return textureColor;
                }
            ENDCG
        }
    }
}

第七部分:Scripting 和Shaders

接下來,我們將討論怎樣使用Unity腳本來控制Shader(即C#和Shader的交互),例如,我們將再次使用之前添加的_Color屬性。首先,我們再片元函數(shù)中讓其為著色器的顏色進行著色,如下:

fixed4 fragmentFunction(v2f i):SV_TARGET{
    float4 textureColor=tex2D(_MainTexture,i.uv);
    float4 dissolveColor=tex2D(_DissolveTexture,i.uv);
    clip(dissolveColor.rgb-_DissolveCutoff);
    return textureColor*_Color;
}

我們將輸出顏色和_Color屬性相乘,在Editor中如下:

image

現(xiàn)在,讓我們開始寫腳本吧,我們將為每一個對象添加一個名為RainbowColour.cs的腳本。

image

在腳本中,聲明兩個私有變量 Rendeerer和Materail:

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

public class RainbowColor:MonoBehaviour{

    Renderer rend;
    Material material;
    
    void Start(){
        
    }
    void Update(){
        
    }
}

在Satrt()函數(shù)中,設(shè)置引用值。

void Start(){
    rend=GetComponent<Renderer>();
    material=rend.material;
}

我們將在shader中使用Material.SetColor()函數(shù)設(shè)置顏色值,這個函數(shù)的第一個參數(shù)是一個字符串,它的名字使我們想要設(shè)置的屬性的名字,第二個參數(shù)是我們想要設(shè)置的顏色的值。

void Start(){
    rend=GetComponent<Renderer>();
    material=rend.material;
    material.SetColor("_Color",Color.mangenta);
}

當(dāng)我們運行游戲的時候,顏色變?yōu)槠芳t。

image

第八部分:陰影? 表面著色器?

到目前為止,我們寫了一個Unlit Shader(無光照著色器),Unity還允許你寫表面著色器,表面著色器實際上就像vertex/fragment著色器,除了它們?nèi)サ袅嗽S多使著色器與光照與陰影交互的示例代碼。如果你對寫光照和陰影感興趣,這是一份很棒的教程 here

在這個章節(jié),我將展示的是,表面著色器的每個部分如何與我們的頂點/片元著色器相關(guān)聯(lián),如果你在Unity中創(chuàng)建一個新的“Standard Shader",你會看到一些自動生成的代碼,如下:

Shader "Custom/NewSurfaceShader" {
    Properties{
        _Color("Color",Color)=(1,1,1,1)
        _MainTex("Albedo(RGB)",2D)="white"{}
        _Glossiness("Smothness",Range(0,1))=0.5
        _Metallic("Metallic",Range(0,1))=0.0
    }
    SubShader{
        Tags{"RenderType="Opaque"}
        LOD 200
        
        CGPROGRAM
        //基于物理著色的光照模型,并且在所有光類型上啟用陰影
        #pragma surface surf Standard fullforwardshadows
        //使用3.0著色器目標(biāo),獲得更好的光照效果
        #pragma target 3.0
        sampler2D _MainTex;
        
        struct Input{
            float2 uv_MainTex;
        };
        half _Glossiness;
        half _Metrllic;
        fixed4 _Color;
        //為證著色器添加實例化支持,你需要在材質(zhì)上檢測“啟用示例"
        
        UNITY_INSTANCING_CBUFFER_START(Props)
        
        UNITY_INSTANCING_CBUFFER_END
        
        void surf(Input in,inout SurfaceOutputStandard o){
            fixed4 c=tex2D(_MainTex,in.uv_MainTex)*_Color;
            o.Albedo=c.rgb;
            o.Metallic=_Metallic;
            o.Smoothness=_Glossiness;
            o.Alpha=c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

讓我們看一看每一個部分并解釋一下他們都做了什么。
首先,tags標(biāo)簽:

SubShader{
    Tags{"RenderType"="Opaque"}
    ...
}

標(biāo)簽幫助你告訴渲染引擎如何以及何時你的著色器被渲染。在這種情況下,我們只是指定我們的著色器是透明的,這個對于深度紋理/地圖是非常有用的。

LOD 200

多細(xì)節(jié)層次或者(LOD)有助于指定再默寫硬件上使用哪種著色器,LOD值越大,著色器越復(fù)雜且它的值與模型的LOD無關(guān)。

#pragma surface surf Standard fullforwardshadows

類似于我們定義頂點和片元函數(shù),我們在這里定義了一個稱之為surf的表面函數(shù),Stadard指定Unity Shader使用標(biāo)準(zhǔn)光照模型,而fullforwardshadows指定著色器啟用所有常規(guī)陰影類型。

#pragma target 3.0

這里指定編譯使用的光照版本,值越大,效果越好,也越復(fù)雜,同時對系統(tǒng)有更高的要求。

void surf(Input i,inout SurfaceOutputStandard o){
    fixed4 c=tex2D(+mAINtEX,i.uv_MianT)*_Color;
    o.Albedo=c.rgb;
    
    o.Metallic=_Metallic;
    
    o.Smoothness=_Glossiness;
    o.Alpha=c.a;
}

這是著色器的核心部分,Unity定義了一個SurfaceOutputStandard 結(jié)構(gòu)體來替代指定像素的顏色值。你可以設(shè)置一些諸如“Albedo"的屬性,由于我們正在處理光照和陰影,不單單是直接獲取顏色值,需要能夠通過SurfaceOutputStandard保存的值來進行計算,下面是SurfaceOutputStandard的所有屬性值的一部分:

struct SurfaceOutput{
    fixed3 Albedo;
    fixed3 Normal;
    fixed3 Emission;
    half Specular;
    fixed Gloss;
    fixed Alpha;
}

Okay,討論一下關(guān)于verties把。
standard surface 默認(rèn)情況下不暴露編輯vertices屬性的函數(shù),我們可以手動添加一個。首先,添加pragma并定義一個vertex函數(shù)

#pragma surface surf Standard fullforwardshadows vertex:vert

定義vert函數(shù):

void vert(inout appdata_full v){
    v.vertex.xyz+=v.normal.xyz*_ExtrudeAmount*sin(_Time.y;
    )
}

提示:如果你在改變頂點坐標(biāo)的時候,陰影沒有隨之改變,你需要確保添加了”addshadow“ paagma 片段聲明,如下:

#pragma surface surf Standard fullforwardshadows vetex:vert addshadow

再表面著色器的內(nèi)部是非常復(fù)雜的,但是,它最終會被編譯成我們之前寫的頂點和片元函數(shù)那樣。我強烈的建議去讀官方文檔,以了解更多關(guān)于這方面的信息。

更多內(nèi)容,歡迎關(guān)注我的公眾號:

![碼碼小蟲](https://img-blog.csdn.net/20180527191517719?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppYW5adW9HdWFuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多