本例中的 Unity 着色器在 GPU 上运行的程序。更多信息
在 词汇表 中查看使用深度纹理和屏幕空间 UV 坐标为 像素计算机图像中的最小单位。像素大小取决于你的屏幕分辨率。像素光照在每个屏幕像素上进行计算。更多信息
在 词汇表 中查看 重构世界空间位置。着色器在一个 网格Unity 的主要图形基元。网格构成了大量 3D 世界。Unity 支持三角化或四边形多边形网格。必须将 Nurbs、Nurms、细分曲面转换为多边形。更多信息
在 词汇表 中查看 上绘制棋盘格图案以可视化位置。
以下图示展示了最终成果
本页包含以下各章节
创建示例 场景场景包含了游戏的环境和菜单。将每个唯一的场景文件看作一个独特的关卡。在每个场景中,你放置环境、障碍物和装饰品,实质上逐个部分地设计和构建你的游戏。更多信息
在 词汇表 中查看 来按照本部分中的步骤操作
将 URP 安装到现有的 Unity 项目中,或使用 通用项目模板 创建新的项目。
在示例场景中,创建一个平面 GameObjectUnity 场景中的基本对象,可以表示角色、道具、场景、照相机、路径点等等。GameObject 的功能由附加到它的组件定义。更多信息
在 词汇表 中查看,并放置它,使其遮挡一些 GameObject。
新建一个材质并将其指派给平面。
新建一个着色器并将其指派给材质。从页面中复制代码并粘贴 Unity 着色器源代码 URP 无光照基本着色器。
选择 URP 资源。
在 URP 资源的常规部分中,启用深度纹理
。
打开你在步骤 4 中创建的着色器。
本节假设你已从页面 URP 无光照基本着色器 中复制了源代码。
对 ShaderLab用于定义着色器对象的结构的 Unity 语言。 了解更多信息
参阅 词汇表 代码进行以下更改
在 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 坐标进行采样。
在片段着色器定义中,添加 Varyings IN
作为输入。
half4 frag(Varyings IN) : SV_Target
在此示例中,片段着色器使用 Varyings
结构中的 positionHCS
属性来获取像素的位置。
在片段着色器中,为对 深度缓冲区存储图像中每个像素的 z 值深度的内存存储,其中 z 值是投影平面中每个渲染像素的深度。 了解更多信息
参阅 词汇表 进行采样,将像素位置除以渲染目标分辨率 _ScaledScreenParams
。属性 _ScaledScreenParams.xy
考虑了渲染目标的任何缩放,例如 动态分辨率允许你动态缩放各个渲染目标的摄像机设置,以降低 GPU 的工作负载。 了解更多信息
参阅 词汇表。
float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;
在片段着色器中,使用 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
变量是用于剪切空间平台无关的近 剪裁平面限制照相机从其当前位置观察的远近的平面。照相机的可视范围介于远剪裁平面和近剪裁平面之间。请参阅远剪裁平面和近剪裁平面。 更多信息
在 术语表 中查看 值。
有关更多信息,请参阅 特定平台渲染差异。
从像素的 UV 和 Z 坐标重建世界空间位置。
float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
ComputeWorldSpacePosition
是从 UV 和深度 (Z) 值计算世界空间位置的实用函数。该函数在 SRP Core 包的 Common.hlsl
文件中定义。
UNITY_MATRIX_I_VP
是将点从剪切空间转换到世界空间的逆视点投影矩阵。
要可视化像素的世界空间位置,请创建棋盘格效果。
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
常量允许代码正确处理所有平台。
保存着色器代码,示例准备就绪。
以下图示展示了最终成果
以下为此示例提供了完整的 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
}
}
}