Skip to content

Commit 39210c2

Browse files
committed
upd
1 parent 244a3bb commit 39210c2

4 files changed

Lines changed: 74 additions & 2 deletions

File tree

content/posts/foundation/pt-6-path-tracing-adventures.md

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
author: mos9527
3-
lastmod: 2025-12-25T14:38:21.895757
3+
lastmod: 2025-12-25T15:47:09.160054
44
title: Foundation 施工笔记 【6】- 路径追踪
55
tags: ["CG","Vulkan","Foundation"]
66
categories: ["CG","Vulkan"]
@@ -1082,11 +1082,83 @@ float3 f = (Fss + Fms) * mfDistrib.D(wm) * mfDistrib.G(wo, wi) / (4 * AbsCosThet
10821082
return BSDFSample(f, wi, pdf, BxDFFlags::GlossyReflection);
10831083
```
10841084
1085-
#### 效果
1085+
##### 导体效果
10861086
10871087
一样的白炉测试效果如下。先令所有`metallic=1.0f`,即只看specular lobe:
10881088
10891089
![image-20251225143740725](/image-foundation/image-20251225143740725.png)
10901090
10911091
(注:别忘了Sampler用CLAMP_TO_EDGE - -||)
1092+
1093+
##### 电介质表现
1094+
1095+
目前为止,我们只对不存在(不考虑:导体中折射即吸收)折射贡献的BRDF做了改进。对于电介质BRDF(及metal<1),这里的工作是不够的:因为算$E$的时候并没有看「折射」后的能量问题。
1096+
1097+
有一个问题就是这里的参数多了个IOR,ImageWorks (Kulla, Conty)提出使用3D材质查表,但回忆glTF定义:我们材质的IOR是常数$1.5$——这里再次省掉一个维度。
1098+
1099+
###### 电介质$E(\mu)$
1100+
1101+
回顾之前不考虑$F$(设$F=1$)的$E$计算,和其对应离散/蒙特卡洛形式:
1102+
$$
1103+
E(\mu_0) = \int_{0}^{2\pi}{d\phi}\int_{0}^{1}f(\mu_0, \mu_i)\mu_id\mu_i = \frac{1}{N}\sum \frac{f(\mu_o, \mu_i)\mu_i}{p(\mu_i)}
1104+
$$
1105+
和之前一样,这里引入$F$即可;鉴于我们使用Shlick形式且IOR=1.5,则有:
1106+
$$
1107+
F = f_0 + (f_{90} - f_{0}) \times (1.0 - \cos\theta)^5
1108+
$$
1109+
1110+
麻烦,多了个$f_0$;不妨拆成几个项,记:
1111+
$$
1112+
\lambda(\theta) = (1.0-\cos\theta)^5
1113+
$$
1114+
我们求的是:
1115+
$$
1116+
E(\mu_0) = \int_{0}^{2\pi}{d\phi}\int_{0}^{1}F(w_o \cdot w_m)f(\mu_0, \mu_i)\mu_id\mu_i \newline
1117+
$$
1118+
1119+
化简:
1120+
$$
1121+
E(\mu_0) = f_0 \int_{0}^{2\pi}{d\phi}\int_{0}^{1}f(\mu_0, \mu_i)\mu_id\mu_i + (f_{90}-f_0) \int_{0}^{2\pi}{d\phi}\int_{0}^{1}\lambda(w_o \cdot w_m)f(\mu_0, \mu_i)\mu_id\mu_i
1122+
$$
1123+
常数$f_0,f_{90}$完全可以拖出来。此外,注意到左边积分还是之前$E$的形式;右边多了个$\lambda$,额外记一个表算即可。我们记右边(不包括$f_0,f_{90}$的积分为$E\prime$,离散形式为:
1124+
$$
1125+
E\prime(\mu_0) = \int_{0}^{1}\lambda(w_o \cdot w_m)f(\mu_0, \mu_i)\mu_id\mu_i = \frac{1}{N}\sum \frac{\lambda(w_o \cdot w_m)f(\mu_o, \mu_i)\mu_i}{p(\mu_i)}
1126+
$$
1127+
和之前计算相比改动很小。直接贴代码:
1128+
1129+
```c++
1130+
// sampleGGX_E 额外输出 VdotH
1131+
float3 wo = float3(sqrt(1.0 - cosTheta * cosTheta), 0.0, cosTheta);
1132+
if (mfDistrib.EffectivelySmooth()){
1133+
float3 wi = float3(-wo.x, -wo.y, wo.z);
1134+
float3 wm = normalize(wo + wi);
1135+
VdotH = AbsDot(wo, wm);
1136+
return 1.0f; // Dirac delta - though we're counting energy, so return 1
1137+
}
1138+
float3 wm = mfDistrib.Sample_wm(wo, u);
1139+
VdotH = AbsDot(wo, wm);
1140+
// integrateGGX_E 多一项 Eprime
1141+
for (uint i = 0; i < kSamples;i++) {
1142+
float cosTheta = clamp(u, 1e-4, 1.0f);
1143+
float rough = clamp(v, 1e-4, 1.0f);
1144+
float3 wi;
1145+
float VdotH;
1146+
float sample = sampleGGX_E(rough, cosTheta, rng.sample(), rng.sample2D(), VdotH);
1147+
float lambda = pow(1 - VdotH, 5);
1148+
E += sample;
1149+
Eprime += lambda * sample;
1150+
samples += 1.0f;
1151+
}
1152+
ggxE[dot(p, uint2(1, 32))] = float2(E / samples, Eprime / samples);
1153+
```
1154+
1155+
跑出来是这样的。参照不太好找,不过 Filament [5.3.4.3 The DFG1 and DFG2 term visualize](https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/processinglightprobes) 做了类似的事情:事实上我们的$E\prime$和$DFG_2$是一致的,对比如下(作为对比:R实际为(1-F)*E, 同时这里的Y轴有翻转处理以对齐Filament结果)
1156+
1157+
| Filament | Ours |
1158+
| -------------------------------------------- | ------------------------------------------------------------ |
1159+
| ![img](/image-foundation/filament-dfg12.png) | ![image-20251225154559371](/image-foundation/image-20251225154559371.png) |
1160+
1161+
参照物被压缩的有点惨,不过可以看出来含义是一样的。
1162+
1163+
10921164
<h1 style="color:red">--- 施工中 ---</h1>
14.6 KB
Loading
41.6 KB
Loading
474 KB
Loading

0 commit comments

Comments
 (0)