Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
著色器簡介
本頁將說明什麼是著色器,並概述其在 Godot 中的運作方式。如需引擎著色語言的詳細參考,請見 著色語言。
著色器(Shader)是一種在圖形處理器(GPU)上執行的特殊程式。最初是用來為 3D 場景進行著色,但現在能做的事情更多。你可以利用著色器控制引擎在螢幕上繪製幾何圖形和像素的方式,實現各種視覺特效。
現代的繪圖引擎(如 Godot)都是透過著色器來繪製畫面:顯示卡能夠同時並行執行數千條指令,帶來極快的算繪速度。
由於著色器本質上是並行運算,處理資訊的方式與一般程式不同。著色器的程式碼會獨立地在每個頂點或像素上執行,且無法在畫格間儲存資料。因此,撰寫著色器時,需要用不同於其他程式語言的思維與方式進行設計。
假設你想把一張紋理中的所有像素都設為某個指定顏色,在 GDScript 中你的程式碼可能會使用 for 迴圈:
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 著色器中使用。
片段函式的標準用途是設定用於光照計算的材質屬性。例如,你可以設定 ROUGHNESS、RIM 或 TRANSMISSION 的數值,這些設定會告訴光照函式該如何處理這個片段。這讓你能夠有效控制複雜的著色流程,而不必撰寫過多程式碼。如果你不需要這些內建功能,也可以忽略它們並自行撰寫光照處理函式,Godot 會自動優化。舉例來說,如果你沒對 RIM 賦值,Godot 就不會進行邊緣光的計算。在編譯階段,Godot 會檢查 RIM 是否有被使用,若沒有,相關程式碼就會被移除。因此,你不會在未使用的特效上浪費任何計算資源。
光照處理器
light() 處理器同樣會針對每個像素執行,且每盞影響該物件的燈光都會執行一次。若沒有任何燈光影響該物件,則不會執行。該函式會在 fragment() 處理器中被呼叫,通常用於處理在 fragment() 函式中設置的材質屬性。
light() 處理器在 2D 和 3D 的運作方式不同,詳細運作原理請參閱 CanvasItem 著色器 及 Spatial 著色器 的說明。