如何在Unity新PostProcessing栈的Shader中获取像素世界坐标?
获取Unity PostProcessing Shader中像素的世界空间坐标
要在Unity新的PostProcessing Shader框架里拿到像素对应的绝对世界XYZ坐标,核心是通过相机的矩阵逆变换,把屏幕空间的像素位置反向推导回世界空间。我给你修改好了测试Shader,每一步都加了注释,帮你理解逻辑:
Shader "Hidden/Filter/Test" { HLSLINCLUDE #include "../../PostProcessing/Shaders/StdLib.hlsl" TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex); // 新增:深度纹理与相机矩阵变量 TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture); float4x4 _CameraInvProjection; float4x4 _CameraInvView; float3 _WorldSpaceCameraPos; float4 Frag(VaryingsDefault i) : SV_Target { float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo); // 1. 将纹理坐标[0,1]转换为NDC归一化设备坐标[-1,1] float2 ndc = i.texcoordStereo * 2.0 - 1.0; // 2. 构造裁剪空间的射线齐次坐标(z=1表示远平面方向) float4 clipRay = float4(ndc.x, ndc.y, 1.0, 1.0); // 3. 用逆投影矩阵把裁剪射线转成视图空间射线 float4 viewRay = mul(_CameraInvProjection, clipRay); viewRay /= viewRay.w; // 透视除法还原真实视图空间坐标 // 4. 用逆视图矩阵把视图射线转成世界空间射线方向(忽略平移,只取方向) float3 worldRayDir = normalize(mul(_CameraInvView, float4(viewRay.xyz, 0.0)).xyz); // 5. 采样当前像素的非线性深度值 float depth = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo).r; // 6. 把非线性深度转成线性的视空间深度(单位:米) float linearDepth = LinearEyeDepth(depth); // 7. 计算最终世界空间坐标:相机位置 + 射线方向 × 深度距离 float3 worldPos = _WorldSpaceCameraPos + worldRayDir * linearDepth; // 调试用示例:把世界坐标映射到[0,1]范围输出到颜色通道 // color.rgb = worldPos / 20.0 + 0.5; // 可根据你的场景大小调整缩放系数 return color; } ENDHLSL SubShader { Cull Off ZWrite Off ZTest Always Pass { HLSLPROGRAM #pragma vertex VertDefault #pragma fragment Frag ENDHLSL } } }
关键逻辑说明:
- 深度纹理依赖:我们需要采样相机的
_CameraDepthTexture来获取每个像素的深度信息,确保你的相机Depth Texture Mode设置为Depth或Depth + Normals,PostProcessing框架会自动传递这个纹理。 - 矩阵逆变换:通过
_CameraInvProjection(相机逆投影矩阵)和_CameraInvView(相机逆视图矩阵),我们把屏幕空间的像素位置反向推导回世界空间的射线方向。 - 深度转换:Unity存储的深度是非线性的,必须用
LinearEyeDepth转换为线性的视空间深度,这样计算出来的世界坐标才是准确的。 - 正交相机兼容:这套逻辑同样适用于正交相机,矩阵变换和深度转换函数已经自动处理了正交投影的特殊情况。
内容的提问来源于stack exchange,提问作者Philipp Lenssen
相关产品推荐
相关产品推荐

