Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

匯出簡介

本頁面會講解什麼是著色器,會為你綜述其在 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 著色語言(GLSL)的簡化。引擎會為你處理一些底層的初始化工作,讓編寫複雜著色器更為簡單。

在 Godot 中,著色器由若干主函式組成,這些函式被稱為“處理器函式”。處理器函式是著色器程式的入口。有七種不同的處理器函式。

  1. vertex() 函式會為網格中的所有頂點各運作一次,用來設定頂點的位置和其他與頂點相關的變數。在 :ref:`canvas_item 著色器 <doc_canvas_item_shader>`和:ref:`空間著色器 <doc_spatial_shader>`中使用。

  2. fragment() 函式會為網格所覆蓋的所有像素各運作一次。這個函式會用到 vertex() 函式輸出的值,這些值會在頂點之間進行插值。在 :ref:`canvas_item 著色器 <doc_canvas_item_shader>`和:ref:`空間著色器 <doc_spatial_shader>`中使用。

  3. light() 函式會為每個像素和每個燈光各運作一次。這個函式會用到 fragment() 函式以及前幾次運作中的變數。在 :ref:`canvas_item 著色器 <doc_canvas_item_shader>`和:ref:`空間著色器 <doc_spatial_shader>`中使用。

  4. start() 函式會在粒子系統中的每個粒子出生時各運作一次。在:ref:`粒子著色器 <doc_particle_shader>`中使用。

  5. start() 函式會為粒子系統中的每個粒子每影格時各運作一次。在:ref:`粒子著色器 <doc_particle_shader>`中使用。

  6. sky() 函式會在輻射度立方體貼圖需要更新時為輻射度立方體貼圖中的每個像素各運作一次,也會為目前螢幕上的每個像素運作一次。在:ref:`天空著色器 <doc_sky_shader>`中使用。

  7. fog() 函式會為體積霧片段體素緩衝中與 FogVolume 相交的每個片段體素運作一次。在:ref:`霧著色器 <doc_fog_shader>`中使用。

警告

如果啟用了 vertex_lighting 渲染模式,或者在專案設定中啟用了 **Rendering > Quality > Shading > Force Vertex Shading**(渲染 > 品質 > 著色 > 強制頂點著色),則不會運作 light() 函式。在移動平臺上預設啟用。

備註

Godot 還為使用者編寫完全自訂的 GLSL 著色器暴露了 API。詳見 使用計算著色器

著色器型別

你所編寫的著色器必須指定型別(2D、3D、粒子、天空、霧),不存在所有場景都可以使用的通用配置。不同的型別支援不同的渲染模式、內建變數、處理函式。

在 Godot 中,所有的著色器都需要在第一行指定它們的型別,類似這樣:

shader_type spatial;

有六種搜尋模式:

渲染模式

可以在著色器的第二行,也就是在著色器型別之後,指定渲染模式,類似這樣:

shader_type spatial;
render_mode unshaded, cull_disabled;

渲染模式會修改 Godot 應用著色器的方式。例如,unshaded 模式會讓引擎跳過內建的光線處理器函式。

每種著色器型別都有不同的渲染模式。每種著色器型別的完整渲染模式列表請參閱參考手冊。

頂點處理器

spatialcanvas_item 著色器中,會為每一個頂點呼叫 vertex() 處理函式。在 particles 著色器中則會為每一個粒子呼叫一次。

你的世界中的幾何體上,每一個頂點都有位置、顏色等屬性。該函式會修改這些值,並將其傳入片段函式。你也可以借助 varying 向片段著色器傳遞額外的資料。

預設情況下,Godot 會為你對頂點資訊進行變換,這是將幾何體投影到螢幕上所必須的。你可以使用渲染模式來自行變換資料;範例見 Spatial 著色器文件

片段處理器

fragment() 處理函式的作用是設定每一個像素的 Godot 材質參數。這裡的程式碼會在繪製的物件或像素的每一個可見像素上執行。只能在 spatialcanvas_itemsky 著色器中使用。

片段函式的標準用途是設定用於計算光照的材質屬性。例如,你可以為 ROUGHNESSRIMTRNASMISSION 等設定值,告訴光照函式光照應該如何處理對應的片段。這樣就可以控制複雜的著色管線,而不必讓使用者編寫過多的程式碼。如果你不需要這一內建功能,那麼你可以忽略它,自行編寫光照處理函式,Godot 會將其優化掉。例如,如果你沒有向 RIM 寫入任何值,那麼 Godot 就不會計算邊緣光照。編譯時,Godot 會檢查是否使用了 RIM;如果沒有,那麼它就會把對應的程式碼刪除。因此,你就不會在沒有使用的效果上浪費算力。

光照處理器

light() 處理器也會在每一個像素上運作,並且同時還會在每一個影響該物件的燈光上運作。如果沒有燈光影響該物件則不會運作。它會被用於 fragment() 處理器,一般會在 fragment() 函式中進行材質屬性設定時執行。

light() 處理器在 2D 和 3D 中的工作方式不同;每種工作方式的詳細描述請參閱它們對應的文件 CanvasItem 著色器 and Spatial 著色器