Skip to content

Commit 92ab56f

Browse files
Some fixes for energy conservation when subsurface is used with transmission. Still some issues though
1 parent 069d1ac commit 92ab56f

File tree

3 files changed

+12
-17
lines changed

3 files changed

+12
-17
lines changed

src/shaders/common/disney.glsl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
* [6] http://shihchinw.github.io/2015/07/implementing-disney-principled-brdf-in-arnold.html
3232
* [7] https://github.com/mmp/pbrt-v4/blob/0ec29d1ec8754bddd9d667f0e80c4ff025c900ce/src/pbrt/bxdfs.cpp#L76-L286
3333
* [8] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
34-
* [9] https://graphics.pixar.com/library/RadiosityCaching/paper.pdf
3534
*/
3635

3736
//-----------------------------------------------------------------------
@@ -120,7 +119,7 @@ vec3 EvalSubsurface(State state, vec3 V, vec3 N, vec3 L, inout float pdf)
120119
float FL = SchlickFresnel(abs(dot(N, L)));
121120
float FV = SchlickFresnel(dot(N, V));
122121
float Fd = (1.0f - 0.5f * FL) * (1.0f - 0.5f * FV);
123-
return sqrt(state.mat.albedo) * state.mat.subsurface * (1.0 / PI) * Fd * (1.0 - state.mat.metallic);
122+
return sqrt(state.mat.albedo) * state.mat.subsurface * (1.0 / PI) * Fd * (1.0 - state.mat.metallic) * (1.0 - state.mat.specTrans);
124123
}
125124

126125
//-----------------------------------------------------------------------
@@ -172,8 +171,7 @@ vec3 DisneySample(inout State state, vec3 V, vec3 N, inout vec3 L, inout float p
172171
{
173172
if (rand() < diffuseRatio)
174173
{
175-
// This way of performing subsurface scattering was taken from Tinsel [4] and is similar [9].
176-
// Simpler than random walk but not sure if accurate.
174+
// Diffuse transmission. A way to approximate subsurface scattering
177175
if (rand() < state.mat.subsurface)
178176
{
179177
L = UniformSampleHemisphere(r1, r2);
@@ -271,7 +269,7 @@ vec3 DisneyEval(State state, vec3 V, vec3 N, vec3 L, inout float pdf)
271269
// Subsurface
272270
if (dot(N, L) < 0.0)
273271
{
274-
// TODO: Double check this. Causing occassional NaNs and fails furnace test when used with transmission
272+
// TODO: Double check this. Fails furnace test when used with rough transmission
275273
if (state.mat.subsurface > 0.0)
276274
{
277275
brdf = EvalSubsurface(state, V, N, L, m_pdf);

src/shaders/common/globals.glsl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,13 @@ struct LightSampleRec
127127

128128
uniform Camera camera;
129129

130-
//-----------
131130
float rand()
132-
//-----------
133131
{
134132
seed -= randomVector.xy;
135133
return fract(sin(dot(seed, vec2(12.9898, 78.233))) * 43758.5453);
134+
}
135+
136+
vec3 FaceForward(vec3 a, vec3 b)
137+
{
138+
return dot(a, b) < 0.0 ? -b : b;
136139
}

src/shaders/common/pathtrace.glsl

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,10 @@ vec3 DirectLight(in Ray r, in State state)
139139
//-----------------------------------------------------------------------
140140
{
141141
vec3 Li = vec3(0.0);
142-
vec3 surfacePos;
142+
vec3 surfacePos = state.fhp;
143143

144144
BsdfSampleRec bsdfSampleRec;
145145

146-
// If sampling subsurface then push surfacePos towards the outer surface to be able to hit a light source
147-
if(state.isSubsurface)
148-
surfacePos = state.fhp + state.normal * EPS;
149-
else
150-
surfacePos = state.fhp + state.ffnormal * EPS;
151-
152146
// Environment Light
153147
#ifdef ENVMAP
154148
#ifndef CONSTANT_BG
@@ -160,7 +154,7 @@ vec3 DirectLight(in Ray r, in State state)
160154

161155
if (state.isSubsurface || dot(lightDir, state.ffnormal) > 0.0)
162156
{
163-
Ray shadowRay = Ray(surfacePos, lightDir);
157+
Ray shadowRay = Ray(surfacePos + FaceForward(state.normal, lightDir) * EPS, lightDir);
164158
bool inShadow = AnyHit(shadowRay, INFINITY - EPS);
165159

166160
if (!inShadow)
@@ -209,7 +203,7 @@ vec3 DirectLight(in Ray r, in State state)
209203
if (!state.isSubsurface && (dot(lightDir, state.ffnormal) <= 0.0 || dot(lightDir, lightSampleRec.normal) >= 0.0))
210204
return Li;
211205

212-
Ray shadowRay = Ray(surfacePos, lightDir);
206+
Ray shadowRay = Ray(surfacePos + FaceForward(state.normal, lightDir) * EPS, lightDir);
213207
bool inShadow = AnyHit(shadowRay, lightDist - EPS);
214208

215209
if (!inShadow)
@@ -293,7 +287,7 @@ vec3 PathTrace(Ray r)
293287

294288
// Set absorption only if the ray is currently inside the object.
295289
if (dot(state.ffnormal, bsdfSampleRec.L) < 0.0)
296-
absorption = -log(state.mat.extinction) / vec3(0.1);
290+
absorption = -log(state.mat.extinction) / vec3(0.2); // TODO: Add atDistance
297291

298292
if (bsdfSampleRec.pdf > 0.0)
299293
throughput *= bsdfSampleRec.f * abs(dot(state.ffnormal, bsdfSampleRec.L)) / bsdfSampleRec.pdf;

0 commit comments

Comments
 (0)