解讀Unity中的CG編寫Shader系列三

2021-07-14 23:50:50 字數 2702 閱讀 2694

在上乙個例子中,我們得到了由mesh元件傳遞的資訊經過數學轉換至合適的顏色區間以顏色的形式著色到物體上。這篇文章將要在此基礎上研究片段的擦除(discarding fragments)和前面剪裁、後面剪裁(front face culling and back face culling)來達到透明效果。

當乙個mesh元件的資訊被傳遞後,我們可以通過**決定哪些部分渲染(render)出來,而哪些部分不要,這個過程就像把那些不要的部分剔除了,我們看不到他,雖然他的mesh資訊還在,但是我們的gpu不會去處理它,肯定比剔除前gpu的效能消耗要低。

這個過程就好比我們的mesh元件是乙個透明的膜,我們假設這個膠紙我們根本看不到,而片段著色器在著色的時候像毛筆選擇性地上色,最後的效果是我們可能看到膜的一部分是可見的,但是不見的地方,膜還是存在的,只是我們沒有給他上色,我們既看不看他們,也不需要再他們上面畫寶貴的墨水(gpu並行處理能力)

所以我們可以來改造一下上乙個例子中的經度綠色假彩色球體,將其經度》0.5的部分擦掉,那麼**應該相應修改為:

pass;

float4 frag(vertexoutput input) : color

//其餘部分仍然按y值大小生成經度綠色球

return float4(0.0, input.posinobjectcoords.y , 0.0, 1.0);

} endcg

}

那麼把這個shader給material,然後給乙個球體可以看到我們上次見到的綠色假彩色球只剩下南半球了:

從正面看起來像是實心的

稍微傾斜一下從上面看過去可以看到球體內部是空心的,所以我用膜和毛筆來比喻這個render過程。

我們來把球體換成立方體,看看是什麼樣子:

可以發現這是乙個詭異的立方體,立方體的六個面分別只繪製了一半,且都是下面的一半。

為啥立方體和球體上的效果差別這麼大呢?

因為立方體是直角座標系,球體是極座標系啊…………扇耳光~~~還給老師了嗎 嗎嗎嗎嗎嗎

同理我們將》0.5改為<0.5,就可以得到球體的北半球。

這是最簡單的表面剔除(cuteaway)

更好一點的表面剔除是將片段的位置從物件座標系轉換到世界座標系,然後根據基礎矩陣進行變換可以計算出哪些片段位於其他球體的內部(原始半徑是0.5),然後再將位於其他球體內部的表面剔除,這樣的話假如兩個球互相重疊一部分,那麼即使兩個球互相繞著自己的球心怎麼旋轉,沒有重疊的部分都會被繪製,而重疊的部分不會被繪製,反正我們看不到,這樣省效能。因為即使球體旋轉,物體的座標經過unity的內建矩陣變換為世界座標後,重疊部分的世界座標是固定的,所以不會出現兩個球體重疊部分表面被裁剪後,旋轉乙個球之後慢慢看到被裁剪的那個洞了。(因為前面的方法是按物件座標系裁剪的)

剛剛的**中我們看到了cull off,這行**位於cgprogram標記之前,所以他不屬於cg的範疇。它是我們unity中的shaderlab的指令,所以他不需要分號來結尾。

cull off 即為關掉三角形剪裁(為何突然冒出來了三角形,腦補一下,我們的立體影象在計算機中是以三角形拼湊的,正因為如此我們的三維圖形才會產生鋸齒,那都是三角形的功勞啊)

cull front 為前面(外部)剪裁

cull back 為後面(內部)剪裁,而這是我們所有shader的預設模式,也就是說如果shader不是你自己寫的,很可能轉動我們的半球的時候,你只看的到前方的曲面而不是半球曲面,不信你可以拖個模型看看

至於為何預設是後面剪裁呢,因為大部分情況下我們的渲染都是對整個三維體的表面進行的,那麼既然表面全部被渲染,你就看不到正背對著你的部分,所以預設後面剪裁會節省很多物理效能啊!

不過既然我們將表面進行了擦除,那麼我們可以透過被擦除的部分看到背面的內表面,那麼我們應該修改這個剪裁模式了,就像乙個房子有房頂,我們從正上方看不到房子裡面的地板,所以地板應該屬於剪裁的範疇。但是如果我們把房頂擦除了(推開房頂),還看不到地板那就有點恐怖了,這種事情就要切換剪裁模式

為了更直觀的明白這兩種模式,我們修改上面的**為內部/外部剪裁的雙通道(pass),並且每個pass中的最後著色不同(紅和綠)

要明白一點,unity中的shader只會執行乙個subshader,但是會執行所有的pass

修改後的**:

pass;

float4 frag(vertexoutput input) : color

//其餘部分仍然按y值大小生成經度綠色球

return float4(0.0, input.posinobjectcoords.y , 0.0, 1.0);

} endcg

} pass;

float4 frag(vertexoutput input) : color

//其餘部分仍然按y值大小生成經度紅色球

return float4(input.posinobjectcoords.y, 0.0 , 0.0, 1.0);

} endcg

}

我們完成了乙個擁有兩個pass的shader,現在看看球體是什麼樣子:

從頂部往下看,由於完全垂直看下去我們不知道這個球體的凹進去的還是凸出來的,彷彿還是我們上個例子中的綠色經度球,

我們再從底部網上看:

我們還是不知道這個紅黑部分是凹的還是凸的,畢竟這是個半球,垂直半球去看沒啥發現

我們再從正面偏上看過去:

可見綠黑部分是凹進去的內表面,紅黑部分是凸起的外表面~

至此,我們已經可以隨心所欲地控制我們的表面哪些地方可見或者不可見啦!

接下來cg還有更神奇的地方等待我們去發現~

Linux的sh指令碼編寫基礎知識

本文總結的shell指令碼編寫核心要點切中要害,入門必讀。1 開頭 程式必須以下面的行開始 必須方在檔案的第一行 bin sh 符號 用來告訴系統它後面的引數是用來執行該檔案的程式。在這個例子中我們使用 bin sh來執行程式。當編寫指令碼完成時,如果要執行該指令碼,還必須使其可執行。要使編寫指令碼...

linux中sh指令碼的寫法

先介紹遇到的問題 遇到shell問題 1將變數中的內容輸入到某個檔案 date8 20181111 錯誤方式,linux會認為date8是指令並且去執行,這時候會報20181111是不可識別的指令 date8 bg action date txt 正確方式 echo date8 bg action ...

mysql裡面show mysql中的show命令

一些工作中常用的mysql中的show命令的用法 show databases 顯示所有的資料庫 show tables show tables from database name 顯示當前資料庫的資料表 顯示指定資料庫的資料表 show columns from table name datab...