著色器簡介

本頁將說明什麼是著色器,並概述其在 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 中,著色器由稱為「處理函式」的主函式組成。處理函式是著色器程式的進入點。共有七種不同的處理函式。

  1. vertex() 函式會針對網格中的所有頂點執行,並設定頂點的位置及其他每個頂點專屬的變數。用於 canvas_item 著色器空間著色器

  2. fragment() 函式會針對網格所覆蓋的每一個像素執行。它會使用 vertex() 函式所輸出的值,並對頂點間的數據進行插值。用於 canvas_item 著色器空間著色器

  3. light() 函式會針對每個像素、每盞燈光各執行一次。它會取得來自 fragment() 函式及之前執行過的變數。用於 canvas_item 著色器空間著色器

  4. start() 函式會在粒子系統中每個粒子首次生成時執行一次。用於 粒子著色器

  5. process() 函式會在每個影格中,針對粒子系統內的每個粒子執行一次。用於 粒子著色器

  6. sky() 函式會在輻射度立方體貼圖需要更新時,針對貼圖中的每個像素執行,也會在目前螢幕上的每個像素執行。用於 天空著色器

  7. fog() 函式會針對體積霧片段體素緩衝區中,與 FogVolume 相交的每個體素執行。用於 霧著色器

警告

如果啟用了 vertex_lighting 算繪模式,或在專案設定中啟用了 Rendering > Quality > Shading > Force Vertex Shading (算繪 > 品質 > 著色 > 強制頂點著色),則 light() 函式將不會執行。在行動平台上預設啟用此設定。

備註

Godot 也提供 API 讓使用者撰寫完全自訂的 GLSL 著色器。詳情請參閱 使用計算著色器

著色器類型

著色器不提供一個適用於所有用途(2D、3D、粒子、天空、霧)的通用型配置,你必須明確指定要編寫的著色器類型。不同類型支援的算繪模式、內建變數與處理函式也都不同。

在 Godot 中,所有著色器必須在第一行就指定其類型,例如:

shader_type spatial;

可用的類型如下:

算繪模式

著色器可以在第二行(類型之後)指定可選的算繪模式,例如:

shader_type spatial;
render_mode unshaded, cull_disabled;

算繪模式會改變 Godot 如何應用著色器的方式。例如,unshaded 模式會讓引擎略過內建的光照處理函式。

每種著色器類型支援的算繪模式各不相同,詳情請參考各類型的文件。

頂點處理器

spatialcanvas_item 著色器中,會針對每個頂點呼叫一次 vertex() 處理函式。

在你的世界幾何體中,每個頂點都擁有像是位置、顏色等屬性。此函式會修改這些數值,並將其傳遞給片段函式。你也可以利用 varying 變數,傳遞額外資訊給片段函式。

預設情況下,Godot 會自動幫你轉換頂點資訊,讓幾何體能正確投影到螢幕。你也可以透過算繪模式,自行進行資料變換;範例請見 Spatial 著色器文件

片段處理器

fragment() 處理函式用於逐像素設定 Godot 材質參數。這段程式碼會在物件或圖元所繪製的每一個可見像素上執行。僅能在 spatialcanvas_item 著色器中使用。

片段函式的標準用途是設定用於光照計算的材質屬性。例如,你可以設定 ROUGHNESSRIMTRANSMISSION 的數值,這些設定會告訴光照函式該如何處理這個片段。這讓你能夠有效控制複雜的著色流程,而不必撰寫過多程式碼。如果你不需要這些內建功能,也可以忽略它們並自行撰寫光照處理函式,Godot 會自動優化。舉例來說,如果你沒對 RIM 賦值,Godot 就不會進行邊緣光的計算。在編譯階段,Godot 會檢查 RIM 是否有被使用,若沒有,相關程式碼就會被移除。因此,你不會在未使用的特效上浪費任何計算資源。

光照處理器

light() 處理器同樣會針對每個像素執行,且每盞影響該物件的燈光都會執行一次。若沒有任何燈光影響該物件,則不會執行。該函式會在 fragment() 處理器中被呼叫,通常用於處理在 fragment() 函式中設置的材質屬性。

light() 處理器在 2D 和 3D 的運作方式不同,詳細運作原理請參閱 CanvasItem 著色器Spatial 著色器 的說明。