HLSL法线、高度、深度、世界坐标互转

Jason Ma

作为 TA,在做各种特殊材质时经常会用到 Depth 和 Normal Buffer,以及 Depth 转 WorldPos / Normal 等等操作,趁编译引擎时在这里做个笔记,包含 UE 和 Unity 中一些常用的代码片段方便日后查阅。

相关知识这篇文章中有非常详细的介绍,如有重复不再赘述,如有疑问或疏漏欢迎提出。
Unity Shader-深度相关知识总结与效果实现(LinearDepth,Reverse Z,世界坐标重建,软粒子,高度雾,运动模糊,扫描线效果)_puppet_master 的博客-CSDN 博客

Depth to World Position

方法有很多,这里只记录最方便且通用的逆矩阵方式,如果需要更高性能可以参考射线插值的方法。

Unity

// TODO

UE

Custom Node Code:

1
2
3
// Input ScreenPos (or ClipPos) : min -1 max 1, LinearDepth : View Space Z
float4 HomogeneousWorldPosition = mul(float4(ScreenPos * LinearDepth, LinearDepth, 1), View.ScreenToWorld);
AbsoluteWorldPos = HomogeneousWorldPosition.xyz / HomogeneousWorldPosition.w;

World Position to Depth

所谓的 Depth 代码中常见的分为 LinearDepth 和 DeviceDepth(Unity 中的 EyeDepth)。
LinearDepth 顾名思义直接等于 ViewSpace 的线性深度,Min/Max 分别为 Near/Far Clip Plane,需要注意浮点精度问题,某些情况下可能需要 abs()。
DeviceDepth(EyeDepth)是指经过投影变换后的 Depth,也就是 ClipPos.z,一些常见的知识点在上面的参考文章中都有非常详细的总结。

Unity

// TODO

UE

1
2
3
4
5
6
float3 RelativeWorldPos = AbsoluteWorldPos + View.PreViewTranslation;
float3 ViewPos = mul(float4(RelativeWorldPos, w), View.TranslatedWorldToView).xyz;
float4 ClipPos = mul(float4(ViewPos, w), View.ViewToClip);
ClipPos = ClipPos / ClipPos.w;
LinearDepth = ViewPos.z;
DeviceDepth = ClipPos.z;

World Position to Normal

详细可以参考以下文章:
Improved normal reconstruction from depth
这里只介绍使用 ddxy 重建法线,故只能在 Fragment Shader 使用,且没有插值。

World Space

1
WorldNormal = normalize(cross(ddx(WorldPos), ddy(WorldPos)));

Transform to Tangent Space

Shader 中一旦涉及 Tangent Space 或 Normal Map,那肯定离不开 float3x3 TangentToWorld 矩阵,TangentToWorld 的[0]、[1]、[2]分别对应 World Space 的 Tangent、Binormal、Normal,也就是 TBN 矩阵(UE 中称为 BTN,但实际值是一样的)。
TBN 是正交矩阵,故有以下用法:

  • Tangent to World:mul(TangentDir, TBN)(左乘) == mul(transpose(TBN), TangentDir) (右乘)
  • World to Tangent:mul(WorldDir, transpose(TBN))(左乘) == mul(TBN, WorldDir) (右乘)
1
TangentNormal = mul(TBN, WorldNormal);

等同于:

Depth to Normal(?)

Height to Normal
如无必要,勿增实体——不要重复造轮子。

Unity

Normal From Height Node | Shader Graph | 6.9.2

UE

  • Title: HLSL法线、高度、深度、世界坐标互转
  • Author: Jason Ma
  • Created at: 2021-11-03 10:23:21
  • Updated at: 2023-07-16 22:55:35
  • Link: https://elysium.jason-ma.com/2021/11/03/TA/HLSL法线、高度、深度、世界坐标互转/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments