跳轉到內容

GLSL 程式設計/Blender/著色器除錯

來自 Wikibooks,開放世界開放書籍
一張偽彩色衛星影像。

本教程介紹了 **屬性變數**。它建立在 關於最小著色器的教程關於變化變數的 RGB 立方體教程 之上。

本教程還介紹了在 Blender 中除錯著色器的主要技術:偽彩色影像,即透過將片段顏色的某個分量設定為該值來視覺化一個值。然後,結果影像中該顏色分量的強度可以讓您對著色器中的值做出推斷。這看起來可能是一個非常原始的除錯技術,因為它確實是。不幸的是,Blender 中沒有其他選擇。

頂點資料從哪裡來?

[編輯 | 編輯原始碼]

RGB 立方體教程 中,您已經看到了片段著色器如何透過變化變數從頂點著色器獲取資料。這裡的問題是:頂點著色器從哪裡獲取資料?在 Blender 中,此資料由 **屬性視窗** 中的設定(特別是 **物件資料選項卡**、**材質選項卡** 和 **紋理選項卡** 中的設定)為每個選定物件指定。物件的網格的所有資料都在每一幀傳送到 OpenGL。(這通常稱為“繪製呼叫”。請注意,每次繪製呼叫都有一些效能開銷;因此,將一個大型網格傳送到 OpenGL 比使用多個繪製呼叫傳送多個較小的網格效率更高。)此資料通常包含一個三角形列表,每個三角形由三個頂點定義,每個頂點都具有某些屬性,包括位置。這些屬性透過屬性變數在頂點著色器中可用。

內建屬性變數及其視覺化方法

[編輯 | 編輯原始碼]

在 Blender 中,大多數標準屬性(位置、顏色、表面法線和紋理座標)都是內建的,即您不需要(事實上也不應該)定義它們。這些內建屬性的名稱實際上是由 OpenGL“相容性配置檔案”定義的,因為如果將為固定功能管道編寫的 OpenGL 應用程式與(可程式設計的)頂點著色器混合,則需要這樣的內建名稱。如果您必須定義它們,定義(僅在頂點著色器中)將如下所示

   attribute vec4 gl_Vertex; // position (in object coordinates, 
      // i.e. local or model coordinates)
   attribute vec4 gl_Color; // color (usually constant)
   attribute vec3 gl_Normal; // surface normal vector 
      // (usually normalized; also in object coordinates)
   attribute vec4 gl_MultiTexCoord0; //0th set of texture coordinates 
      // (a.k.a. “UV”; between 0 and 1) 
   attribute vec4 gl_MultiTexCoord1; //1st set of texture coordinates 
      // (a.k.a. “UV”; between 0 and 1)
   ...

只有一個屬性變數是由 Blender 提供但沒有 OpenGL 中的標準名稱,即切線向量,即一個與表面法線正交的向量。您應該將此變數自己定義為型別為 vec4 的屬性變數,名稱為 tangent,如下面的著色器所示

import bge

cont = bge.logic.getCurrentController()

VertexShader = """
   varying vec4 color;
   attribute vec4 tangent; // this attribute is specific to Blender 
      // and has to be defined explicitly

   void main()
   {
       color = gl_MultiTexCoord0; // set the varying to this attribute
    
       // other possibilities to play with:
    
       // color = gl_Vertex;
       // color = gl_Color;
       // color = vec4(gl_Normal, 1.0);
       // color = gl_MultiTexCoord0;
       // color = gl_MultiTexCoord1;
       // color = tangent;

       gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
   }
"""

FragmentShader = """
   varying vec4 color;

   void main()
   {   
      gl_FragColor = color;
   }
"""


mesh = cont.owner.meshes[0]
for mat in mesh.materials:
    shader = mat.getShader()
    if shader != None:
        if not shader.isValid():
            shader.setSource(VertexShader, FragmentShader, 1)
            shader.setAttrib(bge.logic.SHD_TANGENT)

請注意以下行

shader.setAttrib(bge.logic.SHD_TANGENT)

在 Python 指令碼中,它告訴 Blender 為著色器提供切線屬性。但是,Blender 僅會在 **屬性視窗** 中的某些設定下提供幾個屬性,特別是應在 **物件資料選項卡** 中指定 **UV 貼圖**(只需單擊“+”按鈕),應在 **材質選項卡** 中定義材質,應在 **紋理選項卡** 中定義紋理(例如,任何影像)。

RGB 立方體教程 中,我們已經看到了如何透過將片段顏色設定為這些值來視覺化 gl_Vertex 座標。在本例中,片段顏色設定為 gl_MultiTexCoord0,以便我們可以看到 Blender 為 **屬性視窗** 中的某些設定提供的紋理座標型別。

如何解釋偽彩色影像

[編輯 | 編輯原始碼]

在嘗試理解偽彩色影像中的資訊時,重要的是隻關注一個顏色分量。例如,如果屬性 gl_MultiTexCoord0 被寫入片段顏色,那麼片段的紅色分量會視覺化 gl_MultiTexCoord0x 座標,即輸出顏色是最大純紅色還是最大黃色或最大洋紅色並不重要,在所有情況下,紅色分量都是 1。另一方面,對於紅色分量來說,顏色是藍色、綠色還是青色也不重要,因為在所有情況下紅色分量都是 0。如果您從未學會只關注一個顏色分量,這可能很困難;因此,您可能考慮一次只檢視一個顏色分量。例如,使用此行在頂點著色器中設定變化量

            color = vec4(gl_MultiTexCoord0.x, 0.0, 0.0, 1.0);

這將變化變數的紅色分量設定為 gl_MultiTexCoord0x 分量,但將綠色和藍色分量設定為 0(以及 alpha 或不透明度分量設定為 1,但這在該著色器中並不重要)。

Blender 傳送到頂點著色器的特定紋理座標取決於 **物件資料選項卡** 中指定的 **UV 貼圖** 和 **紋理選項卡** 中指定的 **對映**。

紋理座標特別容易視覺化,因為它們像顏色分量一樣都在 0 到 1 之間。幾乎同樣容易的是歸一化向量的座標(即長度為 1 的向量;例如,gl_Normal 通常是歸一化的),因為它們始終介於 -1 和 +1 之間。要將此範圍對映到 0 到 1 的範圍,您需要將 1 加到每個分量,並將所有分量除以 2,例如

            color = vec4((gl_Normal + vec3(1.0, 1.0, 1.0)) / 2.0, 1.0);

請注意,gl_Normal 是一個三維向量。黑色對應於座標 -1,一個分量的全強度對應於座標 +1。

如果您要視覺化的值不在 0 到 1 或 -1 到 +1 的範圍內,則必須將其對映到 0 到 1 的範圍內,這是顏色分量的範圍。如果您不知道預期哪些值,您只需要嘗試一下。這裡有所幫助的是,如果您將顏色分量指定為不在 0 到 1 的範圍內,它們會自動被鉗制到此範圍內。即,小於 0 的值將被設定為 0,大於 1 的值將被設定為 1。因此,當顏色分量為 0 或 1 時,您至少知道該值小於或大於您假設的值,然後您可以迭代地調整對映,直到顏色分量在 0 到 1 之間。

除錯練習

[編輯 | 編輯原始碼]

為了練習著色器的除錯,本節包含一些在頂點著色器中將對 color 的賦值替換為它們中的每一個時會產生黑色的行。您的任務是找出每行的結果為什麼是黑色的。為此,您應該嘗試視覺化您不確定的任何值,並將小於 0 或大於 1 的值對映到其他範圍內,以便這些值可見,您至少對它們所在的範圍有一個概念。請注意,大多數函式和運算子都記錄在 “向量和矩陣運算” 中。

            color = gl_MultiTexCoord0 - vec4(1.5, 2.3, 1.1, 0.0);


            color = vec4(1.0 - gl_MultiTexCoord0.w);


            color = gl_MultiTexCoord0 / tan(0.0);

以下行僅適用於球體,需要一些關於點積和叉積的知識

            color = dot(gl_Normal, vec3(tangent)) * gl_MultiTexCoord0;


            color = dot(cross(gl_Normal, vec3(tangent)), gl_Normal) * 
               gl_MultiTexCoord0;


            color = vec4(cross(gl_Normal, gl_Normal), 1.0);


            color = vec4(cross(gl_Normal, gl_Vertex), 1.0);

函式 radians() 是否總是返回黑色?它有什麼用?

            color = radians(gl_MultiTexCoord0);

請查閱 “Khronos OpenGL ES API 登錄檔” 中提供的“OpenGL ES 著色語言 1.0.17 規範”中的文件,以瞭解 radians() 的用途。

片段著色器中的特殊變數

[編輯 | 編輯原始碼]

屬性特定於頂點,即它們通常對不同的頂點具有不同的值。片段著色器也有類似的變數,即對每個片段具有不同值的變數。但是,它們不同於屬性,因為它們不是由網格(即三角形列表)指定的。它們也不同於變化變數,因為它們不是由頂點著色器顯式設定的。

具體來說,一個四維向量 gl_FragCoord 可用,它包含正在處理的片段的螢幕(或:視窗)座標 ;有關螢幕座標系的描述,請參見 “頂點變換”

此外,提供了一個布林變數gl_FrontFacing,用於指定正在渲染三角形的正面還是背面。正面通常朝向模型的“外部”,而背面朝向模型的“內部”;但是,如果模型不是閉合曲面,則沒有明顯的外部或內部。通常,表面法線向量指向正面的方向,但這不是必需的。實際上,正面和背面是由頂點三角形的順序指定的:如果頂點以逆時針順序出現,則正面可見;如果它們以順時針順序出現,則背面可見。在切割教程中展示了一個應用程式。

恭喜你,你已經完成了本教程!我們已經看到了

  • Blender 中的內建屬性列表:gl_Vertexgl_Colorgl_Normalgl_MultiTexCoord0gl_MultiTexCoord1以及特殊的tangent
  • 如何透過設定輸出片段顏色的元件來視覺化這些屬性(或任何其他值)。
  • 片段程式中可用的兩個額外特殊變數:gl_FragCoordgl_FrontFacing

進一步閱讀

[編輯 | 編輯原始碼]

如果你還想了解更多


< GLSL 程式設計/Blender

除非另有說明,否則本頁面上的所有示例原始碼均授予公有領域。
華夏公益教科書