夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

ゼロから始めるUnityShader開発 第五章 スクリーン座標の取得

本日はShader学習枠です。

前回はUnityワールド座標を取得してワールド座標に対してのピクセルの位置で処理を変えていきました。

redhologerbera.hatenablog.com

今回はカメラに映る画面に対してのピクセルの位置関係で処理を変えていきます。

〇スクリーン座標とは

スクリーン座標(スクリーンスペース)とはUnityのカメラによって描画されている画面に対しての座標を指す言葉です。

カメラによって映し出されている画面に対しての座標のため、xRの場合ユーザーの視界に対して常についてくる座標になります。

まずはスクリーン座標に対して描画を行うようなシェーダーを記述します。

〇頂点シェーダーの処理

座標変換はこれまで同様頂点シェーダーで行います。

スクリーン座標の取得はComputeScreenPos()というシェーダーマクロを使用することが一般的でしたが

URPになり、処理を見ると非推奨であると表記されています。

// Deprecated: A confusingly named and duplicate function that scales clipspace to unity NDC range. (-w < x(-y) < w --> 0 < xy < w)
// Use GetVertexPositionInputs().positionNDC instead for vertex shader
// Or a similar function in Common.hlsl, ComputeNormalizedDeviceCoordinatesWithZ()
float4 ComputeScreenPos(float4 positionCS)
{
    float4 o = positionCS * 0.5f;
    o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w;
    o.zw = positionCS.zw;
    return o;
}

代わりにGetVertexPositionInputs().positionNDCを使用します。

GetVertexPositionInputs(頂点)で頂点変換に関するシェーダーマクロがあらかた使用できます。

 そのためここではTransformObjectToHClip()による頂点変換もまとめてしまいます。

 次のようになります。

            v2f vert (appdata v)
            {
                v2f o;
              //  o.vertex = TransformObjectToHClip(v.vertex);
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex);
                o.vertex = vertexInput.positionCS;
              //  o.pos = ComputeScreenPos(o.vertex);
                o.pos = vertexInput.positionNDC;
                return o;
            }

これによってfloat4 pos :TEXCOORD0で定義されているposにスクリーン座標が格納されます。

〇フラグメントシェーダーの処理

今回はスクリーン座標に対してテクスチャのサンプリングを行います。

この場合tex2Dproj()というHLSLで提供される関数を使用します。

 float4 col = tex2Dproj(_MainTex,i.pos)

learn.microsoft.com

これは投影によるテクスチャのサンプリングを行う関数です。

これによってスクリーン座標に対してサンプリングが行われます。

スクリーン座標でのサンプリングではカメラの位置に応じてモデルへの描画が変わります。

本日は以上です。

〇シェーダーコード一覧

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
           #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            struct appdata
            {
                float4 vertex : POSITION;
            };


            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 pos : TEXCOORD0;
            };

            sampler2D _MainTex;
            
            v2f vert (appdata v)
            {
                v2f o;
              //  o.vertex = TransformObjectToHClip(v.vertex);
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex);
                o.vertex = vertexInput.positionCS;
              //  o.pos = ComputeScreenPos(o.vertex);
                o.pos = vertexInput.positionNDC;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = tex2Dproj(_MainTex,i.pos);
                return col;
            }
            ENDHLSL
        }
    }
}