夜風のMixedReality

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

ゼロから始めるUnityShader開発 オブジェクトとの距離に応じてフェードがかかるシェーダー

本日はShader学習枠です。

今回はShaderを使用してオブジェクトを描画しているカメラとの距離に応じてフェードを書ける表現を行っていきます。

これはMixedRealityGraphicsToolのStandardShaderではNearFadeと呼ばれる機能に当たります。

redhologerbera.hatenablog.com

〇ワールド座標の取得

カメラの位置とオブジェクトの距離を比較するためにはオブジェクトのワールド座標の取得が必要です。

これはTransformObjectToWorld()を使用します。(ここではURPのCore.hlslを使用しています。)

     struct appdata
            {
              ・・・
            };

            struct v2f
            {
     ・・・
                float3 positionWS : TEXCOORD1;
            };
  v2f vert(appdata v)
            {
                v2f o;
                o.positionWS = TransformObjectToWorld(v.vertex).xyz;
                ・・・
                o.vertex = TransformObjectToHClip(v.vertex);
                return o;
            }

これによってpositionWSにはオブジェクトのワールド座標が取得されます。

〇カメラ位置を取得する_WorldSpaceCameraPos

Unityでは_WorldSpaceCameraPosという変数を使用することでカメラのワールド座標が取得できます。

これと先ほど頂点シェーダーで取得したオブジェクトのワールド座標の差分をとることで距離を取得できます。

具体的なフラグメントシェーダーのコードは以下になります。

 float4 frag(v2f i) : SV_Target
            {
                float3 cameraPositionWs = _WorldSpaceCameraPos.xyz;

                float distance = length(cameraPositionWs - i.positionWS);
                // sample the texture
                float4 col = tex2D(_MainTex, i.uv);
                float coefficient = saturate(distance * _Distance);
                col.a *= coefficient;
                return col;
            }

これによってカメラが近づけば近づくほどα値が0に近づいていきます。

〇コード全文

Shader "Unlit/CameraDistanceFade"
{
    Properties
    {
        _Distance("Distance",float) = 1
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Transparent"
            "Queue"="Transparent"
        }
        LOD 100
        blend SrcAlpha OneMinusSrcAlpha

        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;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 positionWS : TEXCOORD1;
            };

            float _Distance;
            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert(appdata v)
            {
                v2f o;
                o.positionWS = TransformObjectToWorld(v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.vertex = TransformObjectToHClip(v.vertex);
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                float3 cameraPositionWs = _WorldSpaceCameraPos.xyz;

                float distance = length(cameraPositionWs - i.positionWS);
                // sample the texture
                float4 col = tex2D(_MainTex, i.uv);
                float coefficient = saturate(distance * _Distance);
                col.a *= coefficient;
                return col;
            }
            ENDHLSL
        }
    }
}