夜風のMixedReality

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

SpatialMeshにサイバーな影を落とすシェーダーを開発する HoloLensアドベントカレンダー2022 18日目

本日はHoloLensの表現実験枠です。

昨日開発したSpatialMeshのシェーダーを改造していきます。

〇HoloLens 2022年アドベントカレンダー

 HoloLens 2022年アドベントカレンダーはQiita上で私の師であるがち本さんが開催している企画です。

 クリスマスまで毎日記事を埋めていくことが目的で本日は18日目の記事になります。

qiita.com

〇SpatialMeshに影を落とす

昨日はSpatialMeshに影を落とす表現を実装しました。

redhologerbera.hatenablog.com

今回はこれを改造して影の見た目を変えれるようにしていきます。

〇TriplanerMapping

SpatialMeshはテクスチャを張るためのUVを持ち合わせていません。

そのため普通にサンプリングを行うことができないためTriplanerMappingと呼ばれる手法を使用します。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

TriplanerMapingはUVを無視してUnityのワールド座標ベースにサンプリングを行うことができる手法です。

 TriplanerMapingの詳細は本記事では省きますので前述の過去の記事を参考にしてください。

float4 col= tex2D(_CyberTex,uvX)*triplanarBlend.x + tex2D(_CyberTex,uvY)* triplanarBlend.y+tex2D(_CyberTex,uvZ)*triplanarBlend.z;

colはのちに影以外が0(黒)になります。最後に掛け合わせることで影部分のみにテクスチャが反映されるようになります。

〇実機で確認

今回はラメ上のテクスチャでcyberな雰囲気を再現しました。

youtu.be

〇ソースコード

Shader "Unlit/SpatialShadow"
{
    Properties
    {
        _CyberTex("CyberTex",2D) = "white"{}
        _ShadowColor("ShadowColor",color) = (1,1,1,1)
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
            "Queue"="Geometry-1"
        }

       // ColorMask R


        ZWrite On
        ZTest LEqual

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            struct appdata
            {
                float4 vertex : POSITION;
                half3 normal: NORMAL;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 position : SV_POSITION;
                float3 normalWS : TEXCOORD1;
                float4 shadowCoord : TEXCOORD3;
                float3 worldNormal:COLOR3;
                float3 triplanaerNormal : COLOR4;
            float4 triplanaerPosition : TEXCOORD6;
                UNITY_VERTEX_OUTPUT_STEREO
            };
            float4 _MainColor;
            float4  _ShadowColor;
            sampler2D _CyberTex;
            float4 _CyberTex_ST;
            v2f vert(appdata input)
            {
                v2f output;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

                
                output.position = TransformObjectToHClip(input.vertex);;
                 VertexNormalInputs normal = GetVertexNormalInputs(input.normal);
                output.normalWS = normal.normalWS;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz);//追加
                output.shadowCoord = GetShadowCoord(vertexInput);//追加
                output.triplanaerNormal = normal.normalWS;
                output.triplanaerPosition = mul(unity_ObjectToWorld, input.vertex).xyzw;
                return output;
            }

            float4 frag(v2f input) : SV_Target
            {
                 //TriplanaerSettings
            float3 triplanarBlend = pow(abs(input.normalWS),1);
            triplanarBlend/=dot(triplanarBlend,half3(1,1,1));
            float2 uvX = input.triplanaerPosition.zy * _CyberTex_ST.xy+_CyberTex_ST.zw;
            float2 uvY = input.triplanaerPosition.xz * _CyberTex_ST.xy+_CyberTex_ST.zw;
            float2 uvZ = input.triplanaerPosition.xy *_CyberTex_ST.xy+_CyberTex_ST.zw;

            float3 axisSign = input.normalWS <0? -1 : 1;
            uvX*=axisSign.x;
            uvY*=axisSign.y;
            uvZ*=axisSign.z;
                   float4 col= tex2D(_CyberTex,uvX)*triplanarBlend.x + tex2D(_CyberTex,uvY)* triplanarBlend.y+tex2D(_CyberTex,uvZ)*triplanarBlend.z;
                //Light.hlslで提供されるUnityのライトを取得する関数
                Light lt = GetMainLight(input.shadowCoord);

                float4 lightColor = float4(lt.color, 1)*(lt.distanceAttenuation * lt.shadowAttenuation);
                col *=  abs(1-saturate(lightColor.r));
                return col;
            }
            ENDHLSL
        }
    }
}