雅各比矩阵
以下是为您设计的虚幻引擎焦散材质方案,其核心思路是利用表面法线扰动计算光线折射路径的微小变化,并用雅可比矩阵的行列式表示光线能量密度的变化。这个方案只需一次法线贴图采样,计算开销较低。
雅可比矩阵在这里描述 "光线偏移量对表面位置的局部敏感性":
其中
| 物理量 | 近似计算 | 目的 |
|---|---|---|
| 折射方向 | 切线空间直接计算(避免坐标系转换) | 减少运算量 |
| 雅可比行列式 | 屏幕空间梯度 (ddx/ddy) |
避免解析求导,单次采样 |
| 能量守恒 | $\text{intensity} = 1.0 / \max( | \det(J) |
// 在Material Function "CausticCore" 内的 HLSL 代码
void CausticCore(
float3 NormalTS, // 切线空间法线
float IOR, // 折射率 (1.0-2.0)
float Distance, // 到焦平面的距离 (单位:米)
out float2 Offset, // 焦平面上的UV偏移
out float Intensity // 焦散强度 (0.0-10.0)
)
{
// Step 1: 计算折射方向 (切线空间)
float3 LightDir = float3(0, 0, 1); // 垂直入射光
float eta = 1.0 / IOR;
float3 RefractedDir = refract(LightDir, NormalTS, eta);
// Step 2: 计算焦平面偏移量
float z = RefractedDir.z;
if (abs(z) < 0.001) z = 0.001; // 避免除零
Offset = -Distance * RefractedDir.xy / z;
// Step 3: 计算雅可比行列式 (屏幕空间)
float2 dOffsetdx = ddx(Offset);
float2 dOffsetdy = ddy(Offset);
float detJ = dOffsetdx.x * dOffsetdy.y - dOffsetdx.y * dOffsetdy.x;
// Step 4: 计算能量密度
float energy = 1.0 / max(abs(detJ), 0.001);
float focus = saturate(dot(NormalTS, LightDir)); // 法线影响因子
Intensity = energy * focus * 0.1; // 缩放强度
}
[法线贴图采样] --> [切线空间法线]
↓
[参数输入] -IOR-> [CausticCore]-->[Offset]-->[焦散贴图UV偏移]
-Distance-> ↓
[Intensity]-->(*)--->[最终颜色]
↑
[焦散贴图采样]------------+
ddx/ddy代替解析偏导数saturate()限幅防止数值溢出💡 实时演示效果:当表面凹凸剧烈时,
det(J)变化剧烈,形成明亮的焦散图案;平坦区域则呈现均匀光照
这种基于雅可比矩阵的解法在计算开销和物理精确度间取得了平衡,非常适合实时渲染需求。实践中可通过调整距离参数控制焦散图案的锐利度。