33
33
* [8] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
34
34
*/
35
35
36
+ vec3 ToWorld(vec3 X, vec3 Y, vec3 Z, vec3 V)
37
+ {
38
+ return V.x * X + V.y * Y + V.z * Z;
39
+ }
40
+
41
+ vec3 ToLocal(vec3 X, vec3 Y, vec3 Z, vec3 V)
42
+ {
43
+ return vec3 (dot (V, X), dot (V, Y), dot (V, Z));
44
+ }
45
+
36
46
float FresnelMix(Material mat, float eta, vec3 V, vec3 L, vec3 H)
37
47
{
38
48
float metallicFresnel = SchlickFresnel(abs (dot (L, H)));
39
49
float dielectricFresnel = DielectricFresnel(abs (dot (V, H)), eta);
40
50
return mix (dielectricFresnel, metallicFresnel, mat.metallic);
41
51
}
42
52
43
- vec3 EvalDiffuse(Material mat, vec3 Csheen, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf)
53
+ vec3 EvalDiffuse(Material mat, vec3 Csheen, vec3 V, vec3 L, vec3 H, inout float pdf)
44
54
{
45
55
pdf = 0.0 ;
46
- if (dot (N, L) <= 0.0 )
56
+ if (L.z <= 0.0 )
47
57
return vec3 (0.0 );
48
58
49
59
// Diffuse
50
- float FL = SchlickFresnel(dot (N, L) );
51
- float FV = SchlickFresnel(dot (N, V) );
60
+ float FL = SchlickFresnel(L.z );
61
+ float FV = SchlickFresnel(V.z );
52
62
float FH = SchlickFresnel(dot (L, H));
53
63
float Fd90 = 0.5 + 2.0 * dot (L, H) * dot (L, H) * mat.roughness;
54
64
float Fd = mix (1.0 , Fd90, FL) * mix (1.0 , Fd90, FV);
55
65
56
66
// Fake Subsurface TODO: Replace with volumetric scattering
57
67
float Fss90 = dot (L, H) * dot (L, H) * mat.roughness;
58
68
float Fss = mix (1.0 , Fss90, FL) * mix (1.0 , Fss90, FV);
59
- float ss = 1.25 * (Fss * (1.0 / (dot (N, L) + dot (N, V) ) - 0.5 ) + 0.5 );
69
+ float ss = 1.25 * (Fss * (1.0 / (L.z + V.z ) - 0.5 ) + 0.5 );
60
70
61
71
// Sheen
62
72
vec3 Fsheen = FH * mat.sheen * Csheen;
63
73
64
- pdf = dot (N, L) * INV_PI;
74
+ pdf = L.z * INV_PI;
65
75
return (INV_PI * mix (Fd, ss, mat.subsurface) * mat.baseColor + Fsheen) * (1.0 - mat.metallic) * (1.0 - mat.specTrans);
66
76
}
67
77
68
- vec3 EvalSpecReflection(Material mat, float eta, vec3 specCol, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf)
78
+ vec3 EvalSpecReflection(Material mat, float eta, vec3 specCol, vec3 V, vec3 L, vec3 H, inout float pdf)
69
79
{
70
80
pdf = 0.0 ;
71
- if (dot (N, L) <= 0.0 )
81
+ if (L.z <= 0.0 )
72
82
return vec3 (0.0 );
73
83
74
84
float FM = FresnelMix(mat, eta, V, L, H);
75
85
vec3 F = mix (specCol, vec3 (1.0 ), FM);
76
- float D = GTR2(dot (N, H) , mat.roughness);
77
- float G = SmithG(abs (dot (N, L) ), mat.roughness)
78
- * SmithG(abs (dot (N, V) ), mat.roughness);
86
+ float D = GTR2(H.z , mat.roughness);
87
+ float G = SmithG(abs (L.z ), mat.roughness)
88
+ * SmithG(abs (V.z ), mat.roughness);
79
89
80
- pdf = D * dot (N, H) / (4.0 * abs (dot (V, H)));
90
+ pdf = D * H.z / (4.0 * abs (dot (V, H)));
81
91
return F * D * G;
82
92
}
83
93
84
- vec3 EvalSpecRefraction(Material mat, float eta, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf)
94
+ vec3 EvalSpecRefraction(Material mat, float eta, vec3 V, vec3 L, vec3 H, inout float pdf)
85
95
{
86
96
pdf = 0.0 ;
87
- if (dot (N, L) >= 0.0 )
97
+ if (L.z >= 0.0 )
88
98
return vec3 (0.0 );
89
99
90
100
float F = DielectricFresnel(abs (dot (V, H)), eta);
91
- float D = GTR2(dot (N, H) , mat.roughness);
101
+ float D = GTR2(H.z , mat.roughness);
92
102
float denomSqrt = dot (L, H) + dot (V, H) * eta;
93
- float G = SmithG(abs (dot (N, L) ), mat.roughness)
94
- * SmithG(abs (dot (N, V) ), mat.roughness);
103
+ float G = SmithG(abs (L.z ), mat.roughness)
104
+ * SmithG(abs (V.z ), mat.roughness);
95
105
96
- pdf = D * dot (N, H) * abs (dot (L, H)) / (denomSqrt * denomSqrt);
106
+ pdf = D * H.z * abs (dot (L, H)) / (denomSqrt * denomSqrt);
97
107
vec3 specColor = pow (mat.baseColor, vec3 (0.5 ));
98
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);
99
109
}
100
110
101
- vec3 EvalClearcoat(Material mat, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf)
111
+ vec3 EvalClearcoat(Material mat, vec3 V, vec3 L, vec3 H, inout float pdf)
102
112
{
103
113
pdf = 0.0 ;
104
- if (dot (N, L) <= 0.0 )
114
+ if (L.z <= 0.0 )
105
115
return vec3 (0.0 );
106
116
107
117
float FH = DielectricFresnel(dot (V, H), 1.0 / 1.5 );
108
118
float F = mix (0.04 , 1.0 , FH);
109
- float D = GTR1(dot (N, H) , mat.clearcoatRoughness);
110
- float G = SmithG(dot (N, L) , 0.25 )
111
- * SmithG(dot (N, V) , 0.25 );
112
- pdf = D * dot (N, H) / (4.0 * dot (V, H));
119
+ float D = GTR1(H.z , mat.clearcoatRoughness);
120
+ float G = SmithG(L.z , 0.25 )
121
+ * SmithG(V.z , 0.25 );
122
+ pdf = D * H.z / (4.0 * dot (V, H));
113
123
return vec3 (0.25 * mat.clearcoat * F * D * G);
114
124
}
115
125
@@ -162,61 +172,60 @@ vec3 DisneySample(State state, vec3 V, vec3 N, inout vec3 L, inout float pdf)
162
172
163
173
vec3 T, B;
164
174
Onb(N, T, B);
175
+ // NDotL = L.z; NDotV = V.z; NDotH = H.z
176
+ V = ToLocal(T, B, N, V);
165
177
166
178
if (r1 < cdf[0 ]) // Diffuse Reflection Lobe
167
179
{
168
180
r1 /= cdf[0 ];
169
181
L = CosineSampleHemisphere(r1, r2);
170
- L = T * L.x + B * L.y + N * L.z;
171
182
172
183
vec3 H = normalize (L + V);
173
184
174
- f = EvalDiffuse(state.mat, sheenCol, V, N, L, H, pdf);
185
+ f = EvalDiffuse(state.mat, sheenCol, V, L, H, pdf);
175
186
pdf *= diffuseWt;
176
187
}
177
188
else if (r1 < cdf[1 ]) // Specular Reflection Lobe
178
189
{
179
190
r1 = (r1 - cdf[0 ]) / (cdf[1 ] - cdf[0 ]);
180
191
vec3 H = SampleGTR2(state.mat.roughness, r1, r2);
181
- H = T * H.x + B * H.y + N * H.z;
182
192
183
193
if (dot (V, H) < 0.0 )
184
194
H = - H;
185
195
186
196
L = normalize (reflect (- V, H));
187
197
188
- f = EvalSpecReflection(state.mat, state.eta, specCol, V, N, L, H, pdf);
198
+ f = EvalSpecReflection(state.mat, state.eta, specCol, V, L, H, pdf);
189
199
pdf *= specReflectWt;
190
200
}
191
201
else if (r1 < cdf[2 ]) // Specular Refraction Lobe
192
202
{
193
203
r1 = (r1 - cdf[1 ]) / (cdf[2 ] - cdf[1 ]);
194
204
vec3 H = SampleGTR2(state.mat.roughness, r1, r2);
195
- H = T * H.x + B * H.y + N * H.z;
196
205
197
206
if (dot (V, H) < 0.0 )
198
207
H = - H;
199
208
200
209
L = normalize (refract (- V, H, state.eta));
201
210
202
- f = EvalSpecRefraction(state.mat, state.eta, V, N, L, H, pdf);
211
+ f = EvalSpecRefraction(state.mat, state.eta, V, L, H, pdf);
203
212
pdf *= specRefractWt;
204
213
}
205
214
else // Clearcoat Lobe
206
215
{
207
216
r1 = (r1 - cdf[2 ]) / (1.0 - cdf[2 ]);
208
217
vec3 H = SampleGTR1(state.mat.clearcoatRoughness, r1, r2);
209
- H = T * H.x + B * H.y + N * H.z;
210
218
211
219
if (dot (V, H) < 0.0 )
212
220
H = - H;
213
221
214
222
L = normalize (reflect (- V, H));
215
223
216
- f = EvalClearcoat(state.mat, V, N, L, H, pdf);
224
+ f = EvalClearcoat(state.mat, V, L, H, pdf);
217
225
pdf *= clearcoatWt;
218
226
}
219
227
228
+ L = ToWorld(T, B, N, L);
220
229
return f * abs (dot (N, L));
221
230
}
222
231
@@ -225,11 +234,14 @@ vec3 DisneyEval(State state, vec3 V, vec3 N, vec3 L, inout float bsdfPdf)
225
234
bsdfPdf = 0.0 ;
226
235
vec3 f = vec3 (0.0 );
227
236
228
- float NDotL = dot (N, L);
229
- float NDotV = dot (N, V);
237
+ vec3 T, B;
238
+ Onb(N, T, B);
239
+ // NDotL = L.z; NDotV = V.z; NDotH = H.z
240
+ V = ToLocal(T, B, N, V);
241
+ L = ToLocal(T, B, N, L);
230
242
231
243
vec3 H;
232
- if (NDotL > 0.0 )
244
+ if (L.z > 0.0 )
233
245
H = normalize (L + V);
234
246
else
235
247
H = normalize (L + V * state.eta);
@@ -249,32 +261,32 @@ vec3 DisneyEval(State state, vec3 V, vec3 N, vec3 L, inout float bsdfPdf)
249
261
float pdf;
250
262
251
263
// Diffuse
252
- if (diffuseWt > 0.0 && NDotL > 0.0 )
264
+ if (diffuseWt > 0.0 && L.z > 0.0 )
253
265
{
254
- f += EvalDiffuse(state.mat, sheenCol, V, N, L, H, pdf);
266
+ f += EvalDiffuse(state.mat, sheenCol, V, L, H, pdf);
255
267
bsdfPdf += pdf * diffuseWt;
256
268
}
257
269
258
270
// Specular Reflection
259
- if (specReflectWt > 0.0 && NDotL > 0.0 && NDotV > 0.0 )
271
+ if (specReflectWt > 0.0 && L.z > 0.0 && V.z > 0.0 )
260
272
{
261
- f += EvalSpecReflection(state.mat, state.eta, specCol, V, N, L, H, pdf);
273
+ f += EvalSpecReflection(state.mat, state.eta, specCol, V, L, H, pdf);
262
274
bsdfPdf += pdf * specReflectWt;
263
275
}
264
276
265
277
// Specular Refraction
266
- if (specRefractWt > 0.0 && NDotL < 0.0 )
278
+ if (specRefractWt > 0.0 && L.z < 0.0 )
267
279
{
268
- f += EvalSpecRefraction(state.mat, state.eta, V, N, L, H, pdf);
280
+ f += EvalSpecRefraction(state.mat, state.eta, V, L, H, pdf);
269
281
bsdfPdf += pdf * specRefractWt;
270
282
}
271
283
272
284
// Clearcoat
273
- if (clearcoatWt > 0.0 && NDotL > 0.0 && NDotV > 0.0 )
285
+ if (clearcoatWt > 0.0 && L.z > 0.0 && V.z > 0.0 )
274
286
{
275
- f += EvalClearcoat(state.mat, V, N, L, H, pdf);
287
+ f += EvalClearcoat(state.mat, V, L, H, pdf);
276
288
bsdfPdf += pdf * clearcoatWt;
277
289
}
278
290
279
- return f * abs (dot (N, L) );
291
+ return f * abs (L.z );
280
292
}
0 commit comments