35
35
*/
36
36
37
37
// -----------------------------------------------------------------------
38
- void EvalDielectricReflection(State state, inout BsdfSampleRec bRec )
38
+ vec3 EvalDielectricReflection(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf )
39
39
// -----------------------------------------------------------------------
40
40
{
41
- if (dot (bRec. N, bRec. L) < 0.0 ) return ;
41
+ if (dot (N, L) < 0.0 ) return vec3 ( 0.0 ) ;
42
42
43
- float F = DielectricFresnel(dot (bRec. V, bRec. H), state.eta);
44
- float D = GTR2(dot (bRec. N, bRec. H), state.mat.roughness);
43
+ float F = DielectricFresnel(dot (V, H), state.eta);
44
+ float D = GTR2(dot (N, H), state.mat.roughness);
45
45
46
- bRec. pdf = D * dot (bRec. N, bRec. H) * F / (4.0 * dot (bRec. V, bRec. H));
46
+ pdf = D * dot (N, H) * F / (4.0 * dot (V, H));
47
47
48
- float G = SmithG_GGX(abs (dot (bRec. N, bRec. L)), state.mat.roughness) * SmithG_GGX(dot (bRec. N, bRec. V), state.mat.roughness);
49
- bRec.f = state.mat.albedo * F * D * G;
48
+ float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(dot (N, V), state.mat.roughness);
49
+ return state.mat.albedo * F * D * G;
50
50
}
51
51
52
52
// -----------------------------------------------------------------------
53
- void EvalDielectricRefraction(State state, inout BsdfSampleRec bRec )
53
+ vec3 EvalDielectricRefraction(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf )
54
54
// -----------------------------------------------------------------------
55
55
{
56
- float F = DielectricFresnel(abs (dot (bRec. V, bRec. H)), state.eta);
57
- float D = GTR2(dot (bRec. N, bRec. H), state.mat.roughness);
56
+ float F = DielectricFresnel(abs (dot (V, H)), state.eta);
57
+ float D = GTR2(dot (N, H), state.mat.roughness);
58
58
59
- float denomSqrt = dot (bRec. L, bRec. H) * state.eta + dot (bRec. V, bRec. H);
60
- bRec. pdf = D * dot (bRec. N, bRec. H) * (1.0 - F) * abs (dot (bRec. L, bRec. H)) / (denomSqrt * denomSqrt);
59
+ float denomSqrt = dot (L, H) * state.eta + dot (V, H);
60
+ pdf = D * dot (N, H) * (1.0 - F) * abs (dot (L, H)) / (denomSqrt * denomSqrt);
61
61
62
- float G = SmithG_GGX(abs (dot (bRec. N, bRec. L)), state.mat.roughness) * SmithG_GGX(dot (bRec. N, bRec. V), state.mat.roughness);
63
- bRec.f = state.mat.albedo * (1.0 - F) * D * G * abs (dot (bRec. V, bRec. H)) * abs (dot (bRec. L, bRec. H)) * 4.0 * state.eta * state.eta / (denomSqrt * denomSqrt);
62
+ float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(dot (N, V), state.mat.roughness);
63
+ return state.mat.albedo * (1.0 - F) * D * G * abs (dot (V, H)) * abs (dot (L, H)) * 4.0 * state.eta * state.eta / (denomSqrt * denomSqrt);
64
64
}
65
65
66
66
// -----------------------------------------------------------------------
67
- void EvalSpecular(State state, inout BsdfSampleRec bRec , vec3 Cspec0 )
67
+ vec3 EvalSpecular(State state, vec3 Cspec0, vec3 V , vec3 N, vec3 L, vec3 H, inout float pdf )
68
68
// -----------------------------------------------------------------------
69
69
{
70
- if (dot (bRec. N, bRec. L) < 0.0 ) return ;
70
+ if (dot (N, L) < 0.0 ) return vec3 ( 0.0 ) ;
71
71
72
- float D = GTR2_aniso(dot (bRec. N, bRec. H), dot (bRec. H, state.tangent), dot (bRec. H, state.bitangent), state.mat.ax, state.mat.ay);
73
- bRec. pdf = D * dot (bRec. N, bRec. H) / (4.0 * dot (bRec. V, bRec. H));
72
+ float D = GTR2_aniso(dot (N, H), dot (H, state.tangent), dot (H, state.bitangent), state.mat.ax, state.mat.ay);
73
+ pdf = D * dot (N, H) / (4.0 * dot (V, H));
74
74
75
- float FH = SchlickFresnel(dot (bRec. L, bRec. H));
75
+ float FH = SchlickFresnel(dot (L, H));
76
76
vec3 F = mix (Cspec0, vec3 (1.0 ), FH);
77
- float G = SmithG_GGX_aniso(dot (bRec. N, bRec. L), dot (bRec. L, state.tangent), dot (bRec. L, state.bitangent), state.mat.ax, state.mat.ay);
78
- G *= SmithG_GGX_aniso(dot (bRec. N, bRec. V), dot (bRec. V, state.tangent), dot (bRec. V, state.bitangent), state.mat.ax, state.mat.ay);
79
- bRec.f = F * D * G;
77
+ float G = SmithG_GGX_aniso(dot (N, L), dot (L, state.tangent), dot (L, state.bitangent), state.mat.ax, state.mat.ay);
78
+ G *= SmithG_GGX_aniso(dot (N, V), dot (V, state.tangent), dot (V, state.bitangent), state.mat.ax, state.mat.ay);
79
+ return F * D * G;
80
80
}
81
81
82
82
// -----------------------------------------------------------------------
83
- void EvalClearcoat(State state, inout BsdfSampleRec bRec )
83
+ vec3 EvalClearcoat(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout float pdf )
84
84
// -----------------------------------------------------------------------
85
85
{
86
- if (dot (bRec. N, bRec. L) < 0.0 ) return ;
86
+ if (dot (N, L) < 0.0 ) return vec3 ( 0.0 ) ;
87
87
88
- float D = GTR1(dot (bRec. N, bRec. H), state.mat.clearcoatRoughness);
89
- bRec. pdf = D * dot (bRec. N, bRec. H) / (4.0 * dot (bRec. V, bRec. H));
88
+ float D = GTR1(dot (N, H), state.mat.clearcoatRoughness);
89
+ pdf = D * dot (N, H) / (4.0 * dot (V, H));
90
90
91
- float FH = SchlickFresnel(dot (bRec. L, bRec. H));
91
+ float FH = SchlickFresnel(dot (L, H));
92
92
float F = mix (0.04 , 1.0 , FH);
93
- float G = SmithG_GGX(dot (bRec. N, bRec. L), 0.25 ) * SmithG_GGX(dot (bRec. N, bRec. V), 0.25 );
94
- bRec.f = vec3 (0.25 * state.mat.clearcoat * F * D * G);
93
+ float G = SmithG_GGX(dot (N, L), 0.25 ) * SmithG_GGX(dot (N, V), 0.25 );
94
+ return vec3 (0.25 * state.mat.clearcoat * F * D * G);
95
95
}
96
96
97
97
// -----------------------------------------------------------------------
98
- void EvalDiffuse(State state, inout BsdfSampleRec bRec , vec3 Csheen )
98
+ vec3 EvalDiffuse(State state, vec3 Csheen, vec3 V , vec3 N, vec3 L, vec3 H, inout float pdf )
99
99
// -----------------------------------------------------------------------
100
100
{
101
- if (dot (bRec. N, bRec. L) < 0.0 ) return ;
101
+ if (dot (N, L) < 0.0 ) return vec3 ( 0.0 ) ;
102
102
103
- bRec. pdf = dot (bRec. N, bRec. L) * (1.0 / PI);
103
+ pdf = dot (N, L) * (1.0 / PI);
104
104
105
- float FL = SchlickFresnel(dot (bRec. N, bRec. L));
106
- float FV = SchlickFresnel(dot (bRec. N, bRec. V));
107
- float FH = SchlickFresnel(dot (bRec. L, bRec. H));
108
- float Fd90 = 0.5 + 2.0 * dot (bRec. L, bRec. H) * dot (bRec. L, bRec. H) * state.mat.roughness;
105
+ float FL = SchlickFresnel(dot (N, L));
106
+ float FV = SchlickFresnel(dot (N, V));
107
+ float FH = SchlickFresnel(dot (L, H));
108
+ float Fd90 = 0.5 + 2.0 * dot (L, H) * dot (L, H) * state.mat.roughness;
109
109
float Fd = mix (1.0 , Fd90, FL) * mix (1.0 , Fd90, FV);
110
110
vec3 Fsheen = FH * state.mat.sheen * Csheen;
111
- bRec.f = ((1.0 / PI) * Fd * (1.0 - state.mat.subsurface) * state.mat.albedo + Fsheen) * (1.0 - state.mat.metallic);
111
+ return ((1.0 / PI) * Fd * (1.0 - state.mat.subsurface) * state.mat.albedo + Fsheen) * (1.0 - state.mat.metallic);
112
112
}
113
113
114
114
// -----------------------------------------------------------------------
115
- void EvalSubsurface(State state, inout BsdfSampleRec bRec )
115
+ vec3 EvalSubsurface(State state, vec3 V, vec3 N, vec3 L, inout float pdf )
116
116
// -----------------------------------------------------------------------
117
117
{
118
- // if (dot(bRec.N, bRec.V) < 0.0) return ;
118
+ pdf = ( 1.0 / TWO_PI) ;
119
119
120
- bRec.pdf = (1.0 / TWO_PI);
121
-
122
- float FL = SchlickFresnel(abs (dot (bRec.N, bRec.L)));
123
- float FV = SchlickFresnel(dot (bRec.N, bRec.V));
120
+ float FL = SchlickFresnel(abs (dot (N, L)));
121
+ float FV = SchlickFresnel(dot (N, V));
124
122
float Fd = (1 .0f - 0 .5f * FL) * (1 .0f - 0 .5f * FV);
125
- bRec.f = sqrt (state.mat.albedo) * state.mat.subsurface * (1.0 / PI) * Fd * (1.0 - state.mat.metallic);
123
+ return sqrt (state.mat.albedo) * state.mat.subsurface * (1.0 / PI) * Fd * (1.0 - state.mat.metallic);
126
124
}
127
125
128
126
// -----------------------------------------------------------------------
129
- void DisneySample(inout State state, inout BsdfSampleRec bRec )
127
+ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float pdf )
130
128
// -----------------------------------------------------------------------
131
129
{
132
130
state.isSubsurface = false;
133
- bRec. pdf = 0.0 ;
134
- bRec.L = vec3 (0.0 );
131
+ pdf = 0.0 ;
132
+ vec3 f = vec3 (0.0 );
135
133
136
134
float r1 = rand();
137
135
float r2 = rand();
138
136
139
- vec3 brdf = vec3 (0.0 );
140
- vec3 bsdf = vec3 (0.0 );
141
- float brdfPdf = 0.0 ;
142
- float bsdfPdf = 0.0 ;
143
-
144
137
float diffuseRatio = 0.5 * (1.0 - state.mat.metallic);
145
138
float transWeight = (1.0 - state.mat.metallic) * state.mat.specTrans;
146
139
@@ -155,25 +148,25 @@ void DisneySample(inout State state, inout BsdfSampleRec bRec)
155
148
if (rand() < transWeight)
156
149
{
157
150
vec3 H = ImportanceSampleGTR2(state.mat.roughness, r1, r2);
158
- bRec. H = state.tangent * H.x + state.bitangent * H.y + bRec. N * H.z;
151
+ H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
159
152
160
- vec3 R = reflect (- bRec. V, bRec. H);
161
- float F = DielectricFresnel(abs (dot (R, bRec. H)), state.eta);
153
+ vec3 R = reflect (- V, H);
154
+ float F = DielectricFresnel(abs (dot (R, H)), state.eta);
162
155
163
156
// Reflection/Total internal reflection
164
157
if (rand() < F)
165
158
{
166
- bRec. L = normalize (R);
167
- EvalDielectricReflection(state, bRec );
159
+ L = normalize (R);
160
+ f = EvalDielectricReflection(state, V, N, L, H, pdf );
168
161
}
169
162
else // Transmission
170
163
{
171
- bRec. L = normalize (refract (- bRec. V, bRec. H, state.eta));
172
- EvalDielectricRefraction(state, bRec );
164
+ L = normalize (refract (- V, H, state.eta));
165
+ f = EvalDielectricRefraction(state, V, N, L, H, pdf );
173
166
}
174
167
175
- bsdf = bRec.f ;
176
- bsdfPdf = bRec.pdf ;
168
+ f *= transWeight ;
169
+ pdf *= transWeight ;
177
170
}
178
171
else // BRDF
179
172
{
@@ -183,24 +176,23 @@ void DisneySample(inout State state, inout BsdfSampleRec bRec)
183
176
// Simpler than random walk but not sure if accurate.
184
177
if (rand() < state.mat.subsurface)
185
178
{
186
- vec3 L = UniformSampleHemisphere(r1, r2);
187
- bRec. L = state.tangent * L.x + state.bitangent * L.y - bRec. N * L.z;
179
+ L = UniformSampleHemisphere(r1, r2);
180
+ L = state.tangent * L.x + state.bitangent * L.y - N * L.z;
188
181
189
- EvalSubsurface(state, bRec );
190
- bRec. pdf *= state.mat.subsurface * diffuseRatio;
182
+ f = EvalSubsurface(state, V, N, L, pdf );
183
+ pdf *= state.mat.subsurface * diffuseRatio;
191
184
192
185
state.isSubsurface = true; // Required when sampling lights from inside surface
193
- // state.specularBounce = true;
194
186
}
195
187
else // Diffuse
196
188
{
197
- vec3 L = CosineSampleHemisphere(r1, r2);
198
- bRec. L = state.tangent * L.x + state.bitangent * L.y + bRec. N * L.z;
189
+ L = CosineSampleHemisphere(r1, r2);
190
+ L = state.tangent * L.x + state.bitangent * L.y + N * L.z;
199
191
200
- bRec. H = normalize (bRec. L + bRec. V);
192
+ vec3 H = normalize (L + V);
201
193
202
- EvalDiffuse(state, bRec, Csheen );
203
- bRec. pdf *= (1.0 - state.mat.subsurface) * diffuseRatio;
194
+ f = EvalDiffuse(state, Csheen, V, N, L, H, pdf );
195
+ pdf *= (1.0 - state.mat.subsurface) * diffuseRatio;
204
196
}
205
197
}
206
198
else // Specular
@@ -212,79 +204,78 @@ void DisneySample(inout State state, inout BsdfSampleRec bRec)
212
204
{
213
205
// TODO: Implement http://jcgt.org/published/0007/04/01/
214
206
vec3 H = ImportanceSampleGTR2_aniso(state.mat.ax, state.mat.ay, r1, r2);
215
- bRec. H = state.tangent * H.x + state.bitangent * H.y + bRec. N * H.z;
216
- bRec. L = normalize (reflect (- bRec. V, bRec. H));
207
+ H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
208
+ L = normalize (reflect (- V, H));
217
209
218
- EvalSpecular(state, bRec, Cspec0 );
219
- bRec. pdf *= primarySpecRatio * (1.0 - diffuseRatio);
210
+ f = EvalSpecular(state, Cspec0, V, N, L, H, pdf );
211
+ pdf *= primarySpecRatio * (1.0 - diffuseRatio);
220
212
}
221
213
else // Sample clearcoat lobe
222
214
{
223
215
vec3 H = ImportanceSampleGTR1(state.mat.clearcoatRoughness, r1, r2);
224
- bRec. H = state.tangent * H.x + state.bitangent * H.y + bRec. N * H.z;
225
- bRec. L = normalize (reflect (- bRec. V, bRec. H));
216
+ H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
217
+ L = normalize (reflect (- V, H));
226
218
227
- EvalClearcoat(state, bRec );
228
- bRec. pdf *= (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
219
+ f = EvalClearcoat(state, V, N, L, H, pdf );
220
+ pdf *= (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
229
221
}
230
222
}
231
- brdf = bRec.f;
232
- brdfPdf = bRec.pdf;
233
- }
234
223
235
- bRec.pdf = mix (brdfPdf, bsdfPdf, transWeight);
236
- bRec.f = mix (brdf, bsdf, transWeight);
224
+ f *= (1.0 - transWeight);
225
+ pdf *= (1.0 - transWeight);
226
+ }
227
+ return f;
237
228
}
238
229
239
230
// -----------------------------------------------------------------------
240
- void DisneyEval(State state, inout BsdfSampleRec bRec )
231
+ vec3 DisneyEval(State state, vec3 V, vec3 N, vec3 L, inout float pdf )
241
232
// -----------------------------------------------------------------------
242
233
{
243
- if (dot (bRec.N, bRec.L) < 0.0 )
244
- bRec.H = normalize (bRec.L * (1.0 / state.eta) + bRec.V);
234
+ vec3 H;
235
+
236
+ if (dot (N, L) < 0.0 )
237
+ H = normalize (L * (1.0 / state.eta) + V);
245
238
else
246
- bRec. H = normalize (bRec. L + bRec. V);
239
+ H = normalize (L + V);
247
240
248
- if (dot (bRec.N, bRec.H) < 0.0 )
249
- bRec.H = - bRec.H;
241
+ if (dot (N, H) < 0.0 )
242
+ H = - H;
243
+
244
+ float diffuseRatio = 0.5 * (1.0 - state.mat.metallic);
245
+ float primarySpecRatio = 1.0 / (1.0 + state.mat.clearcoat);
246
+ float transWeight = (1.0 - state.mat.metallic) * state.mat.specTrans;
250
247
251
248
vec3 brdf = vec3 (0.0 );
252
249
vec3 bsdf = vec3 (0.0 );
253
250
float brdfPdf = 0.0 ;
254
251
float bsdfPdf = 0.0 ;
255
252
256
- float diffuseRatio = 0.5 * (1.0 - state.mat.metallic);
257
- float primarySpecRatio = 1.0 / (1.0 + state.mat.clearcoat);
258
- float transWeight = (1.0 - state.mat.metallic) * state.mat.specTrans;
259
-
260
253
// BSDF
261
254
if (transWeight > 0.0 )
262
255
{
263
256
// Transmission
264
- if (dot (bRec. N, bRec. L) < 0.0 )
257
+ if (dot (N, L) < 0.0 )
265
258
{
266
- EvalDielectricRefraction(state, bRec );
259
+ bsdf = EvalDielectricRefraction(state, V, N, L, H, bsdfPdf );
267
260
}
268
261
else // Reflection
269
262
{
270
- EvalDielectricReflection(state, bRec );
263
+ bsdf = EvalDielectricReflection(state, V, N, L, H, bsdfPdf );
271
264
}
272
-
273
- bsdf += bRec.f;
274
- bsdfPdf += bRec.pdf;
275
265
}
276
266
267
+ float m_pdf;
268
+
277
269
if (transWeight < 1.0 )
278
270
{
279
271
// Subsurface
280
- if (dot (bRec. N, bRec. L) < 0.0 )
272
+ if (dot (N, L) < 0.0 )
281
273
{
282
274
// TODO: Double check this. Causing occassional NaNs and fails furnace test when used with transmission
283
275
if (state.mat.subsurface > 0.0 )
284
276
{
285
- EvalSubsurface(state, bRec);
286
- brdf += bRec.f;
287
- brdfPdf += bRec.pdf * state.mat.subsurface * diffuseRatio;
277
+ brdf = EvalSubsurface(state, V, N, L, m_pdf);
278
+ brdfPdf = m_pdf * state.mat.subsurface * diffuseRatio;
288
279
}
289
280
}
290
281
// BRDF
@@ -298,22 +289,19 @@ void DisneyEval(State state, inout BsdfSampleRec bRec)
298
289
vec3 Csheen = mix (vec3 (1.0 ), Ctint, state.mat.sheenTint);
299
290
300
291
// Diffuse
301
- EvalDiffuse(state, bRec, Csheen);
302
- brdf += bRec.f;
303
- brdfPdf += bRec.pdf * (1.0 - state.mat.subsurface) * diffuseRatio;
292
+ brdf += EvalDiffuse(state, Csheen, V, N, L, H, m_pdf);
293
+ brdfPdf += m_pdf * (1.0 - state.mat.subsurface) * diffuseRatio;
304
294
305
295
// Specular
306
- EvalSpecular(state, bRec, Cspec0);
307
- brdf += bRec.f;
308
- brdfPdf += bRec.pdf * primarySpecRatio * (1.0 - diffuseRatio);
296
+ brdf += EvalSpecular(state, Cspec0, V, N, L, H, m_pdf);
297
+ brdfPdf += m_pdf * primarySpecRatio * (1.0 - diffuseRatio);
309
298
310
299
// Clearcoat
311
- EvalClearcoat(state, bRec);
312
- brdf += bRec.f;
313
- brdfPdf += bRec.pdf * (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
300
+ brdf += EvalClearcoat(state, V, N, L, H, m_pdf);
301
+ brdfPdf += m_pdf * (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
314
302
}
315
303
}
316
304
317
- bRec. pdf = mix (brdfPdf, bsdfPdf, transWeight);
318
- bRec.f = mix (brdf, bsdf, transWeight);
305
+ pdf = mix (brdfPdf, bsdfPdf, transWeight);
306
+ return mix (brdf, bsdf, transWeight);
319
307
}
0 commit comments