ユニティちゃんでShader学習②、座標色シェーダー

ユニティちゃんでShader学習②、座標色シェーダー

ユニティちゃんで学習。座標を色に変換するUnity 3Dシェーダーの作り方。
スクリーン座標の分かり辛いz軸とw軸について。

関連ページ 参考URL
前回 はマテリアルに単色を代入するシェーダーを作りました。


今回はモデルの座標を無理やり色に変換するシェーダーを作っていきます。

テストに使う3Dモデル

3Dモデルは ユニティちゃんPackege UnityToonShader を使っていきます。
Unityちゃんパッケージ

スクリーン座標を色に変換するシェーダー

頂点シェーダーで受け取った座標を、ピクセルシェーダーで色に変換するコードを書いていきます。
実用的ではないですが、シェーダーの仕組みを知るのに割と便利です。
以下コード全文です。
Shader "Unlit/CoordinatesColor"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            
//後述のComputeScreenPos関数に必要な宣言

            #include "UnityCG.cginc"
            
            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                
//スクリーン座標を保存してピクセルシェーダーに伝えるために追加

                float4 screenPos : TEXCOORD0;
            };

            
// 頂点シェーダー

            v2f vert (appdata v)
            {
                v2f o;
                
// ワールド座標をカメラを原点とする座標系に変換し、

                
// かつカメラの画角外の頂点を削ります

                o.vertex = UnityObjectToClipPos(v.vertex);
                
// クリップ座標を正規化してスクリーン座標に変換

                o.screenPos = ComputeScreenPos(o.vertex);
                return o;
            }

            
// ピクセルシェーダー

            fixed4 frag (v2f i) : SV_Target
            {
                
//座標情報を無理やり色に変換

                
//x軸をr(赤)に、y軸をg(緑)、z軸をb(青)に代入する

                return fixed4(i.screenPos.x, i.screenPos.y, i.screenPos.z, 1);
            }
            ENDCG
        }
    }
}
後述しますが、i.screenPos.zの代入だけは実際はz軸の座標が関係ない処理になっています。

ユニティちゃんの服に使っているdef_matのシェーダーを、作成したシェーダーに変更します。 Unityちゃんの服のシェーダーの設定
シェーダーの変更

実装した結果は次のようなものになります。

スクリーン座標とは何か

Unityシェーダーで言うスクリーン座標とは、UnityC#でいうビューポート座標に近いです。
カメラの画角の左下をx=0, y=0として、右上をx=1, y=1とする、正規化された座標の事を言います。
下の画像を見ての通り、x軸が右に寄るほど赤色が濃くなり、y軸が上に寄るほど緑色が強く出ています。
スクリーン座標のxy軸の説明

一方でビューポート座標とは手前と奥の座標の扱い方がかなり異なります。
ComputeScreenPosで得られたスクリーン座標は、z軸が常に0.5で意味のない値になっています。
z軸の代わりに使うのがw軸の座標です。

スクリーン座標のw軸は、カメラの座標に近づくほど0に近づき、カメラから離れるほど1に近づきます。
カメラのz軸座標と完全に重なったとき、このw軸は0になります。
またTransformのz軸の値が、カメラのz軸から+1になった段階で、このw軸は1になります。そこから1以上には増えません。
スクリーン座標のz軸の説明

つまり先ほどピクセルシェーダー内のコードは、スクリーン座標のz軸を青色に代入しているので、実際には青色の値は常に0.5になっています。
            
// ピクセルシェーダー

            fixed4 frag (v2f i) : SV_Target
            {
                
//座標情報を無理やり色に変換

                
//x軸をr(赤)に、y軸をg(緑)、z軸をb(青)に代入する

                return fixed4(i.screenPos.x, i.screenPos.y, i.screenPos.z, 1);
            }
分かりやすく四角形で座標と色の関係をまとめると次の通りです。
四角形でわかりやすくRGBを開設

コードを少し解説

最初に、使いたい関数を使うのに必要なコンポーネントをincludeしています。
C#でいうusingと同じような処理です。
            
//後述のComputeScreenPos関数に必要な宣言

            #include "UnityCG.cginc"

出力頂点構造体の方にのみ、ピクセルシェーダーに渡す変数を追加しています。
                
//スクリーン座標を保存してピクセルシェーダーに伝えるために追加

                float4 screenPos : TEXCOORD0;
この変数には頂点シェーダー内でスクリーン座標を代入します。

下がその、実際にスクリーン座標を代入している処理です。
                
// クリップ座標を正規化してスクリーン座標に変換

                o.screenPos = ComputeScreenPos(o.vertex);

最後にスクリーン座標を無理やり色に変換して完成。
                
//座標情報を無理やり色に変換

                
//x軸をr(赤)に、y軸をg(緑)、z軸をb(青)に代入する

                return fixed4(i.screenPos.x, i.screenPos.y, i.screenPos.z, 1);
0
0