three-gpu-pathtracer 0.0.3 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -15
- package/build/index.module.js +2706 -529
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +2713 -529
- package/build/index.umd.cjs.map +1 -1
- package/package.json +68 -60
- package/src/core/DynamicPathTracingSceneGenerator.js +24 -11
- package/src/core/PathTracingRenderer.js +22 -0
- package/src/core/PathTracingSceneGenerator.js +36 -20
- package/src/index.js +9 -1
- package/src/materials/PhysicalPathTracingMaterial.js +350 -60
- package/src/objects/EquirectCamera.js +13 -0
- package/src/{core → objects}/PhysicalCamera.js +0 -0
- package/src/objects/PhysicalSpotLight.js +14 -0
- package/src/objects/ShapedAreaLight.js +12 -0
- package/src/shader/shaderEnvMapSampling.js +59 -67
- package/src/shader/shaderGGXFunctions.js +3 -2
- package/src/shader/shaderIridescenceFunctions.js +130 -0
- package/src/shader/shaderLightSampling.js +231 -0
- package/src/shader/shaderMaterialSampling.js +259 -53
- package/src/shader/shaderSheenFunctions.js +98 -0
- package/src/shader/shaderStructs.js +307 -92
- package/src/shader/shaderUtils.js +122 -0
- package/src/uniforms/EquirectHdrInfoUniform.js +10 -14
- package/src/uniforms/IESProfilesTexture.js +100 -0
- package/src/uniforms/LightsInfoUniformStruct.js +162 -0
- package/src/uniforms/MaterialsTexture.js +266 -33
- package/src/uniforms/PhysicalCameraUniform.js +1 -1
- package/src/uniforms/RenderTarget2DArray.js +93 -80
- package/src/utils/GeometryPreparationUtils.js +1 -1
- package/src/utils/IESLoader.js +325 -0
- package/src/workers/PathTracingSceneWorker.js +3 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { shaderGGXFunctions } from './shaderGGXFunctions.js';
|
|
2
|
+
import { shaderSheenFunctions } from './shaderSheenFunctions.js';
|
|
3
|
+
import { shaderIridescenceFunctions } from './shaderIridescenceFunctions.js';
|
|
2
4
|
|
|
3
5
|
export const shaderMaterialSampling = /* glsl */`
|
|
4
6
|
|
|
@@ -13,15 +15,29 @@ struct SurfaceRec {
|
|
|
13
15
|
vec3 emission;
|
|
14
16
|
float transmission;
|
|
15
17
|
float ior;
|
|
18
|
+
float clearcoat;
|
|
19
|
+
float clearcoatRoughness;
|
|
20
|
+
float filteredClearcoatRoughness;
|
|
21
|
+
vec3 sheenColor;
|
|
22
|
+
float sheenRoughness;
|
|
23
|
+
float iridescence;
|
|
24
|
+
float iridescenceIor;
|
|
25
|
+
float iridescenceThickness;
|
|
26
|
+
vec3 specularColor;
|
|
27
|
+
float specularIntensity;
|
|
16
28
|
};
|
|
17
29
|
|
|
18
30
|
struct SampleRec {
|
|
31
|
+
float specularPdf;
|
|
19
32
|
float pdf;
|
|
20
33
|
vec3 direction;
|
|
34
|
+
vec3 clearcoatDirection;
|
|
21
35
|
vec3 color;
|
|
22
36
|
};
|
|
23
37
|
|
|
24
38
|
${ shaderGGXFunctions }
|
|
39
|
+
${ shaderSheenFunctions }
|
|
40
|
+
${ shaderIridescenceFunctions }
|
|
25
41
|
|
|
26
42
|
// diffuse
|
|
27
43
|
float diffusePDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
@@ -56,10 +72,15 @@ vec3 diffuseColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
56
72
|
// specular
|
|
57
73
|
float specularPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
58
74
|
|
|
59
|
-
// See
|
|
75
|
+
// See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/
|
|
60
76
|
float filteredRoughness = surf.filteredRoughness;
|
|
61
77
|
vec3 halfVector = getHalfVector( wi, wo );
|
|
62
|
-
|
|
78
|
+
|
|
79
|
+
float incidentTheta = acos( wo.z );
|
|
80
|
+
float D = ggxDistribution( halfVector, filteredRoughness );
|
|
81
|
+
float G1 = ggxShadowMaskG1( incidentTheta, filteredRoughness );
|
|
82
|
+
float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, halfVector ) ) ) / abs ( wo.z );
|
|
83
|
+
return ggxPdf / ( 4.0 * dot( wo, halfVector ) );
|
|
63
84
|
|
|
64
85
|
}
|
|
65
86
|
|
|
@@ -92,21 +113,25 @@ vec3 specularColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
92
113
|
float iorRatio = frontFace ? 1.0 / ior : ior;
|
|
93
114
|
float G = ggxShadowMaskG2( wi, wo, filteredRoughness );
|
|
94
115
|
float D = ggxDistribution( halfVector, filteredRoughness );
|
|
116
|
+
vec3 F = vec3( schlickFresnelFromIor( dot( wi, halfVector ), iorRatio ) ) * surf.specularColor * surf.specularIntensity;
|
|
95
117
|
|
|
96
|
-
float F = schlickFresnelFromIor( dot( wi, halfVector ), iorRatio );
|
|
97
118
|
float cosTheta = min( wo.z, 1.0 );
|
|
98
119
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
99
120
|
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
100
121
|
if ( cannotRefract ) {
|
|
101
122
|
|
|
102
|
-
F = 1.0;
|
|
123
|
+
F = vec3( 1.0 );
|
|
103
124
|
|
|
104
125
|
}
|
|
105
126
|
|
|
127
|
+
float f0 = pow( ( iorRatio - 1.0 ) / ( iorRatio + 1.0 ), 2.0 );
|
|
128
|
+
vec3 iridescenceFresnel = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, halfVector ), surf.iridescenceThickness, vec3( f0 ) );
|
|
129
|
+
F = mix( F, iridescenceFresnel, surf.iridescence );
|
|
130
|
+
|
|
106
131
|
vec3 color = mix( vec3( 1.0 ), surf.color, metalness );
|
|
107
132
|
color = mix( color, vec3( 1.0 ), F );
|
|
108
133
|
color *= G * D / ( 4.0 * abs( wi.z * wo.z ) );
|
|
109
|
-
color *= mix( F, 1.0, metalness );
|
|
134
|
+
color *= mix( F, vec3( 1.0 ), metalness );
|
|
110
135
|
color *= wi.z; // scale the light by the direction the light is coming in from
|
|
111
136
|
|
|
112
137
|
return color;
|
|
@@ -213,7 +238,119 @@ vec3 transmissionColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
213
238
|
|
|
214
239
|
}
|
|
215
240
|
|
|
216
|
-
|
|
241
|
+
// clearcoat
|
|
242
|
+
float clearcoatPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
243
|
+
|
|
244
|
+
// See equation (27) in http://jcgt.org/published/0003/02/03/
|
|
245
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
246
|
+
vec3 halfVector = getHalfVector( wi, wo );
|
|
247
|
+
return ggxPDF( wo, halfVector, filteredClearcoatRoughness ) / ( 4.0 * dot( wi, halfVector ) );
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
vec3 clearcoatDirection( vec3 wo, SurfaceRec surf ) {
|
|
252
|
+
|
|
253
|
+
// sample ggx vndf distribution which gives a new normal
|
|
254
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
255
|
+
vec3 halfVector = ggxDirection(
|
|
256
|
+
wo,
|
|
257
|
+
filteredClearcoatRoughness,
|
|
258
|
+
filteredClearcoatRoughness,
|
|
259
|
+
rand(),
|
|
260
|
+
rand()
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// apply to new ray by reflecting off the new normal
|
|
264
|
+
return - reflect( wo, halfVector );
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
void clearcoatColor( inout vec3 color, vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
269
|
+
|
|
270
|
+
float ior = 1.5;
|
|
271
|
+
bool frontFace = surf.frontFace;
|
|
272
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
273
|
+
|
|
274
|
+
vec3 halfVector = getHalfVector( wo, wi );
|
|
275
|
+
float iorRatio = frontFace ? 1.0 / ior : ior;
|
|
276
|
+
float G = ggxShadowMaskG2( wi, wo, filteredClearcoatRoughness );
|
|
277
|
+
float D = ggxDistribution( halfVector, filteredClearcoatRoughness );
|
|
278
|
+
|
|
279
|
+
float F = schlickFresnelFromIor( dot( wi, halfVector ), ior );
|
|
280
|
+
float cosTheta = min( wo.z, 1.0 );
|
|
281
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
282
|
+
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
283
|
+
if ( cannotRefract ) {
|
|
284
|
+
|
|
285
|
+
F = 1.0;
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
float fClearcoat = F * D * G / ( 4.0 * abs( wi.z * wo.z ) );
|
|
290
|
+
|
|
291
|
+
color = color * ( 1.0 - surf.clearcoat * F ) + fClearcoat * surf.clearcoat * wi.z;
|
|
292
|
+
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// sheen
|
|
296
|
+
vec3 sheenColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
297
|
+
|
|
298
|
+
vec3 halfVector = getHalfVector( wo, wi );
|
|
299
|
+
|
|
300
|
+
float cosThetaO = saturateCos( wo.z );
|
|
301
|
+
float cosThetaI = saturateCos( wi.z );
|
|
302
|
+
float cosThetaH = halfVector.z;
|
|
303
|
+
|
|
304
|
+
float D = velvetD( cosThetaH, surf.sheenRoughness );
|
|
305
|
+
float G = velvetG( cosThetaO, cosThetaI, surf.sheenRoughness );
|
|
306
|
+
|
|
307
|
+
// See equation (1) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
308
|
+
vec3 color = surf.sheenColor;
|
|
309
|
+
color *= D * G / ( 4.0 * abs( cosThetaO * cosThetaI ) );
|
|
310
|
+
color *= wi.z;
|
|
311
|
+
|
|
312
|
+
return color;
|
|
313
|
+
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// bsdf
|
|
317
|
+
void getLobeWeights( vec3 wo, vec3 clearcoatWo, SurfaceRec surf, out float diffuseWeight, out float specularWeight, out float transmissionWeight, out float clearcoatWeight ) {
|
|
318
|
+
|
|
319
|
+
float ior = surf.ior;
|
|
320
|
+
float metalness = surf.metalness;
|
|
321
|
+
float transmission = surf.transmission;
|
|
322
|
+
bool frontFace = surf.frontFace;
|
|
323
|
+
|
|
324
|
+
float ratio = frontFace ? 1.0 / ior : ior;
|
|
325
|
+
float cosTheta = min( wo.z, 1.0 );
|
|
326
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
327
|
+
float reflectance = schlickFresnelFromIor( cosTheta, ratio );
|
|
328
|
+
bool cannotRefract = ratio * sinTheta > 1.0;
|
|
329
|
+
if ( cannotRefract ) {
|
|
330
|
+
|
|
331
|
+
reflectance = 1.0;
|
|
332
|
+
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
float transSpecularProb = mix( reflectance, 1.0, metalness );
|
|
336
|
+
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
337
|
+
|
|
338
|
+
clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );
|
|
339
|
+
diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb ) * ( 1.0 - clearcoatWeight );
|
|
340
|
+
specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb * ( 1.0 - clearcoatWeight );
|
|
341
|
+
transmissionWeight = transmission * ( 1.0 - transSpecularProb ) * ( 1.0 - clearcoatWeight );
|
|
342
|
+
|
|
343
|
+
float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;
|
|
344
|
+
float invTotalWeight = 1.0 / totalWeight;
|
|
345
|
+
|
|
346
|
+
diffuseWeight *= invTotalWeight;
|
|
347
|
+
specularWeight *= invTotalWeight;
|
|
348
|
+
transmissionWeight *= invTotalWeight;
|
|
349
|
+
clearcoatWeight *= invTotalWeight;
|
|
350
|
+
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
float bsdfPdf( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out float specularPdf, float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight ) {
|
|
217
354
|
|
|
218
355
|
float ior = surf.ior;
|
|
219
356
|
float metalness = surf.metalness;
|
|
@@ -234,43 +371,85 @@ float bsdfPdf( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
234
371
|
float spdf = 0.0;
|
|
235
372
|
float dpdf = 0.0;
|
|
236
373
|
float tpdf = 0.0;
|
|
374
|
+
float cpdf = 0.0;
|
|
237
375
|
|
|
238
376
|
if ( wi.z < 0.0 ) {
|
|
239
377
|
|
|
240
|
-
|
|
378
|
+
if( transmissionWeight > 0.0 ) {
|
|
379
|
+
|
|
380
|
+
tpdf = transmissionPDF( wo, wi, surf );
|
|
381
|
+
|
|
382
|
+
}
|
|
241
383
|
|
|
242
384
|
} else {
|
|
243
385
|
|
|
244
|
-
|
|
245
|
-
|
|
386
|
+
if( diffuseWeight > 0.0 ) {
|
|
387
|
+
|
|
388
|
+
dpdf = diffusePDF( wo, wi, surf );
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if( specularWeight > 0.0 ) {
|
|
393
|
+
|
|
394
|
+
spdf = specularPDF( wo, wi, surf );
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
401
|
+
|
|
402
|
+
cpdf = clearcoatPDF( clearcoatWo, clearcoatWi, surf );
|
|
246
403
|
|
|
247
404
|
}
|
|
248
405
|
|
|
249
|
-
float transSpecularProb = mix( reflectance, 1.0, metalness );
|
|
250
|
-
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
251
406
|
float pdf =
|
|
252
|
-
|
|
253
|
-
+
|
|
254
|
-
+
|
|
255
|
-
+
|
|
407
|
+
dpdf * diffuseWeight
|
|
408
|
+
+ spdf * specularWeight
|
|
409
|
+
+ tpdf * transmissionWeight
|
|
410
|
+
+ cpdf * clearcoatWeight;
|
|
411
|
+
|
|
412
|
+
// retrieve specular rays for the shadows flag
|
|
413
|
+
specularPdf = spdf * specularWeight + cpdf * clearcoatWeight;
|
|
256
414
|
|
|
257
415
|
return pdf;
|
|
258
416
|
|
|
259
417
|
}
|
|
260
418
|
|
|
261
|
-
vec3 bsdfColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
419
|
+
vec3 bsdfColor( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight ) {
|
|
262
420
|
|
|
263
421
|
vec3 color = vec3( 0.0 );
|
|
264
422
|
if ( wi.z < 0.0 ) {
|
|
265
423
|
|
|
266
|
-
|
|
424
|
+
if( transmissionWeight > 0.0 ) {
|
|
425
|
+
|
|
426
|
+
color = transmissionColor( wo, wi, surf );
|
|
427
|
+
|
|
428
|
+
}
|
|
267
429
|
|
|
268
430
|
} else {
|
|
269
431
|
|
|
270
|
-
|
|
271
|
-
|
|
432
|
+
if( diffuseWeight > 0.0 ) {
|
|
433
|
+
|
|
434
|
+
color = diffuseColor( wo, wi, surf );
|
|
435
|
+
color *= 1.0 - surf.transmission;
|
|
272
436
|
|
|
273
|
-
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if( specularWeight > 0.0 ) {
|
|
440
|
+
|
|
441
|
+
color += specularColor( wo, wi, surf );
|
|
442
|
+
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
color *= sheenAlbedoScaling( wo, wi, surf );
|
|
446
|
+
color += sheenColor( wo, wi, surf );
|
|
447
|
+
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
451
|
+
|
|
452
|
+
clearcoatColor( color, clearcoatWo, clearcoatWi, surf );
|
|
274
453
|
|
|
275
454
|
}
|
|
276
455
|
|
|
@@ -278,62 +457,89 @@ vec3 bsdfColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
278
457
|
|
|
279
458
|
}
|
|
280
459
|
|
|
281
|
-
float bsdfResult( vec3 wo, vec3 wi, SurfaceRec surf, out vec3 color ) {
|
|
460
|
+
float bsdfResult( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out vec3 color ) {
|
|
282
461
|
|
|
283
|
-
|
|
284
|
-
|
|
462
|
+
float diffuseWeight;
|
|
463
|
+
float specularWeight;
|
|
464
|
+
float transmissionWeight;
|
|
465
|
+
float clearcoatWeight;
|
|
466
|
+
getLobeWeights( wo, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
467
|
+
|
|
468
|
+
float specularPdf;
|
|
469
|
+
color = bsdfColor( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
470
|
+
return bsdfPdf( wo, clearcoatWo, wi, clearcoatWi, surf, specularPdf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
285
471
|
|
|
286
472
|
}
|
|
287
473
|
|
|
288
|
-
SampleRec bsdfSample( vec3 wo, SurfaceRec surf ) {
|
|
474
|
+
SampleRec bsdfSample( vec3 wo, vec3 clearcoatWo, mat3 normalBasis, mat3 invBasis, mat3 clearcoatNormalBasis, mat3 clearcoatInvBasis, SurfaceRec surf ) {
|
|
289
475
|
|
|
290
|
-
float
|
|
291
|
-
float
|
|
292
|
-
float
|
|
293
|
-
|
|
476
|
+
float diffuseWeight;
|
|
477
|
+
float specularWeight;
|
|
478
|
+
float transmissionWeight;
|
|
479
|
+
float clearcoatWeight;
|
|
480
|
+
getLobeWeights( wo, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
294
481
|
|
|
295
|
-
float
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if ( cannotRefract ) {
|
|
482
|
+
float pdf[4];
|
|
483
|
+
pdf[0] = diffuseWeight;
|
|
484
|
+
pdf[1] = specularWeight;
|
|
485
|
+
pdf[2] = transmissionWeight;
|
|
486
|
+
pdf[3] = clearcoatWeight;
|
|
301
487
|
|
|
302
|
-
|
|
488
|
+
float cdf[4];
|
|
489
|
+
cdf[0] = pdf[0];
|
|
490
|
+
cdf[1] = pdf[1] + cdf[0];
|
|
491
|
+
cdf[2] = pdf[2] + cdf[1];
|
|
492
|
+
cdf[3] = pdf[3] + cdf[2];
|
|
303
493
|
|
|
304
|
-
|
|
494
|
+
if( cdf[3] != 0.0 ) {
|
|
305
495
|
|
|
306
|
-
|
|
307
|
-
|
|
496
|
+
float invMaxCdf = 1.0 / cdf[3];
|
|
497
|
+
cdf[0] *= invMaxCdf;
|
|
498
|
+
cdf[1] *= invMaxCdf;
|
|
499
|
+
cdf[2] *= invMaxCdf;
|
|
500
|
+
cdf[3] *= invMaxCdf;
|
|
308
501
|
|
|
309
|
-
|
|
310
|
-
if ( rand() < specularProb ) {
|
|
502
|
+
} else {
|
|
311
503
|
|
|
312
|
-
|
|
504
|
+
cdf[0] = 1.0;
|
|
505
|
+
cdf[1] = 0.0;
|
|
506
|
+
cdf[2] = 0.0;
|
|
507
|
+
cdf[3] = 0.0;
|
|
313
508
|
|
|
314
|
-
|
|
509
|
+
}
|
|
315
510
|
|
|
316
|
-
|
|
511
|
+
vec3 wi;
|
|
512
|
+
vec3 clearcoatWi;
|
|
317
513
|
|
|
318
|
-
|
|
514
|
+
float r = rand();
|
|
515
|
+
if ( r <= cdf[0] ) {
|
|
319
516
|
|
|
320
|
-
|
|
517
|
+
wi = diffuseDirection( wo, surf );
|
|
518
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
321
519
|
|
|
322
|
-
|
|
323
|
-
if ( rand() < specularProb ) {
|
|
520
|
+
} else if ( r <= cdf[1] ) {
|
|
324
521
|
|
|
325
|
-
|
|
522
|
+
wi = specularDirection( wo, surf );
|
|
523
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
326
524
|
|
|
327
|
-
|
|
525
|
+
} else if ( r <= cdf[2] ) {
|
|
328
526
|
|
|
329
|
-
|
|
527
|
+
wi = transmissionDirection( wo, surf );
|
|
528
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
330
529
|
|
|
331
|
-
|
|
530
|
+
} else if ( r <= cdf[3] ) {
|
|
531
|
+
|
|
532
|
+
clearcoatWi = clearcoatDirection( clearcoatWo, surf );
|
|
533
|
+
wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );
|
|
332
534
|
|
|
333
535
|
}
|
|
334
536
|
|
|
335
|
-
|
|
336
|
-
result.
|
|
537
|
+
SampleRec result;
|
|
538
|
+
result.pdf = bsdfPdf( wo, clearcoatWo, wi, clearcoatWi, surf, result.specularPdf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
539
|
+
result.color = bsdfColor( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
540
|
+
result.direction = wi;
|
|
541
|
+
result.clearcoatDirection = clearcoatWi;
|
|
542
|
+
|
|
337
543
|
return result;
|
|
338
544
|
|
|
339
545
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export const shaderSheenFunctions = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// See equation (2) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
4
|
+
float velvetD( float cosThetaH, float roughness ) {
|
|
5
|
+
|
|
6
|
+
float alpha = max( roughness, 0.07 );
|
|
7
|
+
alpha = alpha * alpha;
|
|
8
|
+
|
|
9
|
+
float invAlpha = 1.0 / alpha;
|
|
10
|
+
|
|
11
|
+
float sqrCosThetaH = cosThetaH * cosThetaH;
|
|
12
|
+
float sinThetaH = max( 1.0 - sqrCosThetaH, 0.001 );
|
|
13
|
+
|
|
14
|
+
return ( 2.0 + invAlpha ) * pow( sinThetaH, 0.5 * invAlpha ) / ( 2.0 * PI );
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
float velvetParamsInterpolate( int i, float oneMinusAlphaSquared ) {
|
|
19
|
+
|
|
20
|
+
const float p0[5] = float[5]( 25.3245, 3.32435, 0.16801, -1.27393, -4.85967 );
|
|
21
|
+
const float p1[5] = float[5]( 21.5473, 3.82987, 0.19823, -1.97760, -4.32054 );
|
|
22
|
+
|
|
23
|
+
return mix( p1[i], p0[i], oneMinusAlphaSquared );
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
float velvetL( float x, float alpha ) {
|
|
28
|
+
|
|
29
|
+
float oneMinusAlpha = 1.0 - alpha;
|
|
30
|
+
float oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;
|
|
31
|
+
|
|
32
|
+
float a = velvetParamsInterpolate( 0, oneMinusAlphaSquared );
|
|
33
|
+
float b = velvetParamsInterpolate( 1, oneMinusAlphaSquared );
|
|
34
|
+
float c = velvetParamsInterpolate( 2, oneMinusAlphaSquared );
|
|
35
|
+
float d = velvetParamsInterpolate( 3, oneMinusAlphaSquared );
|
|
36
|
+
float e = velvetParamsInterpolate( 4, oneMinusAlphaSquared );
|
|
37
|
+
|
|
38
|
+
return a / ( 1.0 + b * pow( abs( x ), c ) ) + d * x + e;
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// See equation (3) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
43
|
+
float velvetLambda( float cosTheta, float alpha ) {
|
|
44
|
+
|
|
45
|
+
return abs( cosTheta ) < 0.5 ? exp( velvetL( cosTheta, alpha ) ) : exp( 2.0 * velvetL( 0.5, alpha ) - velvetL( 1.0 - cosTheta, alpha ) );
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// See Section 3, Shadowing Term, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
50
|
+
float velvetG( float cosThetaO, float cosThetaI, float roughness ) {
|
|
51
|
+
|
|
52
|
+
float alpha = max( roughness, 0.07 );
|
|
53
|
+
alpha = alpha * alpha;
|
|
54
|
+
|
|
55
|
+
return 1.0 / ( 1.0 + velvetLambda( cosThetaO, alpha ) + velvetLambda( cosThetaI, alpha ) );
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
float directionalAlbedoSheen( float cosTheta, float alpha ) {
|
|
60
|
+
|
|
61
|
+
cosTheta = saturate( cosTheta );
|
|
62
|
+
|
|
63
|
+
float c = 1.0 - cosTheta;
|
|
64
|
+
float c3 = c * c * c;
|
|
65
|
+
|
|
66
|
+
return 0.65584461 * c3 + 1.0 / ( 4.16526551 + exp( -7.97291361 * sqrt( alpha ) + 6.33516894 ) );
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
float sheenAlbedoScaling( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
71
|
+
|
|
72
|
+
float alpha = max( surf.sheenRoughness, 0.07 );
|
|
73
|
+
alpha = alpha * alpha;
|
|
74
|
+
|
|
75
|
+
float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );
|
|
76
|
+
|
|
77
|
+
float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );
|
|
78
|
+
float eWi = directionalAlbedoSheen( saturateCos( wi.z ), alpha );
|
|
79
|
+
|
|
80
|
+
return min( 1.0 - maxSheenColor * eWo, 1.0 - maxSheenColor * eWi );
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// See Section 5, Layering, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
85
|
+
float sheenAlbedoScaling( vec3 wo, SurfaceRec surf ) {
|
|
86
|
+
|
|
87
|
+
float alpha = max( surf.sheenRoughness, 0.07 );
|
|
88
|
+
alpha = alpha * alpha;
|
|
89
|
+
|
|
90
|
+
float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );
|
|
91
|
+
|
|
92
|
+
float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );
|
|
93
|
+
|
|
94
|
+
return 1.0 - maxSheenColor * eWo;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
`;
|