跳轉到內容

GLSL 程式設計/Unity/順序無關透明度

來自華夏公益教科書,開放的書籍,開放的世界
“Where Have You Bean” by flickr 使用者 Ombligotron。標題中的錯別字指的是描繪的雕塑“雲門”又名“豆子”。

本教程涵蓋順序無關混合

它繼續討論“透明度”部分,並解決標準透明度的一些問題。如果你沒有讀過那個教程,你應該先讀一下。

“84 – 父子” by Ben Newton。雙重曝光的例子。

順序無關混合

[編輯 | 編輯原始碼]

“透明度”部分所述,混合結果通常(特別是對於標準 alpha 混合)取決於三角形渲染的順序,因此如果三角形沒有從後到前排序(它們通常沒有),就會導致渲染偽像。術語“順序無關透明度”描述了各種避免此問題的技術。其中一項技術是順序無關混合,即使用不依賴於三角形光柵化順序的混合方程。有兩種基本可能性:疊加混合和相乘混合。

疊加混合

[編輯 | 編輯原始碼]

疊加混合的標準示例是本節中的影像中的雙重曝光:顏色被新增,以至於不可能(或至少非常困難)說出照片拍攝的順序。疊加混合可以用“透明度”部分中介紹的混合方程來表徵

vec4 result = SrcFactor * gl_FragColor + DstFactor * pixel_color;

其中SrcFactorDstFactor由 Unity 的 ShaderLab 語法中的行確定

Blend {SrcFactor 的程式碼} {DstFactor 的程式碼}

對於疊加混合,DstFactor 的程式碼必須為OneSrcFactor 的程式碼不能依賴於幀緩衝區中的畫素顏色;也就是說,它可以是OneSrcColorSrcAlphaOneMinusSrcColorOneMinusSrcAlpha

一個例子是

Shader "GLSL shader using additive blending" {
   SubShader {
      Tags { "Queue" = "Transparent" } 
         // draw after all opaque geometry has been drawn
      Pass { 
         Cull Off // draw front and back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha One // additive blending

         GLSLPROGRAM
               
         #ifdef VERTEX
         
         void main()
         {
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
         }
         
         #endif


         #ifdef FRAGMENT
         
         void main()
         {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3); 
         }
         
         #endif

         ENDGLSL
      }
   }
}

相乘混合

[編輯 | 編輯原始碼]

攝影中相乘混合的一個例子是使用多個均勻的灰色濾鏡:濾鏡放在相機上的順序對於影像的最終衰減無關緊要。就三角形的光柵化而言,影像對應於三角形光柵化之前幀緩衝區的內容,而濾鏡對應於三角形。

在使用以下行在 Unity 中指定相乘混合時

Blend {SrcFactor 的程式碼} {DstFactor 的程式碼}

SrcFactor 的程式碼必須為ZeroDstFactor 的程式碼必須依賴於片段顏色;也就是說,它可以是SrcColorSrcAlphaOneMinusSrcColorOneMinusSrcAlpha。一個典型的使用片段的 alpha 分量指定的透明度來衰減背景的示例將使用OneMinusSrcAlpha作為DstFactor 的程式碼

Shader "GLSL shader using multiplicative blending" {
   SubShader {
      Tags { "Queue" = "Transparent" } 
         // draw after all opaque geometry has been drawn
      Pass { 
         Cull Off // draw front and back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend Zero OneMinusSrcAlpha // multiplicative blending 
            // for attenuation by the fragment's alpha

         GLSLPROGRAM
               
         #ifdef VERTEX
         
         void main()
         {
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
         }
         
         #endif


         #ifdef FRAGMENT
         
         void main()
         {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3); 
               // only A (alpha) is used
         }
         
         #endif

         ENDGLSL
      }
   }
}

完整著色器程式碼

[編輯 | 編輯原始碼]

最後,將相乘混合用於衰減背景並將疊加混合用於新增三角形的顏色組合在一個著色器中是有意義的,方法是組合上面介紹的兩個通道。如果忽略三角形網格顏色本身的衰減,這可以被認為是對小透明度,即小的 alpha 值的 alpha 混合的近似。

Shader "GLSL shader using order-independent blending" {
   SubShader {
      Tags { "Queue" = "Transparent" } 
         // draw after all opaque geometry has been drawn
      Pass { 
         Cull Off // draw front and back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend Zero OneMinusSrcAlpha // multiplicative blending 
            // for attenuation by the fragment's alpha

         GLSLPROGRAM
               
         #ifdef VERTEX
         
         void main()
         {
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
         }
         
         #endif


         #ifdef FRAGMENT
         
         void main()
         {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3); 
               // only A (alpha) is used
         }
         
         #endif

         ENDGLSL
      }

      Pass { 
         Cull Off // draw front and back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha One // additive blending to add colors

         GLSLPROGRAM
               
         #ifdef VERTEX
         
         void main()
         {
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
         }
         
         #endif


         #ifdef FRAGMENT
         
         void main()
         {
            gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
         }
         
         #endif

         ENDGLSL
      }
   }
}

請注意,兩個通道的順序很重要:首先衰減背景,然後新增顏色。

恭喜你,你已經完成了本教程。我們已經瞭解了

  • 什麼是順序無關透明度和順序無關混合。
  • 兩種最重要的順序無關混合型別是什麼(疊加和相乘)。
  • 如何實現疊加混合和相乘混合。
  • 如何將兩個通道組合用於疊加和相乘混合,以實現對 alpha 混合的順序無關近似。

進一步閱讀

[編輯 | 編輯原始碼]

如果你仍然想了解更多

  • 關於著色器程式碼,你應該閱讀“透明度”部分.
  • 關於另一種順序無關透明度技術,即深度剝離,你可以閱讀 Cass Everitt 的技術報告:“互動式順序無關透明度”,該報告可在網上獲取。


< GLSL 程式設計/Unity

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