@@ -42,9 +42,9 @@ vec3 EvalDielectricReflection(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout
42
42
float F = DielectricFresnel(dot (V, H), state.eta);
43
43
float D = GTR2(dot (N, H), state.mat.roughness);
44
44
45
- pdf = D * dot (N, H) * F / (4.0 * dot (V, H));
45
+ pdf = D * dot (N, H) * F / (4.0 * abs ( dot (V, H) ));
46
46
47
- float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(dot (N, V), state.mat.roughness);
47
+ float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(abs ( dot (N, V) ), state.mat.roughness);
48
48
return state.mat.albedo * F * D * G;
49
49
}
50
50
@@ -55,10 +55,10 @@ vec3 EvalDielectricRefraction(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout
55
55
float F = DielectricFresnel(abs (dot (V, H)), state.eta);
56
56
float D = GTR2(dot (N, H), state.mat.roughness);
57
57
58
- float denomSqrt = dot (L, H) * state.eta + dot (V, H);
58
+ float denomSqrt = dot (L, H) + dot (V, H) * state.eta ;
59
59
pdf = D * dot (N, H) * (1.0 - F) * abs (dot (L, H)) / (denomSqrt * denomSqrt);
60
60
61
- float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(dot (N, V), state.mat.roughness);
61
+ float G = SmithG_GGX(abs (dot (N, L)), state.mat.roughness) * SmithG_GGX(abs ( dot (N, V) ), state.mat.roughness);
62
62
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);
63
63
}
64
64
@@ -101,32 +101,28 @@ vec3 EvalDiffuse(State state, vec3 Csheen, vec3 V, vec3 N, vec3 L, vec3 H, inout
101
101
102
102
pdf = dot (N, L) * (1.0 / PI);
103
103
104
+ // Diffuse
104
105
float FL = SchlickFresnel(dot (N, L));
105
106
float FV = SchlickFresnel(dot (N, V));
106
107
float FH = SchlickFresnel(dot (L, H));
107
108
float Fd90 = 0.5 + 2.0 * dot (L, H) * dot (L, H) * state.mat.roughness;
108
109
float Fd = mix (1.0 , Fd90, FL) * mix (1.0 , Fd90, FV);
109
- vec3 Fsheen = FH * state.mat.sheen * Csheen;
110
- return ((1.0 / PI) * Fd * (1.0 - state.mat.subsurface) * state.mat.albedo + Fsheen) * (1.0 - state.mat.metallic);
111
- }
112
110
113
- // -----------------------------------------------------------------------
114
- vec3 EvalSubsurface(State state, vec3 V, vec3 N, vec3 L, inout float pdf)
115
- // -----------------------------------------------------------------------
116
- {
117
- pdf = ( 1.0 / TWO_PI );
111
+ // TODO: Replace with volumetric scattering
112
+ // SS
113
+ float Fss90 = dot (L, H) * dot (L, H) * state.mat.roughness;
114
+ float Fss = mix ( 1.0 , Fss90, FL) * mix ( 1.0 , Fss90, FV);
115
+ float ss = 1.25 * (Fss * ( 1.0 / ( dot (N, L) + dot (N, V)) - 0.5 ) + 0.5 );
118
116
119
- float FL = SchlickFresnel(abs (dot (N, L)));
120
- float FV = SchlickFresnel(dot (N, V));
121
- float Fd = (1 .0f - 0 .5f * FL) * (1 .0f - 0 .5f * FV);
122
- return sqrt (state.mat.albedo) * state.mat.subsurface * (1.0 / PI) * Fd * (1.0 - state.mat.metallic) * (1.0 - state.mat.specTrans);
117
+ vec3 Fsheen = FH * state.mat.sheen * Csheen;
118
+ return ((1.0 / PI) * mix (Fd, ss, state.mat.subsurface) * state.mat.albedo + Fsheen) * (1.0 - state.mat.metallic);
123
119
}
124
120
125
121
// -----------------------------------------------------------------------
126
122
vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float pdf)
127
123
// -----------------------------------------------------------------------
128
124
{
129
- state.isSubsurface = false;
125
+ state.specularBounce = false;
130
126
pdf = 0.0 ;
131
127
vec3 f = vec3 (0.0 );
132
128
@@ -150,6 +146,9 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
150
146
vec3 H = ImportanceSampleGTR2(state.mat.roughness, r1, r2);
151
147
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
152
148
149
+ if (dot (V, H) < 0.0 )
150
+ H = - H;
151
+
153
152
vec3 R = reflect (- V, H);
154
153
float F = DielectricFresnel(abs (dot (R, H)), state.eta);
155
154
@@ -161,6 +160,8 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
161
160
}
162
161
else // Transmission
163
162
{
163
+ // TODO: Check how other renderers handle dielectrics
164
+ state.specularBounce = true;
164
165
L = normalize (refract (- V, H, state.eta));
165
166
f = EvalDielectricRefraction(state, V, N, L, H, pdf);
166
167
}
@@ -172,28 +173,13 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
172
173
{
173
174
if (rand() < diffuseRatio)
174
175
{
175
- // Diffuse transmission. A way to approximate subsurface scattering
176
- // TODO: Replace with actual volumetric scattering and absorption
177
- if (rand() < state.mat.subsurface)
178
- {
179
- L = UniformSampleHemisphere(r1, r2);
180
- L = state.tangent * L.x + state.bitangent * L.y - N * L.z;
181
-
182
- f = EvalSubsurface(state, V, N, L, pdf);
183
- pdf *= state.mat.subsurface * diffuseRatio;
184
-
185
- state.isSubsurface = true; // Required when sampling lights from inside surface
186
- }
187
- else // Diffuse
188
- {
189
- L = CosineSampleHemisphere(r1, r2);
190
- L = state.tangent * L.x + state.bitangent * L.y + N * L.z;
176
+ L = CosineSampleHemisphere(r1, r2);
177
+ L = state.tangent * L.x + state.bitangent * L.y + N * L.z;
191
178
192
- vec3 H = normalize (L + V);
179
+ vec3 H = normalize (L + V);
193
180
194
- f = EvalDiffuse(state, Csheen, V, N, L, H, pdf);
195
- pdf *= (1.0 - state.mat.subsurface) * diffuseRatio;
196
- }
181
+ f = EvalDiffuse(state, Csheen, V, N, L, H, pdf);
182
+ pdf *= diffuseRatio;
197
183
}
198
184
else // Specular
199
185
{
@@ -205,6 +191,10 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
205
191
// TODO: Implement http://jcgt.org/published/0007/04/01/
206
192
vec3 H = ImportanceSampleGTR2_aniso(state.mat.ax, state.mat.ay, r1, r2);
207
193
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
194
+
195
+ if (dot (V, H) < 0.0 )
196
+ H = - H;
197
+
208
198
L = normalize (reflect (- V, H));
209
199
210
200
f = EvalSpecular(state, Cspec0, V, N, L, H, pdf);
@@ -214,6 +204,10 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
214
204
{
215
205
vec3 H = ImportanceSampleGTR1(mix (0.1 , 0.001 , state.mat.clearcoatGloss), r1, r2);
216
206
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
207
+
208
+ if (dot (V, H) < 0.0 )
209
+ H = - H;
210
+
217
211
L = normalize (reflect (- V, H));
218
212
219
213
f = EvalClearcoat(state, V, N, L, H, pdf);
@@ -268,37 +262,24 @@ vec3 DisneyEval(State state, vec3 V, vec3 N, vec3 L, inout float pdf)
268
262
269
263
if (transWeight < 1.0 )
270
264
{
271
- // Subsurface
272
- if (dot (N, L) < 0.0 )
273
- {
274
- if (state.mat.subsurface > 0.0 )
275
- {
276
- brdf = EvalSubsurface(state, V, N, L, m_pdf);
277
- brdfPdf = m_pdf * state.mat.subsurface * diffuseRatio;
278
- }
279
- }
280
- // BRDF
281
- else
282
- {
283
- vec3 Cdlin = state.mat.albedo;
284
- float Cdlum = 0.3 * Cdlin.x + 0.6 * Cdlin.y + 0.1 * Cdlin.z; // luminance approx.
265
+ vec3 Cdlin = state.mat.albedo;
266
+ float Cdlum = 0.3 * Cdlin.x + 0.6 * Cdlin.y + 0.1 * Cdlin.z; // luminance approx.
285
267
286
- vec3 Ctint = Cdlum > 0.0 ? Cdlin / Cdlum : vec3 (1 .0f); // normalize lum. to isolate hue+sat
287
- vec3 Cspec0 = mix (state.mat.specular * 0.08 * mix (vec3 (1.0 ), Ctint, state.mat.specularTint), Cdlin, state.mat.metallic);
288
- vec3 Csheen = mix (vec3 (1.0 ), Ctint, state.mat.sheenTint);
268
+ vec3 Ctint = Cdlum > 0.0 ? Cdlin / Cdlum : vec3 (1 .0f); // normalize lum. to isolate hue+sat
269
+ vec3 Cspec0 = mix (state.mat.specular * 0.08 * mix (vec3 (1.0 ), Ctint, state.mat.specularTint), Cdlin, state.mat.metallic);
270
+ vec3 Csheen = mix (vec3 (1.0 ), Ctint, state.mat.sheenTint);
289
271
290
- // Diffuse
291
- brdf += EvalDiffuse(state, Csheen, V, N, L, H, m_pdf);
292
- brdfPdf += m_pdf * ( 1.0 - state.mat.subsurface) * diffuseRatio;
272
+ // Diffuse
273
+ brdf += EvalDiffuse(state, Csheen, V, N, L, H, m_pdf);
274
+ brdfPdf += m_pdf * diffuseRatio;
293
275
294
- // Specular
295
- brdf += EvalSpecular(state, Cspec0, V, N, L, H, m_pdf);
296
- brdfPdf += m_pdf * primarySpecRatio * (1.0 - diffuseRatio);
276
+ // Specular
277
+ brdf += EvalSpecular(state, Cspec0, V, N, L, H, m_pdf);
278
+ brdfPdf += m_pdf * primarySpecRatio * (1.0 - diffuseRatio);
297
279
298
- // Clearcoat
299
- brdf += EvalClearcoat(state, V, N, L, H, m_pdf);
300
- brdfPdf += m_pdf * (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
301
- }
280
+ // Clearcoat
281
+ brdf += EvalClearcoat(state, V, N, L, H, m_pdf);
282
+ brdfPdf += m_pdf * (1.0 - primarySpecRatio) * (1.0 - diffuseRatio);
302
283
}
303
284
304
285
pdf = mix (brdfPdf, bsdfPdf, transWeight);
0 commit comments