Textureを合成するShader

Textureを合成するShader

Textureを任意の位置に好きな大きさで合成することができるShaderです。

図の青色が元のTexture、赤色が合成するTextureです。

外積と内積を使用する方法

・Textureを合成する領域かの判別

 外積と内積を用いて点Qが合成する赤色の領域(点Pを中心とした大きさ2hの四角形abcd)にあるかどうかを判別します。

\(\vec{ab}\)と\(\vec{aQ}\)の外積\(\vec{an}=\vec{ab}\times\vec{aQ}\)で得られるベクトルの方向は下図の紫色の範囲では手前方向、橙色の範囲では奥の方向になります。

また、\(\vec{bc}\)と\(\vec{bQ}\)の外積\(\vec{bn}=\vec{bc}\times\vec{bQ}\)で得られるベクトルの方向は下図で色分けされた通りです。

次に、\(\vec{an}\)と\(\vec{bn}\)の内積を計算します。下図の青色の領域は\(\vec{an}\)と\(\vec{bn}\)が同じ方向を、赤色の領域は反対の方向を向いています。それぞれを単位ベクトルにすることで、ベクトルがなす角度を計算することができます。角度が\(0^\circ\)、二つベクトルが同じ方向の場合は内積値は1となります。また、角度が\(180^\circ\)、二つベクトルが反対方向の場合は-1となります。そのため、下図に示すように青色の領域の内積値は1に、赤色の領域では-1となります。

以上より、\(\vec{an}\cdot\vec{bn}\)、\(\vec{bn}\cdot\vec{cn}\)、\(\vec{cn}\cdot\vec{dn}\)及び\(\vec{dn}\cdot\vec{an}\)の全ての内積値が1となる座標がabcdで囲まれた四角形内の座標となります。

・合成するテクスチャの座標変換

 下図のように、\((P_{x}-h,P_{y}-h)\)を原点とする大きさが2h×2hの座標を、\((0,0)\)を原点とする大きさが1×1のUV座標へ変換する必要があります。式は以下の通りです。
$$
Q^{\prime}=\frac{Q-(P-h)}{2h}=\frac{Q-P}{2h}+\frac{1}{2}
$$

・shader

 shaderでは内積値をsaturateを使用して-1~1を0~1へ変換しています。内積値に2をかけることにより、誤差により1未満の値になったときでも1となるようにしています。内積値を掛け算することで、領域内は1をそれ以外は0となるようにしています。最後に色の合成をしますが、合成するTextureのalpha値を用いて計算しています。これにより、合成するTextureに透明もしくは半透明な部分があっても、問題なく表示されるようになっています。

・stepを使用する方法

 外積と内積を使用して領域内に点Qがあるかどうかを判別していましたが、stepを用いることで簡潔に同じことができます。
\(u\)が\((P_{x}-h)\)より大きく、\((P_{x}+h)\)より小さい。また、\(v\)が\((P_{y}-h)\)より大きく、\((P_{y}+h)\)より小さい。これを満たすとき、点Qは領域内にあるといえます。領域内では1を、それ以外は0を返すコードをif文で記述すると

となります。これをstepを用いて書き直します。step(a, b)はbがa以上となった場合1を、それ以外は0を返します。よって上記のif文は

とstepで書き換えることができます。

・shder

 stepを用いてTextureを合成するshaderは以下の通りです。外積と内積を使用した場合に比べて、コードが簡潔になりました。

alpha値を考慮した色の合成

 以上のshaderではメインのテクスチャのalpha値は考慮されていないため、メインのテクスチャに透明、もしくは半透明な部分があった場合、正しく表示されません。そこで、メインのテクスチャのalpha値を考慮して、合成できるようにshaderを変更しました。

上記部分を

と書き換えることで両方のテクスチャのalpha値を考慮した合成ができます。

実行結果

 実行結果はこちらです。スライダーを動かすことで、合成するTextureの位置と大きさを変更できます。

参考サイト

NEAREAL:Alpha Blending の2種類の算出方法と使い分け