Skip to content

Commit 1120ba7

Browse files
Sample distribution of visible normals (VNDF)
1 parent 17eb961 commit 1120ba7

File tree

2 files changed

+27
-22
lines changed

2 files changed

+27
-22
lines changed

src/shaders/common/disney.glsl

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
* [3] https://github.com/wdas/brdf/blob/main/src/brdfs/disney.brdf
2929
* [4] https://github.com/mmacklin/tinsel/blob/master/src/disney.h
3030
* [5] http://simon-kallweit.me/rendercompo2015/report/
31-
* [6] http://shihchinw.github.io/2015/07/implementing-disney-principled-brdf-in-arnold.html
32-
* [7] https://github.com/mmp/pbrt-v4/blob/0ec29d1ec8754bddd9d667f0e80c4ff025c900ce/src/pbrt/bxdfs.cpp#L76-L286
33-
* [8] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
31+
* [6] https://github.com/mmp/pbrt-v4/blob/0ec29d1ec8754bddd9d667f0e80c4ff025c900ce/src/pbrt/bxdfs.cpp#L76-L286
32+
* [7] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
33+
* [8] https://jcgt.org/published/0007/04/01/paper.pdf
3434
*/
3535

3636
vec3 ToWorld(vec3 X, vec3 Y, vec3 Z, vec3 V)
@@ -84,11 +84,12 @@ vec3 EvalSpecReflection(Material mat, float eta, vec3 specCol, vec3 V, vec3 L, v
8484
float FM = FresnelMix(mat, eta, V, L, H);
8585
vec3 F = mix(specCol, vec3(1.0), FM);
8686
float D = GTR2(H.z, mat.roughness);
87-
float G = SmithG(abs(L.z), mat.roughness)
88-
* SmithG(abs(V.z), mat.roughness);
87+
float G1 = SmithG(abs(V.z), mat.roughness);
88+
float G2 = G1 * SmithG(abs(L.z), mat.roughness);
89+
float jacobian = 1.0 / (4.0 * dot(V, H));
8990

90-
pdf = D * H.z / (4.0 * abs(dot(V, H)));
91-
return F * D * G;
91+
pdf = G1 * max(0.0, dot(V, H)) * D * jacobian / V.z;
92+
return F * D * G2 / (4.0 * L.z * V.z);
9293
}
9394

9495
vec3 EvalSpecRefraction(Material mat, float eta, vec3 V, vec3 L, vec3 H, inout float pdf)
@@ -99,13 +100,16 @@ vec3 EvalSpecRefraction(Material mat, float eta, vec3 V, vec3 L, vec3 H, inout f
99100

100101
float F = DielectricFresnel(abs(dot(V, H)), eta);
101102
float D = GTR2(H.z, mat.roughness);
102-
float denomSqrt = dot(L, H) + dot(V, H) * eta;
103-
float G = SmithG(abs(L.z), mat.roughness)
104-
* SmithG(abs(V.z), mat.roughness);
105-
106-
pdf = D * H.z * abs(dot(L, H)) / (denomSqrt * denomSqrt);
103+
float denom = dot(L, H) + dot(V, H) * eta;
104+
denom *= denom;
105+
float G1 = SmithG(abs(V.z), mat.roughness);
106+
float G2 = G1 * SmithG(abs(L.z), mat.roughness);
107+
float jacobian = abs(dot(L, H)) * eta * eta / denom;
108+
109+
pdf = G1 * max(0.0, dot(V, H)) * D * jacobian / V.z;
110+
107111
vec3 specColor = pow(mat.baseColor, vec3(0.5));
108-
return specColor * (1.0 - mat.metallic) * mat.specTrans * (1.0 - F) * D * G * abs(dot(V, H)) * abs(dot(L, H)) * eta * eta * 4.0 / (denomSqrt * denomSqrt);
112+
return specColor * (1.0 - mat.metallic) * mat.specTrans * (1.0 - F) * D * G2 * abs(dot(V, H)) * abs(dot(L, H)) * eta * eta / (denom * abs(L.z) * abs(V.z));
109113
}
110114

111115
vec3 EvalClearcoat(Material mat, vec3 V, vec3 L, vec3 H, inout float pdf)
@@ -119,8 +123,10 @@ vec3 EvalClearcoat(Material mat, vec3 V, vec3 L, vec3 H, inout float pdf)
119123
float D = GTR1(H.z, mat.clearcoatRoughness);
120124
float G = SmithG(L.z, 0.25)
121125
* SmithG(V.z, 0.25);
122-
pdf = D * H.z / (4.0 * dot(V, H));
123-
return vec3(0.25 * mat.clearcoat * F * D * G);
126+
float jacobian = 1.0 / (4.0 * dot(V, H));
127+
128+
pdf = D * H.z * jacobian;
129+
return vec3(0.25) * mat.clearcoat * F * D * G / (4.0 * L.z * V.z);
124130
}
125131

126132
void GetSpecColor(Material mat, float eta, inout vec3 specCol, inout vec3 sheenCol)
@@ -188,7 +194,7 @@ vec3 DisneySample(State state, vec3 V, vec3 N, inout vec3 L, inout float pdf)
188194
else if (r1 < cdf[1]) // Specular Reflection Lobe
189195
{
190196
r1 = (r1 - cdf[0]) / (cdf[1] - cdf[0]);
191-
vec3 H = SampleGTR2(state.mat.roughness, r1, r2);
197+
vec3 H = SampleGGXVNDF(V, state.mat.roughness, r1, r2);
192198

193199
if (dot(V, H) < 0.0)
194200
H = -H;
@@ -201,7 +207,7 @@ vec3 DisneySample(State state, vec3 V, vec3 N, inout vec3 L, inout float pdf)
201207
else if (r1 < cdf[2]) // Specular Refraction Lobe
202208
{
203209
r1 = (r1 - cdf[1]) / (cdf[2] - cdf[1]);
204-
vec3 H = SampleGTR2(state.mat.roughness, r1, r2);
210+
vec3 H = SampleGGXVNDF(V, state.mat.roughness, r1, r2);
205211

206212
if (dot(V, H) < 0.0)
207213
H = -H;

src/shaders/common/sampling.glsl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,24 @@ vec3 SampleGTR2(float rgh, float r1, float r2)
6767
return vec3(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta);
6868
}
6969

70-
vec3 sampleGGXVNDF(vec3 V, float rgh, float r1, float r2)
70+
vec3 SampleGGXVNDF(vec3 V, float rgh, float r1, float r2)
7171
{
72-
7372
vec3 Vh = normalize(vec3(rgh * V.x, rgh * V.y, V.z));
7473

7574
float lensq = Vh.x * Vh.x + Vh.y * Vh.y;
7675
vec3 T1 = lensq > 0 ? vec3(-Vh.y, Vh.x, 0) * inversesqrt(lensq) : vec3(1, 0, 0);
7776
vec3 T2 = cross(Vh, T1);
7877

7978
float r = sqrt(r1);
80-
float phi = 2.0 * M_PI * r2;
79+
float phi = 2.0 * PI * r2;
8180
float t1 = r * cos(phi);
8281
float t2 = r * sin(phi);
8382
float s = 0.5 * (1.0 + Vh.z);
8483
t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
8584

8685
vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh;
8786

88-
return normalize(vec3(rgh * Nh.x, rgh * Nh.y, std::max<float>(0.0, Nh.z)));
87+
return normalize(vec3(rgh * Nh.x, rgh * Nh.y, max(0.0, Nh.z)));
8988
}
9089

9190
float GTR2Aniso(float NDotH, float HDotX, float HDotY, float ax, float ay)
@@ -111,7 +110,7 @@ float SmithG(float NDotV, float alphaG)
111110
{
112111
float a = alphaG * alphaG;
113112
float b = NDotV * NDotV;
114-
return 1.0 / (NDotV + sqrt(a + b - a * b));
113+
return (2.0 * NDotV) / (NDotV + sqrt(a + b - a * b));
115114
}
116115

117116
float SmithGAniso(float NDotV, float VDotX, float VDotY, float ax, float ay)

0 commit comments

Comments
 (0)