【Cg Programming/Unity】透過 ~ 透明な物体の描画【順番にやっていく】
今回はこちら。
en.wikibooks.org
この節では透過について学ぶ。
サンプル画像として載っている絵画がエッチでかわいい。
透過
例えば色ガラスを覗いたときのように、向こうのものが透けて見えるオブジェクトを描画したい場合、透けて見える景色の色と、色ガラス自身の色とを混ぜ合わせた色を描画する必要がある。
このような操作をBlendingと呼ぶ。
大抵の場合、向こうの景色の色を何割、色ガラスの色を残りの何割といったような感じで混ぜ合わせるのだが、何割という値を指定するのにColorの4番目のパラメータであるα値を用いる。このようなBlendingを特にアルファブレンディングと呼ぶ。
用語
これから描画しようとしているフラグメントシェーダの出力値をSource、すでに描画されている背景のことをDestinationと呼ぶ。
一般的なアルファブレンディング
一般的なアルファブレンディングでは最終的に描画される色は以下のようになっている。
result = SrcAlpha * SrcColor + (1 - SrcAlpha) * DstColor
ただし、SrcAlpha
は4つのパラメータすべてがSourceのアルファ値であるfloat4ベクトル。
SrcColor
はそのままSourceの色(float4)、DstColor
はDestinationの色(float4)である。
このようなブレンディングを行いたい場合、コード上のCGPROGRAMの外側で以下のように指定してやる。
Blend SrcAlpha OneMinusSrcAlpha
Blend
の後ろ、1つ目にSourceの色に掛け合わせる値(float4)の名前、2つ目にDestinationの色に掛け合わせる値(float4)の名前を指定する。
Blend係数
SrcAlpha
のように指定できる値はBlend係数と呼び、ほかにも色々ある。
One
float4(1, 1, 1, 1)
Zero
float4(0, 0, 0, 0)
SrcColor
Sourceの色(フラグメントシェーダで返す値)
SrcAlpha
SrcColor.aaaa
DstColor
背景の色
DstAlpha
DstColor.aaaa
OneMinusSrcColor
float4(1, 1, 1, 1) - SrcColor
コード
実際にBlendingを行うシェーダのコードは以下のようになる。
Shader "Custom/Transparency" { SubShader { Tags { "Queue" = "Transparent" } pass { ZWrite Off Cull Front //アルファブレンディングの形式を指定 //この場合はSrcAlphaがこのパスで出力する色のアルファ値で、 //最終的には (このパスで出力する色)xSrcAlpha + (背景にすでに描画されている色)x(1-SrcAlpha)がピクセルの色になる Blend SrcAlpha OneMinusSrcAlpha //Blend One Zero //こんな書き方をすると単純に上書きしているのと同じ //Blend SrcColor DstColor //こんな書き方をすると色の2乗同士を足し合わせることになるが、使う場面が思いつかない CGPROGRAM #pragma vertex v #pragma fragment f struct v2f { float4 position : SV_POSITION; float4 color : TEXCOORD0; }; v2f v(float4 vertexPos : POSITION) { v2f output; output.position = UnityObjectToClipPos(vertexPos); output.color = float4(vertexPos.xyz, 0.5) + float4(0, 0, 0, 0); return output; } float4 f(v2f input) : COLOR { return input.color; } ENDCG } pass { ZWrite Off Cull Back Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex v #pragma fragment f struct v2f { float4 position : SV_POSITION; float4 color : TEXCOORD0; }; v2f v(float4 vertexPos : POSITION) { v2f output; output.position = UnityObjectToClipPos(vertexPos); output.color = float4(vertexPos.xyz, 0.5) + float4(1, 1, 1, 0); return output; } float4 f(v2f input) : COLOR { return input.color; } ENDCG } } }
まず裏面をアルファブレンディングで背景に重ねて描画し、そのあとに表面を同じように重ねて描画している。
こうすることによってCubeが透明な箱のように見える。
わかりやすくするため同じシェーダを適用したCubeをもう一つ少しずらした位置に置いてある。
注意点
さて、ここで少し注意しておきたいのが、描画がオブジェクト単位で行われるということだ。
例えば箱同士が重なっている場合、正確には箱①表、箱②表、箱①裏、箱②裏の順に描画されてほしいところだがこの方法だと箱①表、箱①裏、箱②表、箱②裏になってしまう。
これを解決する方法はのちのち出てくると思う。
と思っていたら次の節で解決方法が1つ示されていた。
spi8823.hatenablog.com