Shader 之 Blend

什麼是 Blend?

Blending is used to make transparent objects.html

When graphics are rendered, after all Shaders have executed and all Textures have been applied, the pixels are written to the screen. How they are combined with what is already there is controlled by the Blend command.git

上面這段話是 Unity 官方對 Blend 命令的解釋,意思大體是「 Blend 命令控制與已經存在在 GBuffer 緩存中的像素進行組合渲染(是應該渲染 GBuffer 中的像素?仍是原遊戲物體的像素?仍是說兩個像素作一些組合操做再渲染?)。」github

語法

  • Blend Off:關閉混合(這是默認值)。
  • Blend SrcFactor DstFactor:配置並啓用混合。生成的顏色乘以 SrcFactor。屏幕上已有的顏色乘以 DstFactor,二者相加。
  • Blend SrcFactor DstFactor, SrcFactorA DstFactorA:與上面相同,但使用不一樣的因子來混合 alpha 通道。
  • BlendOp Op:不要將混合顏色添加到一塊兒,而是對它們執行不一樣的操做。
  • BlendOp OpColor, OpAlpha:與上面相同,但對顏色(RGB)alpha(A)通道使用不一樣的混合操做。

Blend 屬性

SrcFactor/SrcFactorADstFactor/DstFactorA 上填的值。緩存

  • One:混合因子 1,表示徹底的源顏色或目標顏色。
  • Zero:混合因子 0,捨棄掉源顏色或目標顏色。
  • SrcColor:源顏色值
  • SrcAlpha:源透明度
  • DstColor:目標顏色值
  • DstAlpha:目標透明度
  • OneMinusSrcColor:1 - SrcColor
  • OneMinusSrcAlpha:1 - SrcAlpha
  • OneMinusDstColor:1 - DstColor
  • OneMinusDstAlpha:1 - DstAlpha

BlendOp 屬性

  • Add:加法 FinalColor = SrcFactor * SrcColor + DstFactor * DstColor
  • Sub:減法(源-目標) FinalColor = SrcFactor * SrcColor - DstFactor * DstColor
  • RevSub:減法(目標-源) FinalColor = DstFactor * DstColor - SrcFactor * SrcColor
  • Min:較小值(逐個通道比較)
  • Max:較大值(逐個通道比較)

下面是一些目前僅限 DX11.1 支持的邏輯運算混合操做。app

⚠️ 注意:s == SrcFactord == DstFactoroop

  • LogicalClear:Clear (0)
  • LogicalSet:Set (1)
  • LogicalCopy:Copy (s)
  • LogicalCopyInverted:Copy inverted (!s)
  • LogicalNoop:Noop (d)
  • LogicalInvert:Invert (!d)
  • LogicalAnd:And (s & d)
  • LogicalNand:Nand !(s & d)
  • LogicalOr:Or (s | d)
  • LogicalNor:Nor !(s | d)
  • LogicalXor:Xor (s ^ d)
  • LogicalEquiv:Equivalence !(s ^ d)
  • LogicalAndReverse:Reverse And (s & !d)
  • LogicalAndInverted:Inverted And (!s & d)
  • LogicalOrReverse:Reverse Or (s | !d)
  • LogicalOrInverted:Inverted Or (!s | d)

語法分析

當使用 Blend 時,最終顏色被計算爲 result = fragment_color * SrcFactor + pixel_color * DstFactor,這個 fragment_color 便是通過處理的片斷顏色,也就是 fragment返回的結果,pixel_color 是本來存在於緩衝區(GBuffer)的顏色,這個 result 顏色被從新寫入緩衝區,等待被其餘片斷 Blend 或者變成最終顏色(若是沒有被其餘 Blend)。ui

上面這段話是對 語法 中的spa

Blend SrcFactor DstFactor:配置並啓用混合。生成的顏色乘以 SrcFactor。屏幕上已有的顏色乘以 DstFactor,二者相加。翻譯

的分析,其中的 生成的顏色 是指 fragment 返回的結果,屏幕上已有的顏色 對應上面的 pixel_color 是指 本來存在於緩衝區(GBuffer)的顏色 。3d

除去 Blend 參數,上述公式中的加號也是能夠配置的,這個就是 BlendOp

常見 Blend 組合及效果

上圖爲無任何 Blend 命令的狀況下 ,左邊爲 Scene 視圖,右邊爲 Game 視圖。

前提條件:

  1. 立方體在前面,白色球體在立方體的後面。
  2. 立方體的 Tags{ "RenderType"="Transprant" "Queue" = "Transparent" }
    白色球體的 Tags{ "RenderType"="Transprant" "Queue" = "Transparent+100" }Queue使用 Transprant 保證了 立方體Game 視圖中不爲黑色,白色球體的 QueueTransparent+100 保證了白色球體比立方體後渲染。

⚠️ 注意:下面是修改的立方體的 Shader :

  • Blend One One:立方體材質的像素和 GBuffer(天空盒)中的像素混合渲染。
  • Blend One Zero:只渲染立方體材質的像素。
  • Blend Zero One:只渲染 GBuffer(天空盒)中的像素。
  • Blend SrcAlpha OneMinusSrcAlpha:傳統透明度
  • Blend SrcColor zero:只顯示立方體材質的源顏色
  • Blend SrcColor One:混合立方體材質的源顏色和 GBuffer(天空盒)的源顏色

更多的組合請自行去嘗試。

下面將經過風宇衝博客中的幾個具體的數值計算的小例子來加深理解,以 Blend SrcAlpha OneMinusSrcAlpha 爲 🌰 :

翻譯成中文就是 最終顏色 = 源顏色 * 源透明值 + 目標顏色 * (1 - 源透明值)

  1. 假設貼圖有一個不透明紅色點 Color(1, 0, 0, 1),該點背景色爲不透明藍色 Color(0, 0, 1, 1)

    最終顏色 = (1, 0, 0) * 1 + (0, 0, 1) * (1 - 1) = (1, 0, 0)

    結論一:貼圖 alpha 值爲 1 時,僅顯示貼圖,不顯示背景。

  2. 假設貼圖有一個透明紅色點 Color(1, 0, 0, 0),該點背景色爲透明,但 B 通道值爲 1,即 Color(0, 0, 1, 0)

    最終顏色 = (1, 0, 0) * 0 + (0, 0, 1) * (1 - 0) = (0, 0, 1)

    結論二:貼圖 alpha 值爲 0 時,僅顯示混合目標即背景,不顯示貼圖。

    可是目標 alpha 值爲 0,即其實這個點的背景是透明的,而咱們卻把它顯示出來了,這就不對了。

    經驗:帶 A 通道的貼圖中,不僅 A 值爲 0,RGB 值也要爲 0,否則容易出錯。

  3. 假設貼圖有一個半透明紅色點 Color(1, 0, 0, 0.8),該點背景色爲不透明藍色 Color(0, 0, 1, 1)

    最終顏色 = (1, 0, 0) * 0.8 + (0, 0, 1) * (1 - 0.8) = (0.8, 0, 0.2)

    而假如 0.8 變爲 0.2 時,

    最終顏色 = (1, 0, 0) * 0.2 + (0, 0, 1) * (1 - 0.2) = (0.2, 0, 0.8)

    結論:貼圖 alpha 值越大,顏色越偏向貼圖;alpha 值越小,顏色越偏向混合目標。

參考文章:

若有內容有誤,歡迎 issue 指正。

轉載請註明出處!

相關文章
相關標籤/搜索