読者です 読者をやめる 読者になる 読者になる

Blend Mode (3)

DirectX

Photoshop 互換の「スクリーン」合成について見ていきましょう.
吉里吉里2の ltPsScreen を参考にします.
http://devdoc.kikyou.info/tvp/docs/kr2doc/contents/GraphicSystem.html#id128

FillColor = blend(DestColor, 1 - (1 - DestColor) × (1 - SrcColor), SrcAlpha)
ここに blend(a, b, r) = a × (1 - r) + b × r

これだけだと感覚が掴めないので,式を展開してみましょう.

FillColor = DestColor + SrcAlpha × SrcColor - DestColor × SrcAlpha × SrcColor

だいぶすっきりしてきました.よく見ると SrcAlpha は常に SrcColor にかけられる形で現われています.従って PixelShader 最終段あたりで事前に SrcColor に SrcAlpha を乗じておけば,アルファブレンディング時に SrcAlpha は不要となります.

FillColor = DestColor + SrcColor' - DestColor × SrcColor'
ここに SrcColor' = SrcAlpha × SrcColor

これをもう少しだけ書き換えます.

FillColor = DestColor × 1 + (1 - DestColor) × SrcColor'
または
FillColor = (1 - SrcColor') × DestColor + SrcColor' × 1

すなわち Photoshop 互換の「スクリーン」合成とは,一方の色をブレンド係数とみて,もう一方の色と「白」を線形合成する演算であることが分かります.ここで演算 f(x,y) を次のように定義します.

f(x,y) = x + y - x × y

f(x,y) は次のような性質を持ちます.

f(x,y) = f(y,x)
f(x,0) = x
f(f(x,y),z) = f(x,f(y,z))
f(x,y)∈[0,1] (for all x,y∈[0,1])


この結果は「スクリーン」合成によるマルチパスレンダリングは描画順序に依存しないことを示しています.
DirectX Graphics でこの合成方法を使用するには,先ほどの FillColor の最終形に着目し,次のように設定します(記法はエフェクトファイル準拠).

BlendOp = Add;
DestBlend = InvSrcColor;
SrcBlend = One;

ただし色出力については事前にアルファ値を乗じておく必要があります.例えば次のような設定が必要でしょう.

ColorOp[0] = Modulate;
ColorArg1[0] = Texture;
ColorArg2[0] = Current;
ColorOp[1] = Modulate;
ColorArg1[1] = Current | AlphaReplicate;
ColorArg2[1] = Current;

最終的な出力色が黒色 (0,0,0) というのは恒等変換に対応しますので,PixelShader 使用時であれば出力色が (0,0,0) に近いと分かった段階で texkill によって描画をキャンセルしてしまう等の応用も考えられます.