Skip to content

Commit dd0a02d

Browse files
Removed hacky diffuse transmission for sss. Fixed an issue with dielectrics and mis
1 parent dd2964f commit dd0a02d

File tree

3 files changed

+52
-73
lines changed

3 files changed

+52
-73
lines changed

src/shaders/common/disney.glsl

Lines changed: 45 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ vec3 EvalDielectricReflection(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout
4242
float F = DielectricFresnel(dot(V, H), state.eta);
4343
float D = GTR2(dot(N, H), state.mat.roughness);
4444

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)));
4646

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);
4848
return state.mat.albedo * F * D * G;
4949
}
5050

@@ -55,10 +55,10 @@ vec3 EvalDielectricRefraction(State state, vec3 V, vec3 N, vec3 L, vec3 H, inout
5555
float F = DielectricFresnel(abs(dot(V, H)), state.eta);
5656
float D = GTR2(dot(N, H), state.mat.roughness);
5757

58-
float denomSqrt = dot(L, H) * state.eta + dot(V, H);
58+
float denomSqrt = dot(L, H) + dot(V, H) * state.eta;
5959
pdf = D * dot(N, H) * (1.0 - F) * abs(dot(L, H)) / (denomSqrt * denomSqrt);
6060

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);
6262
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);
6363
}
6464

@@ -101,32 +101,28 @@ vec3 EvalDiffuse(State state, vec3 Csheen, vec3 V, vec3 N, vec3 L, vec3 H, inout
101101

102102
pdf = dot(N, L) * (1.0 / PI);
103103

104+
// Diffuse
104105
float FL = SchlickFresnel(dot(N, L));
105106
float FV = SchlickFresnel(dot(N, V));
106107
float FH = SchlickFresnel(dot(L, H));
107108
float Fd90 = 0.5 + 2.0 * dot(L, H) * dot(L, H) * state.mat.roughness;
108109
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-
}
112110

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);
118116

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);
123119
}
124120

125121
//-----------------------------------------------------------------------
126122
vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float pdf)
127123
//-----------------------------------------------------------------------
128124
{
129-
state.isSubsurface = false;
125+
state.specularBounce = false;
130126
pdf = 0.0;
131127
vec3 f = vec3(0.0);
132128

@@ -150,6 +146,9 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
150146
vec3 H = ImportanceSampleGTR2(state.mat.roughness, r1, r2);
151147
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
152148

149+
if (dot(V, H) < 0.0)
150+
H = -H;
151+
153152
vec3 R = reflect(-V, H);
154153
float F = DielectricFresnel(abs(dot(R, H)), state.eta);
155154

@@ -161,6 +160,8 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
161160
}
162161
else // Transmission
163162
{
163+
// TODO: Check how other renderers handle dielectrics
164+
state.specularBounce = true;
164165
L = normalize(refract(-V, H, state.eta));
165166
f = EvalDielectricRefraction(state, V, N, L, H, pdf);
166167
}
@@ -172,28 +173,13 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
172173
{
173174
if (rand() < diffuseRatio)
174175
{
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;
191178

192-
vec3 H = normalize(L + V);
179+
vec3 H = normalize(L + V);
193180

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;
197183
}
198184
else // Specular
199185
{
@@ -205,6 +191,10 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
205191
// TODO: Implement http://jcgt.org/published/0007/04/01/
206192
vec3 H = ImportanceSampleGTR2_aniso(state.mat.ax, state.mat.ay, r1, r2);
207193
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
194+
195+
if (dot(V, H) < 0.0)
196+
H = -H;
197+
208198
L = normalize(reflect(-V, H));
209199

210200
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
214204
{
215205
vec3 H = ImportanceSampleGTR1(mix(0.1, 0.001, state.mat.clearcoatGloss), r1, r2);
216206
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
207+
208+
if (dot(V, H) < 0.0)
209+
H = -H;
210+
217211
L = normalize(reflect(-V, H));
218212

219213
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)
268262

269263
if (transWeight < 1.0)
270264
{
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.
285267

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);
289271

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;
293275

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);
297279

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);
302283
}
303284

304285
pdf = mix(brdfPdf, bsdfPdf, transWeight);

src/shaders/common/globals.glsl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ struct State
102102

103103
bool isEmitter;
104104
bool specularBounce;
105-
bool isSubsurface;
106105

107106
vec2 texCoord;
108107
vec3 bary;

src/shaders/common/pathtrace.glsl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ vec3 DirectLight(in Ray r, in State state)
142142
//-----------------------------------------------------------------------
143143
{
144144
vec3 Li = vec3(0.0);
145-
vec3 surfacePos = state.fhp;
145+
vec3 surfacePos = state.fhp + state.ffnormal * EPS;
146146

147147
BsdfSampleRec bsdfSampleRec;
148148

@@ -155,9 +155,9 @@ vec3 DirectLight(in Ray r, in State state)
155155
vec3 lightDir = dirPdf.xyz;
156156
float lightPdf = dirPdf.w;
157157

158-
if (state.isSubsurface || dot(lightDir, state.ffnormal) > 0.0)
158+
if (dot(lightDir, state.ffnormal) > 0.0)
159159
{
160-
Ray shadowRay = Ray(surfacePos + FaceForward(state.normal, lightDir) * EPS, lightDir);
160+
Ray shadowRay = Ray(surfacePos, lightDir);
161161
bool inShadow = AnyHit(shadowRay, INFINITY - EPS);
162162

163163
if (!inShadow)
@@ -203,9 +203,9 @@ vec3 DirectLight(in Ray r, in State state)
203203
float lightDistSq = lightDist * lightDist;
204204
lightDir /= sqrt(lightDistSq);
205205

206-
if ((state.isSubsurface || dot(lightDir, state.ffnormal) > 0.0) && dot(lightDir, lightSampleRec.normal) < 0.0)
206+
if (dot(lightDir, state.ffnormal) > 0.0 && dot(lightDir, lightSampleRec.normal) < 0.0)
207207
{
208-
Ray shadowRay = Ray(surfacePos + FaceForward(state.normal, lightDir) * EPS, lightDir);
208+
Ray shadowRay = Ray(surfacePos, lightDir);
209209
bool inShadow = AnyHit(shadowRay, lightDist - EPS);
210210

211211
if (!inShadow)
@@ -237,7 +237,6 @@ vec3 PathTrace(Ray r)
237237

238238
for (int depth = 0; depth < maxDepth; depth++)
239239
{
240-
float lightPdf = 1.0f;
241240
state.depth = depth;
242241
float t = ClosestHit(r, state, lightSampleRec);
243242

@@ -254,7 +253,7 @@ vec3 PathTrace(Ray r)
254253
if (depth > 0 && !state.specularBounce)
255254
{
256255
// TODO: Fix NaNs when using certain HDRs
257-
lightPdf = EnvPdf(r);
256+
float lightPdf = EnvPdf(r);
258257
misWeight = powerHeuristic(bsdfSampleRec.pdf, lightPdf);
259258
}
260259
radiance += misWeight * texture(hdrTex, uv).xyz * throughput * hdrMultiplier;
@@ -301,7 +300,7 @@ vec3 PathTrace(Ray r)
301300
// Russian roulette
302301
if (depth >= RR_DEPTH)
303302
{
304-
float q = min(max(throughput.x, max(throughput.y, throughput.z)) * state.eta * state.eta + 0.001, 0.95);
303+
float q = min(max(throughput.x, max(throughput.y, throughput.z)) + 0.001, 0.95);
305304
if (rand() > q)
306305
break;
307306
throughput /= q;

0 commit comments

Comments
 (0)