Version: 6000.3
语言: 中文
在通用渲染管线着色器中编写仅深度通道
URP 中的着色器方法

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

团结着色器在 GPU 上运行的程序。更多信息
请参阅术语表
在此示例中,重建像素计算机图像中的最小单位。像素大小取决于您的屏幕分辨率。像素光照是在每个屏幕像素下计算的。更多信息
请参阅术语表
使用深度纹理和屏幕空间UV坐标。着色器在meshUnity 的主要图形原语。网格体构成了 3D 世界的很大一部分。Unity 支持三角或四边形多边形网格。Nurbs、Nurms、Subdiv 曲面必须转换为多边形。更多信息
请参阅术语表
以可视化位置。

下图显示了最终结果:

棋盘图案可视化重建的世界空间位置。
棋盘图案可视化重建的世界空间位置。

此页面包含以下部分:

创建示例场景

创建示例场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
要按照本节中的步骤作:

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

  2. 在示例场景中,创建一个平面游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
    请参阅术语表
    并放置它,使其遮挡一些游戏对象。

    创建平面
    创建平面
  3. 创建一个新材质并将其分配给平面。

  4. 创建一个新的着色器并将其分配给材质。从 URP unlit 基本着色器页面复制并粘贴 Unity 着色器源代码。

  5. 选择 URP 资产。

  6. 在URP资产的 常规(General) 分段中,启用Depth Texture.

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

编辑ShaderLab代码

本部分假定你从URP unlit basic shader页面复制了源代码。

ShaderLabUnity 用于定义 Shader 对象结构的语言。更多信息
请参阅术语表
法典:

  1. HLSLPROGRAM块中,为深度纹理着色器标头添加 include 声明。例如,将其放在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
    

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

  3. 在片段着色器中,要计算用于采样的 UV 坐标深度缓冲区 保存图像中每个像素的 z 值深度的内存存储,其中 z 值是投影平面中每个呈现像素的深度。更多信息
    请参阅术语表
    ,将像素位置除以渲染目标分辨率_ScaledScreenParams.该物业_ScaledScreenParams.xy考虑渲染目标的任何缩放,例如动态分辨率(Dynamic Resolution)摄像机设置,允许你动态缩放单个渲染目标,以减少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文件。它返回范围内的 Z 值[0, 1].

对于重建函数 (ComputeWorldSpacePosition) 才能工作,深度值必须位于规范化设备坐标 (NDC) 空间中。在 D3D 中,Z 在范围内[0,1],在 OpenGL 中,Z 在范围内[-1, 1].

此示例使用UNITY_REVERSED_Z常量来确定平台并调整 Z 值范围。查看此示例中的步骤 6 以获取更多说明。

UNITY_NEAR_CLIP_VALUEvariable 是一个独立于平台的 near剪切平面限制摄像机从当前位置可以看到的距离或距离的平面。摄像机的可视范围介于远裁剪平面和近裁剪平面之间。查看远剪切平面和近剪切平面。更多信息
请参阅术语表
值。

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

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

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

    ComputeWorldSpacePosition是一个实用函数,它根据 UV 和深度 (Z) 值计算世界空间位置。此函数在Common.hlslSRP Core 包的文件。

    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函数将图案镜像到负坐标侧。

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

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

    XOR运算符<integer value> ^ <integer value>翻转方形颜色。

    深度缓冲区可能没有用于未呈现几何图形的区域的有效值。以下代码在此类区域中绘制黑色。

    #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 值远剪切平面相机的最大绘制距离。超出此值定义的平面的几何体不会被渲染。该平面垂直于摄像机的前向 (Z) 方向。
    请参阅术语表
    (0 == far,或 1 == far)。这UNITY_REVERSED_Zconstant 允许代码正确处理所有平台。

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

下图显示了最终结果:

3D 棋盘格
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 中的着色器方法