在创建AR内容时,AR中显示的3D物体可以被地面、建筑物、障碍物等遮挡,也可以通过将3D物体的阴影投射到地面等,与摄像头获取的真实图像融为一体.可以做到。

您必须为 Unity 中的每个此类操作编写专用着色器。本文介绍通用渲染管线 (URP) 的着色器。

用于验证的 Unity 版本为 2020.3.39f1 和 2021.3.11f1。我对 Unity 的着色器并不完全熟悉,因此代码中可能存在一些不必要或遗漏的内容。

仅写入深度的着色器

要遮挡环境中的对象,例如地面、建筑物和障碍物,请在绘制要在 AR 中显示的 3D 对象之前仅绘制它们的深度。着色器如下所示:

WriteDepth.shader
Shader "WriteDepth"
{
    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalPipeline"
            "RenderType"="Opaque"
            "Queue"="Geometry-1"
        }

        Pass
        {
            Name "Pass"

            Cull Back
            Blend One Zero
            ZTest LEqual
            ZWrite On
            ColorMask 0

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 2.0

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
 
            struct Attributes
            {
                float4 positionOS : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
 
            struct Varyings
            {
                float4 positionCS               : SV_POSITION;
                float3 positionWS               : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };
 
            Varyings vert (Attributes input)
            {
                Varyings output = (Varyings)0;
 
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
 
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionCS = vertexInput.positionCS;
                output.positionWS = vertexInput.positionWS;
 
                return output;
            }
 
            half4 frag (Varyings input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
 
                return half4(1, 1, 1, 1);
            }

            ENDHLSL
        }
    }
}

"Queue"="Geometry-1" 在其他对象之前绘制,ColorMask 0 防止绘制颜色。

仅绘制阴影的着色器

创建一个仅绘制在 AR 中显示的 3D 对象的阴影的着色器。

DrawShadow.shader
Shader "DrawShadow"
{
    Properties
    {
        _ShadowColor ("Shadow Color", Color) = (0.5,0.5,0.5,1.0)
    }
 
    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalPipeline"
            "RenderType"="Transparent"
            "Queue"="Transparent-1"
        }
 
        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }
 
            Blend DstColor Zero, Zero One
            Cull Back
            ZTest LEqual
            ZWrite Off
   
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
 
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 2.0
 
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _SHADOWS_SOFT
            #pragma multi_compile_fog
 
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
 
            CBUFFER_START(UnityPerMaterial)
            float4 _ShadowColor;
            CBUFFER_END
 
            struct Attributes
            {
                float4 positionOS : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
 
            struct Varyings
            {
                float4 positionCS               : SV_POSITION;
                float3 positionWS               : TEXCOORD0;
                float fogCoord                  : TEXCOORD1;
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };
 
            Varyings vert (Attributes input)
            {
                Varyings output = (Varyings)0;
 
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
 
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionCS = vertexInput.positionCS;
                output.positionWS = vertexInput.positionWS;
                output.fogCoord = ComputeFogFactor(vertexInput.positionCS.z);
 
                return output;
            }
 
            half4 frag (Varyings input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
 
                half4 color = half4(1,1,1,1);
 
            #ifdef _MAIN_LIGHT_SHADOWS
                VertexPositionInputs vertexInput = (VertexPositionInputs)0;
                vertexInput.positionWS = input.positionWS;
 
                float4 shadowCoord = GetShadowCoord(vertexInput);
                half shadowAttenutation = MainLightRealtimeShadow(shadowCoord);
                color = lerp(half4(1,1,1,1), _ShadowColor, (1.0 - shadowAttenutation) * _ShadowColor.a);
                color.rgb = MixFogColor(color.rgb, half3(1,1,1), input.fogCoord);
            #endif
                return color;
            }
 
            ENDHLSL
        }
    }
}

下面论坛帖子中的代码是这样的。只绘制主光的阴影。
水着色图:透明度和阴影/通用渲染管线顺序 - Unity Forum

在 2021 版中,如果您删除 #ifdef _MAIN_LIGHT_SHADOWS 括号(如下文所述),它将起作用。

结果

在下面的场景中,如果您仅使用深度书写+阴影绘制一个白色对象,它将看起来像第二张图像。
【Unity】URPでDepthだけを書き込むシェーダー&影だけを描画するシェーダー
【Unity】URPでDepthだけを書き込むシェーダー&影だけを描画するシェーダー
为了应用两种材质,我复制了同一个对象并准备了两种,并为每个材质分配了一种用于深度书写的材质和一种仅用于绘制阴影的材质。

其他

Unity 提供的 ARFoundation 演示还提供了一个 ShaderGraph 用于显示阴影。
GitHub - Unity-Technologies/arfoundation-demos: AR Foundation 演示项目


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308628301.html

相关文章: