UE中通过深度缓冲重建世界空间坐标原理和Unity shader重建原理基本一致,但是UE中重建世界坐标的实现路径与Unity是不一致的 :
• Unity中使用SAMPLE_DEPTH_TEXTUR采样的是原始深度值(RawDepth),是一个范围[0,1]的非线性深度值;UE中SceneDepth节点获取的是真实距离的线性深度(Linearepth),单位是厘米。
• Unity和UE的坐标系不同,Unity是左手坐标系,Y轴向上 (Y-Up),Z轴向前;UE是左手坐标系,Z轴向上 (Z-Up),X轴向前。这意味着Unity和UE的矩阵内容不同,Unity 的逆矩阵和 UE 的逆矩阵,里面的 16 个数字是不一样的;Clip Space 方向不同,Unity 的 UV 原点通常在左下角 (OpenGL) 或左上角 (DX),UE 的 UV 原点在左上角。这会导致 Y 轴方向可能需要1 - y反转。
• Unity和UE的单位不一致,Unity的世界单位是米,UE的世界单位是厘米,因此按照Unity的路径重建出来是 (0, 1, 0),在 UE 里重建出来则是 (0, 0, 100)。如果不缩放,特效大小会差 100 倍
因此在UE中通过深度缓冲重建世界坐标,建议使用射线法:
1. 射线法
原理公式:P´ = C + ->v * Depth / ->v * ->f
如图所示,P是像素的屏幕空间位置(ScreenPosition),P´是像素的世界空间位置(WorldPosition);C是相机的世界空间位置(CameraPosition);->v是相机指向像素P视线的向量(CameraVector),->f是相机朝向向量(CameraDirrction);Depth是像素P的深度值。由向量->v点乘向量->f可得向量->v、->f的夹角θ的余弦值cosθ,Depth/cosθ获取CP´长度。向量->v* 距离CP´获得向量->CP´,向量->CP´只表示P´到相机C的相对距离,要获取P´在世界空间中的绝对位置,还需要加上相机C的世界空间坐标,即可确定像素P在世界空间中的位置P´。公式如下:
UE节点连线图:
2. 逆矩阵重建
UE中通过逆矩阵重建世界坐标,基本逻辑和Unity一致,由裁剪空间逆矩阵反推至世界空间,但在具体执行层面与Unity不一样
2.1 实现方法
UE中没有提供逆矩阵相关节点,因此需要使用CustomNode输入代码实现逆矩阵
//1.采样:获取纹理坐标,自动适配动态分辨率 (Screen Percentage) //GetSceneTextureUV 为UE内置函数,用于采样屏幕空间UV坐标 float2 ScreenUV = GetSceneTextureUV(Parameters); //获取 DeviceZ (采样0 ~ 1 的非线性深度) float deviceZ = LookupDeviceZ(ScreenUV); //2.几何重建 //获取NDC空间坐标,GetScreenPosition UE内置函数,直接获取NDC空间坐标 float2 ndcPos = GetScreenPosition(Parameters).xy; //通过NDC坐标构建裁剪空间齐次坐标 float4 ClipPos = float4(ndcPos, deviceZ, 1.0); //3.空间变换(Transform) //逆投影矩阵,由裁剪空间齐次坐标转为平移世界空间坐标 float4 TranslatedWorldPosH = mul(ClipPos, ResolvedView.ClipToTranslatedWorld); //透视除法(归一化),还原为平移世界空间笛卡尔2坐标 TranslatedWorldPos = TranslatedWorldPosH / TranslatedWorldPosH.w; //4.LWC还原(LWC Restore) //获取平移世界坐标偏移量 float3 PreViewTranslation = LWCToFloat(ResolvedView.PreViewTranslation); //还原绝对世界坐标 float3 WorldPos = TranslatedPos.xyz - PreViewTranslation; return WorldPos;2.2 平移世界空间 (Translated World Space)
平移世界空间 (Translated World Space) 是 Unreal Engine (UE) 渲染管线中一个非常独特且核心的概念。它是 “以相机为原点,但坐标轴方向与世界保持一致” 的坐标系。
在计算机图形学中,GPU处理顶点和像素位置时,通常使用32位浮点数 (Float32)。Float32有一个致命弱点:数值越大,精度越低。如一个超大开放世界游戏中,玩家走到地图边缘(比如坐标1000000, 1000000),此时如果直接使用绝对世界坐标进行渲染计算:模型会开始疯狂抖动(顶点乱跳)、阴影会变成锯齿状或消失、物理计算会崩溃。为了解决这个问题,UE采用了一个聪明的策略:既然GPU处理大数值精度低,那我就强行让所有计算都发生在原点 (0,0,0) 附近。
• 绝对世界空间:世界原点固定不动;相机可能飞到十万八千里外;精度风险:高
• 平移世界空间:强行把世界原点移动到相机所在的位置,在渲染每一帧时,引擎会计算一个偏移量 PreViewTranslation(大约等于 - CameraPosition),所有的物体坐标,都加上这个偏移量,无论玩家走到地图哪里,在GPU看来,相机永远在 (0,0,0) 附近,所有要渲染的物体也都在相机附近。数值永远很小,精度永远完美。