kingBook

导航

URP 编写自定义 Shader (5) 从深度纹理重建像素的世界空间位置

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.7/manual/writing-shaders-urp-reconstruct-world-position.html

// 此 Unity 着色器使用深度纹理和屏幕空间 UV 坐标来重建
//像素的世界空间位置。该着色器在网格上绘制棋盘图案,
//使位置可视化。
Shader "Example/URPReconstructWorldPos"
{
    Properties
    { 
    }

    // 包含 Shader 代码的 SubShader 代码块。
    SubShader
    {
        // SubShader Tags 定义何时以及在何种条件下执行某个 SubShader 代码块
        // 或某个通道。
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }

        Pass
        {
            HLSLPROGRAM
            // 此行定义顶点着色器的名称。
            #pragma vertex vert
            // 此行定义片元着色器的名称。
            #pragma fragment frag

            // Core.hlsl 文件包含常用的 HLSL 宏和
            // 函数的定义,还包含对其他 HLSL 文件(例如
            // Common.hlsl、SpaceTransforms.hlsl 等)的#include 引用。
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            // DeclareDepthTexture.hlsl 文件包含用于对摄像机深度纹理进行采样的
            // 实用程序。
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"

            // 此示例使用 Attributes 结构作为顶点着色器中的
            // 输入结构。
            struct Attributes
            {
                // positionOS 变量包含对象空间中的顶点
                // 位置。
                float4 positionOS   : POSITION;
            };

            struct Varyings
            {
                // 此结构中的位置必须具有 SV_POSITION 语义。
                float4 positionCS  : SV_POSITION;
            };

            // 顶点着色器定义具有在 Varyings 结构中定义的
            // 属性。vert 函数的类型必须与它返回的类型(结构)
            // 匹配。
            Varyings vert(Attributes input)
            {
                // 使用 Varyings 结构声明输出对象 (output)。
                Varyings output;
                // TransformObjectToHClip 函数将顶点位置
                // 从对象空间变换到齐次裁剪空间。
                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                // 返回输出。
                return output;
            }

            // 片元着色器定义。
            // Varyings 输入结构包含来自顶点着色器的
            // 插值。片元着色器使用 `Varyings` 结构中的
            // `positionCS` 属性来获取像素的位置。
            half4 frag(Varyings input) : SV_Target
            {
                // 要计算用于采样深度缓冲区的 UV 坐标,
                // 请将像素位置除以渲染目标分辨率
                // _ScaledScreenParams。
                float2 UV = input.positionCS.xy / _ScaledScreenParams.xy;

                // 从摄像机深度纹理中采样深度。
                #if UNITY_REVERSED_Z
                    real depth = SampleSceneDepth(UV);
                #else
                    //  调整 Z 以匹配 OpenGL 的 NDC ([-1, 1])
                    real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
                #endif

                // 重建世界空间位置。
                float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);

                // 以下部分创建棋盘效果。
                // 比例是平方反比。
                uint scale = 10;
                // 缩放、镜像和捕捉坐标。
                uint3 worldIntPos = uint3(abs(worldPos.xyz * scale));
                // 将表面划分为正方形。计算颜色 ID 值。
                bool white = ((worldIntPos.x) & 1) ^ (worldIntPos.y & 1) ^ (worldIntPos.z & 1);
                // 根据 ID 值(黑色或白色)为正方形着色。
                half4 output = white ? half4(1,1,1,1) : half4(0,0,0,1);

                // 在远裁剪面附近将颜色设置为
                // 黑色。
                #if UNITY_REVERSED_Z
                    // 具有 REVERSED_Z 的平台(如 D3D)的情况。
                    if(depth < 0.0001)
                        return half4(0,0,0,1);
                #else
                    // 没有 REVERSED_Z 的平台(如 OpenGL)的情况。
                    if(depth > 0.9999)
                        return half4(0,0,0,1);
                #endif

                return output;
            }
            ENDHLSL
        }
    }
}

posted on 2022-02-14 23:33  kingBook  阅读(441)  评论(0编辑  收藏  举报