Unity シェーダーで _MainTex 画像のアルファ値を参照・反映

前回、Unity の Unlit Shader を新規作成し、指定された影の色のシェーダープロパティを参照し、その色で、タイルマップ画像の色を指定した影の色で塗る処理を実装しました。
しかし、なぜかタイルマップ画像のアルファ値は反映されていないらしく、透けて見える部分も指定された影の色で塗りつぶされてしまいました。

前回の記事:Unity シェーダープロパティを処理で参照するためのマッピング | Compota-Soft-Press

Unity shader のシェーダープロパティを Cg 言語で参照する型を Color に対応した Fixed4 に変えると、その色で塗りつぶされました.

今回は、ピクセルシェーダーの処理(frag関数)で、タイルマップ画像のアルファ値を正しく読み取りその形にあわせた影を作成するための検証と実装手順を紹介します。
※ Unity は 2021.3.14f1、Test Framework パッケージは Version 1.1.33、Visual Studio は Community 版 Version 17.2.5、 OS は Windows 10 です。

テンプレートの frag 関数の処理

新規作成した Unlit Shader をタイルマップオブジェクトに割り当てても、マップチップは正常に表示されました。
しかし、このとき、 _MainTex シェーダープロパティのアルファ値はすべて完全不透明を指しています。

Unlit Shader で扱うアルファ値の検証

Unlit Shader を新規作成し、その frag 関数の r (赤) の値を返す部分を、 _MainTex シェーダープロパティの同じ座標のアルファ値(不透明度)に変えてみました。

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 texCol = tex2D(_MainTex, i.uv);

                // _MainTex の i.uv のアルファ値を R (赤) の値として出力
                fixed4 retCol = fixed4(texCol.w, 0.0, 0.0, 1.0);

                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, retCol);

                return retCol;
            }

この結果は、冒頭で触れたように、前回の結果から考えると、全て R=255 の赤色で矩形の範囲が塗りつぶされるはずです。
しかし、結果は、赤(1.0)と黒(0.0)で不透明度はマップチップの形にそって適切に設定されていました。

Unity Unlit Shader で_MainTexのアルファ値をR要素に置き換えた結果、赤と黒で不透明度がきちんと設定されていた.

しかし、次のように、アルファ値をアルファ値として扱うと、灰色(0.1)でさきほど黒かった(不透明度=0)だった部分も塗りつぶされています。

この画像の赤色や黒色が完全不透明と完全透明の二つでしかないことを確認するため GIMP に入力し、ヒストグラムダイアログで赤色の成分の分布を見ると 0 と 255 しかないことが確認できました。

Unity Unlit Shader でアルファ値を赤色で出力した画像をGIMPヒストグラムで調べると0か255の要素しか検出されませんでした.

それならば、アルファ値を、そもそものアルファ値として色の4番目の要素に指定して、1~3番目に歯 R, G, B を設定すれば、タイルマップ画像の形にそって影もできると思い、次のコードで試しました。
※ frag 関数で返す色の各要素の値は 0 ~ 255 ではなく 0.0 ~ 1.0 です。(0.3, 0.3, 0.3) は少し明るめの灰色を指します。

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 texCol = tex2D(_MainTex, i.uv);

                // _MainTex の i.uv のアルファ値を R (赤) の値として出力
                //fixed4 retCol = fixed4(texCol.w, 0.0, 0.0, 1.0);
                fixed4 retCol = fixed4(0.3, 0.3, 0.3, texCol.w);

                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, retCol);

                return retCol;
            }

しかし、タイルマップ画像(_MainTex)のアルファ値をアルファ値として使うと、先ほどは赤と黒で完全不透明と不透明な部分に分けられていたのに、全て完全不透明で矩形で塗りつぶされてしまいました。

Unity Unlit Shader の frag 関数で _MainTex のアルファ値を用いて影の色をつけると全て完全不透明になってしまう.

Tilemap のシェーダーによる描画はマス単位?

タイルマップは何も置かれていないマスも含めて複数のマスを描画します。
先ほど、灰色になった部分は、何かが配置されたマスの領域です。
しかも、その縦幅は、そのマスに指定したように半分になっています。
このことから、TilemapRenderer からシェーダーが描画するのは、何かが配置されたマスごとではないかと推測します。

画像のアルファ値を扱えるように変更

【Unity】アルファテクスチャを利用できる Shader – うにてぃブログ」によると、シェーダにはアルファ値を扱えないものがあることがわかりました。
_MainTex シェーダープロパティからタイルマップ画像の情報としてアルファ値も適切に読みとれていることは、先ほどのアルファ値を赤色に置き換えたテスト画像でわかりました。
しかし、アルファ値として frag 関数が戻り値で返しても、アルファ値を扱えないシェーダの場合は、アルファ値が無視されて、指定した RGB で完全不透明で塗られてしまうようです。

そこで、シェーダープログラムの一部を変更し、アルファ値を扱えるようにします。
参照:【Unity】アルファテクスチャを利用できる Shader – うにてぃブログShaderLab: Blending – Unity マニュアル

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

SubShader の冒頭で行っている Tags の設定を変更します。

    SubShader
    {
        Tags {"Queue" = "Transparent"}
        Blend SrcAlpha OneMinusSrcAlpha
        LOD 100

これで、アルファブレンドを扱えるシェーダになりました。

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);

                fixed4 shadowCol = fixed4(_ShadowColor.x, _ShadowColor.y, _ShadowColor.z, col.w);

                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, shadowCol);
                return shadowCol;
            }

6 行目では、 _ShadowColor という Unity エディタの Inspector ウィンドウのシェーダープロパティで指定できる影の色で RGB を指定し、4 番目でタイルマップ画像から得たその座標のアルファ値を設定しています。
※fixed4 の場合は、x, y, z, w という要素で 1 ~ 4 番目この場合ならば、 r, g, b, a の値にアクセスします。

シェーダの Tags を変更し、アルファ値を扱えるようにしたシェーダーでは、アルファ値を用いて画像の形に合わせた影が塗られました。

Unity Unlit Shader の Tags を変更しアルファ値を扱えるようにしたシェーダーでは、アルファ値を用いて画像の形に合わせた影が塗られました.

作成したタイルマップ影用シェーダーのプログラムの公開

今回作成した影用シェーダーのプログラムは GitHub で公開しています。自己責任で使用してください。

Unity/SCTilemapShadowUnlitShader.shader at main · sakura-crowd/Unity

アルファ値を赤色の要素に出力したテスト用のシェーダーも公開しました。

Unity/UnlitShaderAlphaToRed.shader at main · sakura-crowd/Unity

影用シェーダーは画像のアルファ値をもとに、指定された色に塗り替えるだけです。
タイルマップの影として利用する場合は、Unity 用に自作した影用タイルマップ作成関数で作成した影用タイルマップのゲームオブジェクトに設定することで、タイルマップの影を表現します。

Unity Tilemap の壁に影をつける自作関数の処理手順の紹介 | Compota-Soft-Press

まとめ

今回は、Unity の Unlit Shader をベースにして、画像の不透明度に応じて指定した色で塗るシェーダを作成・公開しました。
シェーダの不透明度が正しく受け取れているかを確認するために、シェーダーの赤色の要素の値にアルファ値を設定し出力された画像の色を GIMP のヒストグラムを用いて検証しました。
シェーダの設定でアルファ値を扱うかどうかを変えられることもわかりました。

参照サイト Thank You!

記事一覧 → Compota-Soft-Press

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました