跳轉到內容

GLSL 程式設計/Blender/透明度

來自 Wikibooks,開放世界中的開放書籍
皮埃爾·奧古斯特·柯特創作於 1873 年的《春天》。注意透明的衣服。

本教程介紹了使用 Blender 中的 GLSL 著色器進行片段混合(即合成)。它假設您熟悉前面和後面的概念,如切面教程中所述。

更具體地說,本教程介紹了渲染透明物體,例如透明玻璃、塑膠、織物等。(更嚴格地說,這些實際上是半透明物體,因為它們不必完全透明。)透明物體允許我們透過它們看到東西;因此,它們的顏色與它們後面的東西的顏色“混合”。

“OpenGL ES 2.0 管道”的描述中所述,片段著色器為每個片段計算一個 RGBA 顏色(即gl_FragColor中的紅色、綠色、藍色和 alpha 分量)(除非片段被丟棄)。然後在“每個片段操作”中處理這些片段。其中之一是混合階段,它將片段的顏色(如gl_FragColor中指定)與已在幀緩衝區中的相應畫素的顏色組合,該顏色稱為“源顏色”(因為混合顏色的“目標”是幀緩衝區),稱為“目標顏色”。

混合是一個固定功能階段,即您可以自定義它,但不能對其進行程式設計。自定義的方式是指定一個混合方程。您可以將混合方程視為對結果 RGBA 顏色的定義

vec4 result = SrcFactor * gl_FragColor + DstFactor * pixel_color;

其中pixel_color是當前在幀緩衝區中的 RGBA 顏色,result是混合的結果,即混合階段的輸出。SrcFactorDstFactor是可自定義的 RGBA 顏色(型別為vec4),它們與片段顏色和畫素顏色進行逐元件相乘。SrcFactorDstFactor的值是在 Blender 的 Python API 中使用以下函式指定的

bge.types.KX_BlenderMaterial.setBlending({SrcFactor的程式碼},{DstFactor的程式碼})

兩個因子的可能程式碼在以下表格中總結(另請參見Blender 文件

程式碼 結果因子(SrcFactorDstFactor
bge.logic.BL_ONE vec4(1.0)
bge.logic.BL_ZERO vec4(0.0)
bge.logic.BL_SRC_COLOR gl_FragColor
bge.logic.BL_SRC_ALPHA vec4(gl_FragColor.a)
bge.logic.BL_DST_COLOR pixel_color
bge.logic.BL_DST_ALPHA vec4(pixel_color.a)
bge.logic.BL_ONE_MINUS_SRC_COLOR vec4(1.0) - gl_FragColor
bge.logic.BL_ONE_MINUS_SRC_ALPHA vec4(1.0 - gl_FragColor.a)
bge.logic.BL_ONE_MINUS_DST_COLOR vec4(1.0) - pixel_color
bge.logic.BL_ONE_MINUS_DST_ALPHA vec4(1.0 - pixel_color.a)

“向量和矩陣操作”中所述,vec4(1.0)只是vec4(1.0, 1.0, 1.0, 1.0)的簡寫。還要注意,混合方程中所有顏色和因子的所有分量都夾在 0 和 1 之間。

Alpha 混合

[編輯 | 編輯原始碼]

混合方程的一個具體示例稱為“alpha 混合”。在 Blender 中,它是這樣指定的

mat.setBlending(bge.logic.BL_SRC_ALPHA, bge.logic.BL_ONE_MINUS_SRC_ALPHA)

mat是一個型別為bge.types.KX_BlenderMaterial的材質(請參見Blender 文件;有關完整程式碼,請參見下文)。這將SrcFactor設定為vec4(gl_FragColor.a),將DstFactor設定為vec4(1.0 - gl_FragColor.a)。因此混合方程變為

vec4 result = vec4(gl_FragColor.a) * gl_FragColor + vec4(1.0 - gl_FragColor.a) * pixel_color;

這使用gl_FragColor的 alpha 分量作為不透明度。即,片段顏色越不透明,其不透明度及其 alpha 分量就越大,因此混合結果中片段顏色的比例就越大,而幀緩衝區中畫素顏色的比例就越小。一個完全不透明的片段顏色(即 alpha 分量為 1)將完全替換畫素顏色。

這個混合方程有時被稱為“over”操作,即“gl_FragColor over pixel_color”,因為它對應於在畫素顏色之上放置具有特定不透明度的片段顏色半透明層。(想象一下,在另一種顏色的東西上面放一層彩色玻璃或彩色半透明塑膠。)

由於 alpha 混合的普及,顏色的 alpha 分量通常被稱為不透明度,即使沒有使用 alpha 混合。此外,請注意,在計算機圖形學中,顏色的透明度的常見正式定義是該顏色的1 - 不透明度

預乘 Alpha 混合

[編輯 | 編輯原始碼]

alpha 混合有一個重要的變體:有時片段的顏色已將其 alpha 分量預乘到顏色分量中。(您可能認為它就像一個已經包含增值稅的價格。)在這種情況下,alpha 不應該再次乘以(增值稅不應該再次新增),正確的混合是

mat.setBlending(bge.logic.BL_ONE, bge.logic.BL_ONE_MINUS_SRC_ALPHA)

這對應於

vec4 result = vec4(1.0) * gl_FragColor + vec4(1.0 - gl_FragColor.a) * pixel_color;

疊加混合

[編輯 | 編輯原始碼]

混合方程的另一個示例是

mat.setBlending(bge.logic.BL_ONE, bge.logic.BL_ONE)

這對應於

vec4 result = vec4(1.0) * gl_FragColor + vec4(1.0) * pixel_color;

這只是將片段顏色新增到幀緩衝區中的顏色。注意,alpha 分量根本沒有使用;儘管如此,這個混合方程對許多種透明效果非常有用;例如,它通常用於粒子系統,當它們表示火焰或其他透明且發光的物體時。在關於順序無關透明度的教程中更詳細地討論了疊加混合。

著色器程式碼

[編輯 | 編輯原始碼]

這是一個簡單的著色器,它使用 alpha 混合,顏色為綠色,不透明度為 0.3。請注意,您必須將視窗著色設定為紋理,在3D 檢視選單中才能使混合生效。

import bge

cont = bge.logic.getCurrentController()

VertexShader = """
         void main()
         {
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
         }

"""

FragmentShader = """
         void main()
         {
            gl_FragColor = vec4(0.0, 1.0, 0.0, 0.3); 
               // fourth component (alpha) is important: 
               // this is semitransparent green
         }
"""

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)
            mat.setBlending(bge.logic.BL_SRC_ALPHA, 
                            bge.logic.BL_ONE_MINUS_SRC_ALPHA)

通常,半透明網格應該在所有不透明網格渲染後使用停用的深度緩衝區寫入進行渲染。這樣,不透明物體(應透過半透明物體發出光)的任何片段都不會因為其前面的半透明物體而導致深度測試失敗。(深度測試在關於“每個片段操作”部分中討論。)為了在 Blender 中啟用此技術,您必須在3D 檢視中選擇該物體,然後轉到屬性視窗並選擇材質選項卡。如果您還沒有,請建立一個新材質。在材質選項卡中,選中透明度並選擇Z 透明度

此設定還應按從後到前的順序渲染三角形。這是必要的,因為使用停用的深度緩衝區寫入渲染透明網格並不總是能解決所有問題。如果片段混合的順序無關緊要,它會完美執行;例如,如果片段顏色只是用加性混合新增到幀緩衝區中的畫素顏色,則片段混合的順序並不重要;參見關於順序無關透明度的教程。但是,對於其他混合方程式,例如 alpha 混合,結果將根據片段混合的順序而不同。(如果你透過幾乎不透明的綠色玻璃看幾乎不透明的紅色玻璃,你主要會看到綠色,而如果你透過幾乎不透明的紅色玻璃看幾乎不透明的綠色玻璃,你主要會看到紅色。類似地,將幾乎不透明的綠色顏色混合在幾乎不透明的紅色顏色之上,將不同於將幾乎不透明的紅色顏色混合在幾乎不透明的綠色顏色之上。)為了避免出現偽影,**Z 透明度**按從後到前的順序渲染三角形。另一種方法是使用加性混合或(預乘)alpha 混合,混合度較小(在這種情況下,目標因子DstFactor接近 1,因此 alpha 混合接近加性混合)。

包含背面

[編輯 | 編輯原始碼]

前面的著色器沒有渲染物體的“內部”。但是,由於我們可以透過透明物體的外部看到內部,因此我們也應該渲染內部。如關於切口的教程中所述,可以透過停用背面剔除來渲染內部。但是,如果我們只是停用剔除,我們可能會遇到麻煩:如上所述,透明片段渲染的順序通常很重要,但是沒有任何剔除,來自內部和外部的重疊三角形可能會以隨機順序渲染,這會導致令人討厭的渲染偽影。因此,透過選擇**Z 透明度**(如上一節所述)來啟用三角形排序非常重要。

恭喜,您完成了本教程!關於渲染透明物體的一件有趣的事情是,它不僅僅是關於混合,還要求瞭解背面剔除和深度緩衝區。具體來說,我們已經研究了

  • 什麼是混合以及如何在 Blender 中指定它。
  • 帶有透明和不透明物體的場景是如何渲染的。

進一步閱讀

[編輯 | 編輯原始碼]

如果你還想了解更多


< GLSL 程式設計/Blender

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