ETH官方钱包

切換
舊版
前往
大廳
主題

【學(xué)習(xí)筆記 #1】從0開始的Unity Shader學(xué)習(xí)

%%鼠 拒收病婿 | 2020-04-28 00:29:57 | 巴幣 20 | 人氣 2533

開始自學(xué)Shader,前一兩個月前讀的進(jìn)度經(jīng)過一點時間就完全忘記了
用自己的大腦去解讀Unity Shader就好像付費解鎖冰原DLC一樣,完全不同的世界。
姻緣下找到不錯的學(xué)習(xí)教材,開始有系統(tǒng)的學(xué)習(xí),順便幫自己做個筆記,也許能幫到你。

先聲明自己的用詞都極為不專業(yè),也許會用錯字或觀念誤導(dǎo)什麼的,還請包涵和指點。
(建議用網(wǎng)頁版看,手機(jī)格式會跑掉)


unlit的基本架構(gòu)
Shader "Unlit/RE0Practice"
{
    Properties{}
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex v
            #pragma fragment f

            fixed4 v():SV_POSITION{
                return 0;
            }
            fixed4 f():SV_TARGET{
                return fixed4(1,1,1,1);
            }
            ENDCG
        }
    }
}

  • Shader "shader名稱"
  • Properties :宣告可以從外部輸入的變數(shù)的地方
  • SubShader: 一個shader可以有多個Subshader,用處大概就是A平臺主機(jī)只支援Subshader A,而B平臺主機(jī)只支援Subshader B,兩個SubShader就可以寫在同一個腳本裡,主機(jī)會自動去偵測支援哪個管道。
  • Pass: 寫我們要對這Shader做哪些處理的方法,一個Subshader可以有多個pass,但太多會降低效能
上面程式碼還有一些藍(lán)藍(lán)的字沒講解,別擔(dān)心!! 我第一次看也很怕,但其實很單純,我先一層一層講下來:

Properties:
變數(shù)型態(tài)有
  • Int
  • Float
  • Range
  • Color
  • Vector
  • Cube
  • 2D
  • 3D
宣告方式:
變數(shù)名稱 ("inspector顯示名稱", 變數(shù)型態(tài)) =初始值
亂打的範(fàn)例:
Properties{
        myInt ("MYInt",int)=2
        v ("v",Vector)=(1,2,3,1)
        c ("c",Cube)=""{}
        d ("d",2D)="white"{}
        r ("myRange",Range(0,5))=2.5
    }

*注意: Vector型態(tài)一定是四維的
面板長這樣:


Subshader:
除了上面講的功能,他還有一些東西可以設(shè)定:
Cull  Back | Front | Off  剔除選擇的面
ZTest 沒用過
ZWrite On | Off  要不要寫深度
Blend 混和模式

Tags有好幾個可以查,但以新手來說,我只用過來設(shè)定透明材質(zhì)
亂打得範(fàn)例:
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        Blend SrcAlpha OneMinusSrcAlpha
        Cull off
        ZWrite On
        LOD 100

Pass:
先用CGPROGRAM 和 ENDCG包起來,宣告這是CG語法。
接下來一個pass基本要輸出2個東西! 就是 vertex和fragment 才能正常顯示在畫面上。

要用#pragma 來宣告接下來用來輸出的函數(shù)名稱,
以這個程式碼為例:
            CGPROGRAM
            #pragma vertex v
            #pragma fragment f

            fixed4 v():SV_POSITION{
                return 0;
            }
            fixed4 f():SV_TARGET{
                return fixed4(1,1,1,1);
            }
            ENDCG

格式:
#pragma vertex 函數(shù)名稱
#pragma fragment 函數(shù)名稱
然後實做 v()和 f(),輸出值的型態(tài)可以改,目前先以最簡單的fixed4為例子。

" : "右邊是輸出的目標(biāo),SV_POSITION跟POSITION在大部分的平臺都是相同的,但保守起見,輸出的目標(biāo)都是SV開頭的那個比較好。
所以整段程式碼的意思是:
有個函數(shù)v負(fù)責(zé)放置vertex的位置,有個函數(shù)f負(fù)責(zé)給面上白色 (1,1,1,1)
因為點都放在0,所以看不到任何東西,但恭喜! 寫出了第一個可執(zhí)行的shader

再改一下:
           fixed4 v(float4 vp:POSITION):SV_POSITION{
                return UnityObjectToClipPos(vp);
            }
            fixed4 f():SV_TARGET{
                return fixed4(1,1,1,1);
            }

給v函數(shù) 輸入物件的位置資訊vp,用UnityObjectToClipPos轉(zhuǎn)成世界座標(biāo)的位置顯示。

一開始我很困惑到底是從哪裡輸入資料進(jìn)來的,但好像是Unity 的MeshRender會負(fù)責(zé)這部分。

結(jié)果:


自訂型態(tài):
剛開一個shader檔案裡面預(yù)設(shè)有a2v和v2f的資料型態(tài),一開始真的會嚇到不知道怎麼改才好,但其實就算不用那些也能操作,但就是比較整齊的感覺吧

如果我程式碼改成:
            struct myData{
                float4 v:POSITION; //模型頂點座標(biāo)
                float3 normal: NORMAL; //法線
                float4 texcoord:TEXCOORD0; //貼圖座標(biāo)
            };
            struct myOutPut{
                float4 pos :SV_POSITION;
                fixed3 col : COLOR0;
            };

            myOutPut v(myData vp){
                myOutPut o;
                //vp.v+=0.5; 修改傳入的座標(biāo)
                o.pos= UnityObjectToClipPos(vp.v);
                //o.pos+=20; 影響在物件在世界座標(biāo)的位置
                o.col=vp.normal*0.5+0.2;
                return o;
            }
            fixed4 f(myOutPut d):SV_TARGET{
                return fixed4(d.col,1);
            }


結(jié)果:


補充:
有內(nèi)建的資料結(jié)構(gòu)可用,以下是用appdata_full
會輕鬆很多
//片段著色資料
            struct v2f{
                float4 pos : SV_POSITION;
                fixed4 color : COLOR0;
            };

            //讓頂點著色器與片段著色器互動
            v2f vert(appdata_full v){
                v2f o;
                o.pos= UnityObjectToClipPos(v.vertex);

                o.color=fixed4(v.texcoord.xy ,0.0 ,1);
                o.color=fixed4(v.texcoord1.xy ,0.0 ,1);

                return o;
            }
            
            fixed4 frag(v2f i):SV_Target{
                return i.color;
            }


接下來是胡亂實驗:
改成這樣但結(jié)果與上面相同
          struct myData{
                float4 v:POSITION; //模型頂點座標(biāo)
                float3 normal: NORMAL; //法線
                float4 texcoord:TEXCOORD0; //貼圖座標(biāo)
                
                fixed3 col : COLOR0;
            };
         
            myData v(myData vp){
                myData o;
                o.v= UnityObjectToClipPos(vp.v);
                o.col=vp.normal*0.5+0.5;
                return o;
            }
            fixed4 f(myData d):SV_TARGET{
                d.v=0;//無效
                //d.col=d.normal*0.5+0.5; //無效,無法取得normal
                return fixed4(d.col,1);
            }

但我發(fā)現(xiàn)在片段著色器 f() 裡面執(zhí)行跟頂點有關(guān)的程式碼是無效的,或會取不到值。
所以我想會制定出一個偏向給fragment函數(shù)用的資料類別可能一來是頂點與片段間資料傳遞,二來是用來區(qū)分跟片段著色較無關(guān)係的變數(shù)吧??




先這樣,我直接跳過數(shù)學(xué)理論那段就來看程式碼了....在想下一個該繼續(xù)看實作的,還是回去看數(shù)學(xué)的基礎(chǔ)呢

然後我的書是跟老師借的,非常推薦!! 對新手超友善。
送禮物贊助創(chuàng)作者 !
0
留言

創(chuàng)作回應(yīng)

樂小呈
我是理論派
董邏輯才能活用[e12]

這裡有一些Shader教學(xué),但窩看不董
https://catlikecoding.com/unity/tutorials/
https://www.febucci.com/

加油!
2020-04-28 10:37:22
%%鼠 拒收病婿
感謝分享![e5]
不過我是實作派的,應(yīng)該說沒有trial and error,我是學(xué)不起來的[e15]
2020-04-30 18:36:21
追蹤 創(chuàng)作集

作者相關(guān)創(chuàng)作

相關(guān)創(chuàng)作

更多創(chuàng)作