著色器簡介
本頁將說明什麼是著色器,並概述其在 Godot 中的運作方式。如需引擎著色語言的詳細參考,請見 著色語言。
著色器(Shader)是一種在圖形處理器(GPU)上執行的特殊程式。最初是用來為 3D 場景進行著色,但現在能做的事情更多。你可以利用著色器控制引擎在螢幕上繪製幾何圖形和像素的方式,實現各種視覺特效。
現代的繪圖引擎(如 Godot)都是透過著色器來繪製畫面:顯示卡能夠同時並行執行數千條指令,帶來極快的算繪速度。
由於著色器本質上是並行運算,處理資訊的方式與一般程式不同。著色器的程式碼會獨立地在每個頂點或像素上執行,且無法在畫格間儲存資料。因此,撰寫著色器時,需要用不同於其他程式語言的思維與方式進行設計。
假設你想把一張紋理中的所有像素都設為某個指定顏色,在 GDScript 中你可能會這麼寫:
for x in range(width):
for y in range(height):
set_color(x, y, some_color)
而在著色器中,你的程式碼本身就處於一個迴圈中,所以對應的寫法會像這樣。
void fragment() {
COLOR = some_color;
}
備註
顯示卡會針對每個需要繪製的像素呼叫一次或多次 fragment() 函式。詳細說明請參見下文。
Godot 中的著色器
Godot 提供的著色語言是基於廣泛使用的 OpenGL Shading Language(GLSL)所簡化而成。引擎會自動處理部分底層初始化作業,使你能更輕鬆地撰寫複雜的著色器。
在 Godot 中,著色器由稱為「處理函式」的主函式組成。處理函式是著色器程式的進入點。共有七種不同的處理函式。
vertex()函式會針對網格中的所有頂點執行,並設定頂點的位置及其他每個頂點專屬的變數。用於 canvas_item 著色器 與 空間著色器。fragment()函式會針對網格所覆蓋的每一個像素執行。它會使用vertex()函式所輸出的值,並對頂點間的數據進行插值。用於 canvas_item 著色器 及 空間著色器。light()函式會針對每個像素、每盞燈光各執行一次。它會取得來自fragment()函式及之前執行過的變數。用於 canvas_item 著色器 和 空間著色器。start()函式會在粒子系統中每個粒子首次生成時執行一次。用於 粒子著色器。process()函式會在每個影格中,針對粒子系統內的每個粒子執行一次。用於 粒子著色器。sky()函式會在輻射度立方體貼圖需要更新時,針對貼圖中的每個像素執行,也會在目前螢幕上的每個像素執行。用於 天空著色器。
警告
如果啟用了 vertex_lighting 算繪模式,或在專案設定中啟用了 Rendering > Quality > Shading > Force Vertex Shading (算繪 > 品質 > 著色 > 強制頂點著色),則 light() 函式將不會執行。在行動平台上預設啟用此設定。
備註
Godot 也提供 API 讓使用者撰寫完全自訂的 GLSL 著色器。詳情請參閱 使用計算著色器。
著色器類型
著色器不提供一個適用於所有用途(2D、3D、粒子、天空、霧)的通用型配置,你必須明確指定要編寫的著色器類型。不同類型支援的算繪模式、內建變數與處理函式也都不同。
在 Godot 中,所有著色器必須在第一行就指定其類型,例如:
shader_type spatial;
可用的類型如下:
spatial 用於 3D 算繪。
canvas_item 用於 2D 算繪。
particles 用於粒子系統。
fog 用於算繪 FogVolumes
算繪模式
著色器可以在第二行(類型之後)指定可選的算繪模式,例如:
shader_type spatial;
render_mode unshaded, cull_disabled;
算繪模式會改變 Godot 如何應用著色器的方式。例如,unshaded 模式會讓引擎略過內建的光照處理函式。
每種著色器類型支援的算繪模式各不相同,詳情請參考各類型的文件。
頂點處理器
在 spatial 與 canvas_item 著色器中,會針對每個頂點呼叫一次 vertex() 處理函式。
在你的世界幾何體中,每個頂點都擁有像是位置、顏色等屬性。此函式會修改這些數值,並將其傳遞給片段函式。你也可以利用 varying 變數,傳遞額外資訊給片段函式。
預設情況下,Godot 會自動幫你轉換頂點資訊,讓幾何體能正確投影到螢幕。你也可以透過算繪模式,自行進行資料變換;範例請見 Spatial 著色器文件。
片段處理器
fragment() 處理函式用於設定每一個像素的 Godot 材質參數。這段程式碼會在物件或圖元繪製的每一個可見像素上執行。僅能在 spatial、canvas_item 與 sky 著色器中使用。
片段函式的標準用途是設定用於光照計算的材質屬性。例如,你可以設定 ROUGHNESS、RIM 或 TRANSMISSION 的數值,這些設定會告訴光照函式該如何處理這個片段。這讓你能夠有效控制複雜的著色流程,而不必撰寫過多程式碼。如果你不需要這些內建功能,也可以忽略它們並自行撰寫光照處理函式,Godot 會自動優化。舉例來說,如果你沒對 RIM 賦值,Godot 就不會進行邊緣光的計算。在編譯階段,Godot 會檢查 RIM 是否有被使用,若沒有,相關程式碼就會被移除。因此,你不會在未使用的特效上浪費任何計算資源。
光照處理器
light() 處理器同樣會針對每個像素執行,且每盞影響該物件的燈光都會執行一次。若沒有任何燈光影響該物件,則不會執行。該函式會在 fragment() 處理器中被呼叫,通常用於處理在 fragment() 函式中設置的材質屬性。
light() 處理器在 2D 和 3D 的運作方式不同,詳細運作原理請參閱 CanvasItem 著色器 及 Spatial 著色器 的說明。