版本:Unity 6 (6000.0)
语言:英语
在 URP 中的可视化法向量着色器
URP 中的着色器方法

在 URP 的着色器中重构世界空间位置

本例中的 Unity 着色器在 GPU 上运行的程序。更多信息
词汇表 中查看
使用深度纹理和屏幕空间 UV 坐标为 像素计算机图像中的最小单位。像素大小取决于你的屏幕分辨率。像素光照在每个屏幕像素上进行计算。更多信息
词汇表 中查看
重构世界空间位置。着色器在一个 网格Unity 的主要图形基元。网格构成了大量 3D 世界。Unity 支持三角化或四边形多边形网格。必须将 Nurbs、Nurms、细分曲面转换为多边形。更多信息
词汇表 中查看
上绘制棋盘格图案以可视化位置。

以下图示展示了最终成果

Checkerboard pattern visualizing the reconstructed world space positions.
可视化重构世界空间位置的棋盘格图案。

本页包含以下各章节

创建示例场景

创建示例 场景场景包含了游戏的环境和菜单。将每个唯一的场景文件看作一个独特的关卡。在每个场景中,你放置环境、障碍物和装饰品,实质上逐个部分地设计和构建你的游戏。更多信息
词汇表 中查看
来按照本部分中的步骤操作

  1. 将 URP 安装到现有的 Unity 项目中,或使用 通用项目模板 创建新的项目。

  2. 在示例场景中,创建一个平面 GameObjectUnity 场景中的基本对象,可以表示角色、道具、场景、照相机、路径点等等。GameObject 的功能由附加到它的组件定义。更多信息
    词汇表 中查看
    ,并放置它,使其遮挡一些 GameObject。

    Create a plane
    创建一个平面
  3. 新建一个材质并将其指派给平面。

  4. 新建一个着色器并将其指派给材质。从页面中复制代码并粘贴 Unity 着色器源代码 URP 无光照基本着色器

  5. 选择 URP 资源。

  6. 在 URP 资源的常规部分中,启用深度纹理

    In URP Asset, enable Depth Texture
    在 URP 资源中,启用深度纹理
  7. 打开你在步骤 4 中创建的着色器。

编辑 ShaderLab 代码

本节假设你已从页面 URP 无光照基本着色器 中复制了源代码。

ShaderLab用于定义着色器对象的结构的 Unity 语言。 了解更多信息
参阅 词汇表
代码进行以下更改

  1. HLSLPROGRAM 块中,添加深度纹理着色器标头的包含声明。例如,将其置于对 Core.hlsl 的现有包含声明下方。

    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    
    // The DeclareDepthTexture.hlsl file contains utilities for sampling the Camera
    // depth texture.
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
    

    DeclareDepthTexture.hlsl 文件包含用于采样 摄像机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。 了解更多信息
    参阅 词汇表
    深度纹理的函数。此示例使用 SampleSceneDepth 函数来对像素的 Z 坐标进行采样。

  2. 在片段着色器定义中,添加 Varyings IN 作为输入。

    half4 frag(Varyings IN) : SV_Target
    

    在此示例中,片段着色器使用 Varyings 结构中的 positionHCS 属性来获取像素的位置。

  3. 在片段着色器中,为对 深度缓冲区存储图像中每个像素的 z 值深度的内存存储,其中 z 值是投影平面中每个渲染像素的深度。 了解更多信息
    参阅 词汇表
    进行采样,将像素位置除以渲染目标分辨率 _ScaledScreenParams。属性 _ScaledScreenParams.xy 考虑了渲染目标的任何缩放,例如 动态分辨率允许你动态缩放各个渲染目标的摄像机设置,以降低 GPU 的工作负载。 了解更多信息
    参阅 词汇表

    float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;
    
  4. 在片段着色器中,使用 SampleSceneDepth 函数对深度缓冲区进行采样。

    #if UNITY_REVERSED_Z
        real depth = SampleSceneDepth(UV);
    #else
        // Adjust z to match NDC for OpenGL
        real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
    #endif
    

SampleSceneDepth 函数来自 DeclareDepthTexture.hlsl 文件。它返回范围 [0, 1] 中的 Z 值。

要使重建函数 (ComputeWorldSpacePosition) 生效,深度值必须处于归一化设备坐标 (NDC) 空间中。在 D3D 中,Z 处于 [0,1] 范围内,而在 OpenGL 中,Z 处于 [-1, 1] 范围内。

本例使用 UNITY_REVERSED_Z 常量来确定平台,并调整 Z 值范围。请参阅本例中的步骤 6 以了解更详细的说明。

UNITY_NEAR_CLIP_VALUE 变量是用于剪切空间平台无关的近 剪裁平面限制照相机从其当前位置观察的远近的平面。照相机的可视范围介于远剪裁平面和近剪裁平面之间。请参阅远剪裁平面和近剪裁平面。 更多信息
术语表 中查看
值。

有关更多信息,请参阅 特定平台渲染差异

  1. 从像素的 UV 和 Z 坐标重建世界空间位置。

    float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
    

    ComputeWorldSpacePosition 是从 UV 和深度 (Z) 值计算世界空间位置的实用函数。该函数在 SRP Core 包的 Common.hlsl 文件中定义。

    UNITY_MATRIX_I_VP 是将点从剪切空间转换到世界空间的逆视点投影矩阵。

  2. 要可视化像素的世界空间位置,请创建棋盘格效果。

    uint scale = 10;
    uint3 worldIntPos = uint3(abs(worldPos.xyz * scale));
    bool white = (worldIntPos.x & 1) ^ (worldIntPos.y & 1) ^ (worldIntPos.z & 1);
    half4 color = white ? half4(1,1,1,1) : half4(0,0,0,1);
    

    scale 是棋盘格图案大小的逆缩放。

    abs 函数将图案镜像到负坐标侧。

    worldIntPos 变量的 uint3 声明将坐标位置捕捉到整数。

    表达式 <integer value> & 1 中的 AND 运算符检查该值是偶数 (0) 还是奇数 (1)。该表达式允许代码将表面划分为正方形。

    表达式 <integer value> ^ <integer value> 中的 XOR 运算符反转正方形颜色。

    深度缓冲区对于未渲染几何体的区域可能没有有效值。以下代码在这些区域中绘制黑色。

    #if UNITY_REVERSED_Z
        if(depth < 0.0001)
            return half4(0,0,0,1);
    #else
        if(depth > 0.9999)
            return half4(0,0,0,1);
    #endif
    

    不同平台对 远剪裁平面照相机的最大平移距离。不渲染超出此值定义平面的几何体。该平面垂直于照相机的正前方 (Z) 方向。
    术语表 中查看
    (0 == 远或 1 == 远) 使用不同的 Z 值。UNITY_REVERSED_Z 常量允许代码正确处理所有平台。

    保存着色器代码,示例准备就绪。

以下图示展示了最终成果

3D Checkerboard
3D 棋盘格

完整的 ShaderLab 代码

以下为此示例提供了完整的 ShaderLab 代码。

// This Unity shader reconstructs the world space positions for pixels using a depth
// texture and screen space UV coordinates. The shader draws a checkerboard pattern
// on a mesh to visualize the positions.
Shader "Example/URPReconstructWorldPos"
{
    Properties
    { }

    // The SubShader block containing the Shader code.
    SubShader
    {
        // SubShader Tags define when and under which conditions a SubShader block or
        // a pass is executed.
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }

        Pass
        {
            HLSLPROGRAM
            // This line defines the name of the vertex shader.
            #pragma vertex vert
            // This line defines the name of the fragment shader.
            #pragma fragment frag

            // The Core.hlsl file contains definitions of frequently used HLSL
            // macros and functions, and also contains #include references to other
            // HLSL files (for example, Common.hlsl, SpaceTransforms.hlsl, etc.).
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            // The DeclareDepthTexture.hlsl file contains utilities for sampling the
            // Camera depth texture.
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"

            // This example uses the Attributes structure as an input structure in
            // the vertex shader.
            struct Attributes
            {
                // The positionOS variable contains the vertex positions in object
                // space.
                float4 positionOS   : POSITION;
            };

            struct Varyings
            {
                // The positions in this struct must have the SV_POSITION semantic.
                float4 positionHCS  : SV_POSITION;
            };

            // The vertex shader definition with properties defined in the Varyings
            // structure. The type of the vert function must match the type (struct)
            // that it returns.
            Varyings vert(Attributes IN)
            {
                // Declaring the output object (OUT) with the Varyings struct.
                Varyings OUT;
                // The TransformObjectToHClip function transforms vertex positions
                // from object space to homogenous clip space.
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                // Returning the output.
                return OUT;
            }

            // The fragment shader definition.
            // The Varyings input structure contains interpolated values from the
            // vertex shader. The fragment shader uses the `positionHCS` property
            // from the `Varyings` struct to get locations of pixels.
            half4 frag(Varyings IN) : SV_Target
            {
                // To calculate the UV coordinates for sampling the depth buffer,
                // divide the pixel location by the render target resolution
                // _ScaledScreenParams.
                float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;

                // Sample the depth from the Camera depth texture.
                #if UNITY_REVERSED_Z
                    real depth = SampleSceneDepth(UV);
                #else
                    // Adjust Z to match NDC for OpenGL ([-1, 1])
                    real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
                #endif

                // Reconstruct the world space positions.
                float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);

                // The following part creates the checkerboard effect.
                // Scale is the inverse size of the squares.
                uint scale = 10;
                // Scale, mirror and snap the coordinates.
                uint3 worldIntPos = uint3(abs(worldPos.xyz * scale));
                // Divide the surface into squares. Calculate the color ID value.
                bool white = ((worldIntPos.x) & 1) ^ (worldIntPos.y & 1) ^ (worldIntPos.z & 1);
                // Color the square based on the ID value (black or white).
                half4 color = white ? half4(1,1,1,1) : half4(0,0,0,1);

                // Set the color to black in the proximity to the far clipping
                // plane.
                #if UNITY_REVERSED_Z
                    // Case for platforms with REVERSED_Z, such as D3D.
                    if(depth < 0.0001)
                        return half4(0,0,0,1);
                #else
                    // Case for platforms without REVERSED_Z, such as OpenGL.
                    if(depth > 0.9999)
                        return half4(0,0,0,1);
                #endif

                return color;
            }
            ENDHLSL
        }
    }
}
在 URP 中的可视化法向量着色器
URP 中的着色器方法