three-gpu-pathtracer 0.0.14 → 0.0.16

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.
Files changed (76) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1004 -981
  3. package/build/index.module.js +7413 -6902
  4. package/build/index.module.js.map +1 -1
  5. package/build/index.umd.cjs +7446 -6933
  6. package/build/index.umd.cjs.map +1 -1
  7. package/package.json +73 -73
  8. package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
  9. package/src/core/MaterialReducer.js +256 -256
  10. package/src/core/PathTracingRenderer.js +346 -346
  11. package/src/core/PathTracingSceneGenerator.js +69 -69
  12. package/src/core/QuiltPathTracingRenderer.js +223 -223
  13. package/src/detectors/CompatibilityDetector.js +38 -0
  14. package/src/detectors/MaterialCompileDetector.js +50 -0
  15. package/src/detectors/PrecisionDetector.js +85 -0
  16. package/src/detectors/PrecisionMaterial.js +160 -0
  17. package/src/index.js +40 -36
  18. package/src/materials/MaterialBase.js +56 -56
  19. package/src/materials/debug/GraphMaterial.js +243 -243
  20. package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
  21. package/src/materials/fullscreen/BlendMaterial.js +67 -67
  22. package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
  23. package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
  24. package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
  25. package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
  26. package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
  27. package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
  28. package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
  29. package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
  30. package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
  31. package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
  32. package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
  33. package/src/materials/surface/FogVolumeMaterial.js +23 -23
  34. package/src/objects/EquirectCamera.js +13 -13
  35. package/src/objects/PhysicalCamera.js +42 -28
  36. package/src/objects/PhysicalSpotLight.js +25 -14
  37. package/src/objects/ShapedAreaLight.js +22 -12
  38. package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
  39. package/src/shader/bsdf/fog.glsl.js +22 -23
  40. package/src/shader/bsdf/ggx.glsl.js +102 -102
  41. package/src/shader/bsdf/iridescence.glsl.js +135 -135
  42. package/src/shader/bsdf/sheen.glsl.js +98 -98
  43. package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
  44. package/src/shader/common/bvhAnyHit.glsl.js +76 -76
  45. package/src/shader/common/fresnel.glsl.js +98 -98
  46. package/src/shader/common/intersectShapes.glsl.js +62 -62
  47. package/src/shader/common/math.glsl.js +81 -81
  48. package/src/shader/common/utils.glsl.js +116 -116
  49. package/src/shader/rand/pcg.glsl.js +57 -57
  50. package/src/shader/rand/sobol.glsl.js +256 -256
  51. package/src/shader/sampling/equirectSampling.glsl.js +62 -62
  52. package/src/shader/sampling/lightSampling.glsl.js +223 -223
  53. package/src/shader/sampling/shapeSampling.glsl.js +86 -86
  54. package/src/shader/structs/cameraStruct.glsl.js +13 -13
  55. package/src/shader/structs/equirectStruct.glsl.js +13 -14
  56. package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
  57. package/src/shader/structs/lightsStruct.glsl.js +78 -78
  58. package/src/shader/structs/materialStruct.glsl.js +207 -207
  59. package/src/textures/GradientEquirectTexture.js +35 -35
  60. package/src/textures/ProceduralEquirectTexture.js +75 -75
  61. package/src/uniforms/AttributesTextureArray.js +35 -35
  62. package/src/uniforms/EquirectHdrInfoUniform.js +269 -277
  63. package/src/uniforms/FloatAttributeTextureArray.js +169 -169
  64. package/src/uniforms/IESProfilesTexture.js +100 -100
  65. package/src/uniforms/LightsInfoUniformStruct.js +212 -212
  66. package/src/uniforms/MaterialsTexture.js +503 -503
  67. package/src/uniforms/PhysicalCameraUniform.js +36 -36
  68. package/src/uniforms/RenderTarget2DArray.js +97 -97
  69. package/src/uniforms/utils.js +30 -30
  70. package/src/utils/BlurredEnvMapGenerator.js +116 -116
  71. package/src/utils/GeometryPreparationUtils.js +214 -214
  72. package/src/utils/IESLoader.js +325 -325
  73. package/src/utils/SobolNumberMapGenerator.js +80 -80
  74. package/src/utils/UVUnwrapper.js +101 -101
  75. package/src/utils/macroify.js +9 -9
  76. package/src/workers/PathTracingSceneWorker.js +42 -42
@@ -31,7 +31,7 @@ import { lightSamplingGLSL } from '../../shader/sampling/lightSampling.glsl.js';
31
31
  import { shapeSamplingGLSL } from '../../shader/sampling/shapeSampling.glsl.js';
32
32
 
33
33
  // common glsl
34
- import { intersectShapesGLSL } from '../../shader/common/intersectShapes.glsl';
34
+ import { intersectShapesGLSL } from '../../shader/common/intersectShapes.glsl.js';
35
35
  import { mathGLSL } from '../../shader/common/math.glsl.js';
36
36
  import { utilsGLSL } from '../../shader/common/utils.glsl.js';
37
37
  import { fresnelGLSL } from '../../shader/common/fresnel.glsl.js';
@@ -42,10 +42,12 @@ import { pcgGLSL } from '../../shader/rand/pcg.glsl.js';
42
42
  import { sobolCommonGLSL, sobolSamplingGLSL } from '../../shader/rand/sobol.glsl.js';
43
43
 
44
44
  // path tracer utils
45
+ import { renderStructsGLSL } from './glsl/renderStructs.glsl.js';
45
46
  import { cameraUtilsGLSL } from './glsl/cameraUtils.glsl.js';
46
47
  import { attenuateHitGLSL } from './glsl/attenuateHit.glsl.js';
47
48
  import { traceSceneGLSL } from './glsl/traceScene.glsl.js';
48
49
  import { getSurfaceRecordGLSL } from './glsl/getSurfaceRecord.glsl.js';
50
+ import { directLightContributionGLSL } from './glsl/directLightContribution.glsl.js';
49
51
 
50
52
  export class PhysicalPathTracingMaterial extends MaterialBase {
51
53
 
@@ -75,6 +77,8 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
75
77
  // 2 = Equirectangular
76
78
  CAMERA_TYPE: 0,
77
79
 
80
+ DEBUG_MODE: 0,
81
+
78
82
  ATTR_NORMAL: 0,
79
83
  ATTR_TANGENT: 1,
80
84
  ATTR_UV: 2,
@@ -212,9 +216,10 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
212
216
 
213
217
  varying vec2 vUv;
214
218
 
215
- ${ cameraUtilsGLSL }
216
- ${ traceSceneGLSL }
217
- ${ attenuateHitGLSL }
219
+ // globals
220
+ mat3 envRotation3x3;
221
+ mat3 invEnvRotation3x3;
222
+ float lightsDenom;
218
223
 
219
224
  float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
220
225
 
@@ -244,6 +249,11 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
244
249
 
245
250
  }
246
251
 
252
+ ${ renderStructsGLSL }
253
+ ${ cameraUtilsGLSL }
254
+ ${ traceSceneGLSL }
255
+ ${ attenuateHitGLSL }
256
+ ${ directLightContributionGLSL }
247
257
  ${ getSurfaceRecordGLSL }
248
258
 
249
259
  void main() {
@@ -254,85 +264,73 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
254
264
  sobolPathIndex = uint( seed );
255
265
 
256
266
  // get camera ray
257
- vec3 rayDirection, rayOrigin;
258
- getCameraRay( rayDirection, rayOrigin );
267
+ Ray ray = getCameraRay();
259
268
 
260
269
  // inverse environment rotation
261
- mat3 envRotation3x3 = mat3( environmentRotation );
262
- mat3 invEnvRotation3x3 = inverse( envRotation3x3 );
263
- float lightsDenom = environmentIntensity == 0.0 && lights.count != 0u ? float( lights.count ) : float( lights.count + 1u );
270
+ envRotation3x3 = mat3( environmentRotation );
271
+ invEnvRotation3x3 = inverse( envRotation3x3 );
272
+ lightsDenom = environmentIntensity == 0.0 && lights.count != 0u ? float( lights.count ) : float( lights.count + 1u );
264
273
 
265
274
  // final color
266
- gl_FragColor = vec4( 0.0 );
267
- gl_FragColor.a = 1.0;
275
+ gl_FragColor = vec4( 0, 0, 0, 1 );
268
276
 
269
- // hit results
270
- uvec4 faceIndices = uvec4( 0u );
271
- vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
272
- vec3 barycoord = vec3( 0.0 );
273
- float side = 1.0;
274
- float dist = 0.0;
277
+ // surface results
278
+ SurfaceHit surfaceHit;
279
+ LightRecord lightRec;
280
+ ScatterRecord scatterRec;
275
281
 
276
282
  // path tracing state
277
- float accumulatedRoughness = 0.0;
278
- bool transmissiveRay = true;
279
- bool isShadowRay = false;
280
- int transmissiveTraversals = transmissiveBounces;
281
- vec3 throughputColor = vec3( 1.0 );
282
- ScatterRecord sampleRec;
283
- int i;
284
-
285
- Material fogMaterial;
283
+ RenderState state = initRenderState();
284
+ state.transmissiveTraversals = transmissiveBounces;
286
285
  #if FEATURE_FOG
287
286
 
288
- fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
289
- bvh, rayOrigin, - rayDirection,
287
+ state.fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
288
+ bvh, ray.origin, - ray.direction,
290
289
  materialIndexAttribute, materials,
291
- fogMaterial
290
+ state.fogMaterial
292
291
  );
293
292
 
294
293
  #endif
295
294
 
296
- for ( i = 0; i < bounces; i ++ ) {
295
+ for ( int i = 0; i < bounces; i ++ ) {
297
296
 
298
297
  sobolBounceIndex ++;
299
298
 
300
- bool firstRay = i == 0 && transmissiveTraversals == transmissiveBounces;
299
+ state.depth ++;
300
+ state.traversals = bounces - i;
301
+ state.firstRay = i == 0 && state.transmissiveTraversals == transmissiveBounces;
301
302
 
302
- LightSampleRecord lightSampleRec;
303
303
  int hitType = traceScene(
304
- rayOrigin, rayDirection,
305
- bvh, lights, fogMaterial,
306
- faceIndices, faceNormal, barycoord, side, dist,
307
- lightSampleRec
304
+ ray, bvh, lights, state.fogMaterial,
305
+ surfaceHit, lightRec
308
306
  );
309
307
 
310
308
  if ( hitType == LIGHT_HIT ) {
311
309
 
312
- if ( firstRay || transmissiveRay ) {
310
+ if ( state.firstRay || state.transmissiveRay ) {
313
311
 
314
- gl_FragColor.rgb += lightSampleRec.emission * throughputColor;
312
+ gl_FragColor.rgb += lightRec.emission * state.throughputColor;
315
313
 
316
314
  } else {
317
315
 
318
316
  #if FEATURE_MIS
319
317
 
320
318
  // NOTE: we skip MIS for punctual lights since they are not supported in forward PT case
321
- if ( lightSampleRec.type == SPOT_LIGHT_TYPE || lightSampleRec.type == DIR_LIGHT_TYPE || lightSampleRec.type == POINT_LIGHT_TYPE ) {
319
+ if ( lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ) {
322
320
 
323
- gl_FragColor.rgb += lightSampleRec.emission * throughputColor;
321
+ gl_FragColor.rgb += lightRec.emission * state.throughputColor;
324
322
 
325
323
  } else {
326
324
 
327
325
  // weight the contribution
328
- float misWeight = misHeuristic( sampleRec.pdf, lightSampleRec.pdf / lightsDenom );
329
- gl_FragColor.rgb += lightSampleRec.emission * throughputColor * misWeight;
326
+ float misWeight = misHeuristic( scatterRec.pdf, lightRec.pdf / lightsDenom );
327
+ gl_FragColor.rgb += lightRec.emission * state.throughputColor * misWeight;
330
328
 
331
329
  }
332
330
 
333
331
  #else
334
332
 
335
- gl_FragColor.rgb += lightSampleRec.emission * throughputColor;
333
+ gl_FragColor.rgb += lightRec.emission * state.throughputColor;
336
334
 
337
335
  #endif
338
336
 
@@ -341,9 +339,9 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
341
339
 
342
340
  } else if ( hitType == NO_HIT ) {
343
341
 
344
- if ( firstRay || transmissiveRay ) {
342
+ if ( state.firstRay || state.transmissiveRay ) {
345
343
 
346
- gl_FragColor.rgb += sampleBackground( envRotation3x3 * rayDirection, sobol2( 2 ) ) * throughputColor;
344
+ gl_FragColor.rgb += sampleBackground( envRotation3x3 * ray.direction, sobol2( 2 ) ) * state.throughputColor;
347
345
  gl_FragColor.a = backgroundAlpha;
348
346
 
349
347
  } else {
@@ -352,19 +350,19 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
352
350
 
353
351
  // get the PDF of the hit envmap point
354
352
  vec3 envColor;
355
- float envPdf = sampleEquirect( envMapInfo, envRotation3x3 * rayDirection, envColor );
353
+ float envPdf = sampleEquirect( envMapInfo, envRotation3x3 * ray.direction, envColor );
356
354
  envPdf /= lightsDenom;
357
355
 
358
356
  // and weight the contribution
359
- float misWeight = misHeuristic( sampleRec.pdf, envPdf );
360
- gl_FragColor.rgb += environmentIntensity * envColor * throughputColor * misWeight;
357
+ float misWeight = misHeuristic( scatterRec.pdf, envPdf );
358
+ gl_FragColor.rgb += environmentIntensity * envColor * state.throughputColor * misWeight;
361
359
 
362
360
  #else
363
361
 
364
362
  gl_FragColor.rgb +=
365
363
  environmentIntensity *
366
- sampleEquirectColor( envMapInfo.map, envRotation3x3 * rayDirection ) *
367
- throughputColor;
364
+ sampleEquirectColor( envMapInfo.map, envRotation3x3 * ray.direction ) *
365
+ state.throughputColor;
368
366
 
369
367
  #endif
370
368
 
@@ -373,32 +371,33 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
373
371
 
374
372
  }
375
373
 
376
- uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
374
+ uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;
377
375
  Material material = readMaterialInfo( materials, materialIndex );
378
376
 
379
377
  #if FEATURE_FOG
380
378
 
381
379
  if ( hitType == FOG_HIT ) {
382
380
 
383
- material = fogMaterial;
384
- accumulatedRoughness += 0.2;
381
+ material = state.fogMaterial;
382
+ state.accumulatedRoughness += 0.2;
385
383
 
386
384
  } else if ( material.fogVolume ) {
387
385
 
388
- fogMaterial = material;
389
- fogMaterial.fogVolume = side == 1.0;
386
+ state.fogMaterial = material;
387
+ state.fogMaterial.fogVolume = surfaceHit.side == 1.0;
390
388
 
391
- rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
389
+ ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
392
390
 
393
- i -= sign( transmissiveTraversals );
394
- transmissiveTraversals -= sign( transmissiveTraversals );
391
+ i -= sign( state.transmissiveTraversals );
392
+ state.transmissiveTraversals -= sign( state.transmissiveTraversals );
395
393
  continue;
396
394
 
397
395
  }
398
396
 
399
397
  #endif
400
398
 
401
- if ( material.matte && firstRay ) {
399
+ // early out if this is a matte material
400
+ if ( material.matte && state.firstRay ) {
402
401
 
403
402
  gl_FragColor = vec4( 0.0 );
404
403
  break;
@@ -407,9 +406,9 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
407
406
 
408
407
  // if we've determined that this is a shadow ray and we've hit an item with no shadow casting
409
408
  // then skip it
410
- if ( ! material.castShadow && isShadowRay ) {
409
+ if ( ! material.castShadow && state.isShadowRay ) {
411
410
 
412
- rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
411
+ ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
413
412
  continue;
414
413
 
415
414
  }
@@ -417,164 +416,77 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
417
416
  SurfaceRecord surf;
418
417
  if (
419
418
  getSurfaceRecord(
420
- material, attributesArray, side, barycoord, faceIndices,
421
- faceNormal, accumulatedRoughness,
419
+ material, surfaceHit, attributesArray, state.accumulatedRoughness,
422
420
  surf
423
421
  ) == SKIP_SURFACE
424
422
  ) {
425
423
 
426
424
  // only allow a limited number of transparency discards otherwise we could
427
425
  // crash the context with too long a loop.
428
- i -= sign( transmissiveTraversals );
429
- transmissiveTraversals -= sign( transmissiveTraversals );
426
+ i -= sign( state.transmissiveTraversals );
427
+ state.transmissiveTraversals -= sign( state.transmissiveTraversals );
430
428
 
431
- rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
429
+ ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
432
430
  continue;
433
431
 
434
432
  }
435
433
 
436
- faceNormal = surf.faceNormal;
434
+ scatterRec = bsdfSample( - ray.direction, surf );
435
+ state.isShadowRay = scatterRec.specularPdf < sobol( 4 );
437
436
 
438
- mat3 normalBasis = getBasisFromNormal( surf.normal );
439
- mat3 invBasis = inverse( normalBasis );
437
+ bool isBelowSurface = ! surf.volumeParticle && dot( scatterRec.direction, surf.faceNormal ) < 0.0;
438
+ vec3 hitPoint = stepRayOrigin( ray.origin, ray.direction, isBelowSurface ? - surf.faceNormal : surf.faceNormal, surfaceHit.dist );
440
439
 
441
- mat3 clearcoatNormalBasis = getBasisFromNormal( surf.clearcoatNormal );
442
- mat3 clearcoatInvBasis = inverse( clearcoatNormalBasis );
443
-
444
- vec3 outgoing = - normalize( invBasis * rayDirection );
445
- vec3 clearcoatOutgoing = - normalize( clearcoatInvBasis * rayDirection );
446
- sampleRec = bsdfSample( outgoing, clearcoatOutgoing, normalBasis, invBasis, clearcoatNormalBasis, clearcoatInvBasis, surf );
447
-
448
- bool wasBelowSurface = ! surf.volumeParticle && dot( rayDirection, faceNormal ) > 0.0;
449
- isShadowRay = sampleRec.specularPdf < sobol( 4 );
450
-
451
- vec3 prevRayDirection = rayDirection;
452
- rayDirection = normalize( normalBasis * sampleRec.direction );
453
-
454
- bool isBelowSurface = ! surf.volumeParticle && dot( rayDirection, faceNormal ) < 0.0;
455
- rayOrigin = stepRayOrigin( rayOrigin, prevRayDirection, isBelowSurface ? - faceNormal : faceNormal, dist );
456
-
457
- // direct env map sampling
440
+ // next event estimation
458
441
  #if FEATURE_MIS
459
442
 
460
- // uniformly pick a light or environment map
461
- if( lightsDenom != 0.0 && sobol( 5 ) < float( lights.count ) / lightsDenom ) {
462
-
463
- // sample a light or environment
464
- LightSampleRecord lightSampleRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, sobol3( 6 ) );
465
-
466
- bool isSampleBelowSurface = ! surf.volumeParticle && dot( faceNormal, lightSampleRec.direction ) < 0.0;
467
- if ( isSampleBelowSurface ) {
468
-
469
- lightSampleRec.pdf = 0.0;
443
+ gl_FragColor.rgb += directLightContribution( - ray.direction, surf, state, hitPoint );
470
444
 
471
- }
472
-
473
- // check if a ray could even reach the light area
474
- vec3 attenuatedColor;
475
- if (
476
- lightSampleRec.pdf > 0.0 &&
477
- isDirectionValid( lightSampleRec.direction, surf.normal, faceNormal ) &&
478
- ! attenuateHit( bvh, rayOrigin, lightSampleRec.direction, lightSampleRec.dist, bounces - i, transmissiveTraversals, isShadowRay, fogMaterial, attenuatedColor )
479
- ) {
480
-
481
- // get the material pdf
482
- vec3 sampleColor;
483
- float lightMaterialPdf = bsdfResult( outgoing, clearcoatOutgoing, normalize( invBasis * lightSampleRec.direction ), normalize( clearcoatInvBasis * lightSampleRec.direction ), surf, sampleColor );
484
- bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
485
- if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {
486
-
487
- // weight the direct light contribution
488
- float lightPdf = lightSampleRec.pdf / lightsDenom;
489
- float misWeight = lightSampleRec.type == SPOT_LIGHT_TYPE || lightSampleRec.type == DIR_LIGHT_TYPE || lightSampleRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
490
- gl_FragColor.rgb += attenuatedColor * lightSampleRec.emission * throughputColor * sampleColor * misWeight / lightPdf;
491
-
492
- }
493
-
494
- }
495
-
496
- } else {
497
-
498
- // find a sample in the environment map to include in the contribution
499
- vec3 envColor, envDirection;
500
- float envPdf = sampleEquirectProbability( envMapInfo, sobol2( 7 ), envColor, envDirection );
501
- envDirection = invEnvRotation3x3 * envDirection;
502
-
503
- // this env sampling is not set up for transmissive sampling and yields overly bright
504
- // results so we ignore the sample in this case.
505
- // TODO: this should be improved but how? The env samples could traverse a few layers?
506
- bool isSampleBelowSurface = ! surf.volumeParticle && dot( faceNormal, envDirection ) < 0.0;
507
- if ( isSampleBelowSurface ) {
508
-
509
- envPdf = 0.0;
510
-
511
- }
512
-
513
- // check if a ray could even reach the surface
514
- vec3 attenuatedColor;
515
- if (
516
- envPdf > 0.0 &&
517
- isDirectionValid( envDirection, surf.normal, faceNormal ) &&
518
- ! attenuateHit( bvh, rayOrigin, envDirection, INFINITY, bounces - i, transmissiveTraversals, isShadowRay, fogMaterial, attenuatedColor )
519
- ) {
520
-
521
- // get the material pdf
522
- vec3 sampleColor;
523
- float envMaterialPdf = bsdfResult( outgoing, clearcoatOutgoing, normalize( invBasis * envDirection ), normalize( clearcoatInvBasis * envDirection ), surf, sampleColor );
524
- bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
525
- if ( envMaterialPdf > 0.0 && isValidSampleColor ) {
526
-
527
- // weight the direct light contribution
528
- envPdf /= lightsDenom;
529
- float misWeight = misHeuristic( envPdf, envMaterialPdf );
530
- gl_FragColor.rgb += attenuatedColor * environmentIntensity * envColor * throughputColor * sampleColor * misWeight / envPdf;
531
-
532
- }
533
-
534
- }
535
-
536
- }
537
445
  #endif
538
446
 
539
447
  // accumulate a roughness value to offset diffuse, specular, diffuse rays that have high contribution
540
448
  // to a single pixel resulting in fireflies
449
+ // TODO: handle transmissive surfaces
541
450
  if ( ! surf.volumeParticle && ! isBelowSurface ) {
542
451
 
543
452
  // determine if this is a rough normal or not by checking how far off straight up it is
544
- vec3 halfVector = normalize( outgoing + sampleRec.direction );
545
- vec3 clearcoatHalfVector = normalize( clearcoatOutgoing + sampleRec.clearcoatDirection );
546
- accumulatedRoughness += max( sin( acosApprox( halfVector.z ) ), sin( acosApprox( clearcoatHalfVector.z ) ) );
453
+ vec3 halfVector = normalize( - ray.direction + scatterRec.direction );
454
+ state.accumulatedRoughness += max(
455
+ sin( acosApprox( dot( halfVector, surf.normal ) ) ),
456
+ sin( acosApprox( dot( halfVector, surf.clearcoatNormal ) ) )
457
+ );
547
458
 
548
- transmissiveRay = false;
459
+ state.transmissiveRay = false;
549
460
 
550
461
  }
551
462
 
552
- // if we're bouncing around the inside a transmissive material then decrement
553
- // perform this separate from a bounce
554
- bool isTransmissiveRay = ! surf.volumeParticle && dot( rayDirection, faceNormal * side ) < 0.0;
555
- if ( ( isTransmissiveRay || isBelowSurface ) && transmissiveTraversals > 0 ) {
463
+ // accumulate emissive color
464
+ gl_FragColor.rgb += ( surf.emission * state.throughputColor );
556
465
 
557
- transmissiveTraversals --;
558
- i --;
466
+ // skip the sample if our PDF or ray is impossible
467
+ if ( scatterRec.pdf <= 0.0 || ! isDirectionValid( scatterRec.direction, surf.normal, surf.faceNormal ) ) {
468
+
469
+ break;
559
470
 
560
471
  }
561
472
 
562
- #if FEATURE_FOG
563
- if ( material.fogVolume ) {
473
+ // if we're bouncing around the inside a transmissive material then decrement
474
+ // perform this separate from a bounce
475
+ bool isTransmissiveRay = ! surf.volumeParticle && dot( scatterRec.direction, surf.faceNormal * surfaceHit.side ) < 0.0;
476
+ if ( ( isTransmissiveRay || isBelowSurface ) && state.transmissiveTraversals > 0 ) {
564
477
 
565
- transmissiveTraversals --;
478
+ state.transmissiveTraversals --;
566
479
  i --;
567
480
 
568
481
  }
569
- #endif
570
482
 
571
- // accumulate color
572
- gl_FragColor.rgb += ( surf.emission * throughputColor );
483
+ //
573
484
 
574
- // skip the sample if our PDF or ray is impossible
575
- if ( sampleRec.pdf <= 0.0 || ! isDirectionValid( rayDirection, surf.normal, faceNormal ) ) {
485
+ // handle throughput color transformation
486
+ // attenuate the throughput color by the medium color
487
+ if ( ! surf.frontFace ) {
576
488
 
577
- break;
489
+ state.throughputColor *= transmissionAttenuation( surfaceHit.dist, surf.attenuationColor, surf.attenuationDistance );
578
490
 
579
491
  }
580
492
 
@@ -583,10 +495,10 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
583
495
  // russian roulette path termination
584
496
  // https://www.arnoldrenderer.com/research/physically_based_shader_design_in_arnold.pdf
585
497
  uint minBounces = 3u;
586
- float depthProb = float( sobolBounceIndex < minBounces );
498
+ float depthProb = float( state.depth < minBounces );
587
499
 
588
- float rrProb = luminance( throughputColor * sampleRec.color / sampleRec.pdf );
589
- rrProb /= luminance( throughputColor );
500
+ float rrProb = luminance( state.throughputColor * scatterRec.color / scatterRec.pdf );
501
+ rrProb /= luminance( state.throughputColor );
590
502
  rrProb = sqrt( rrProb );
591
503
  rrProb = max( rrProb, depthProb );
592
504
  rrProb = min( rrProb, 1.0 );
@@ -597,31 +509,41 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
597
509
  }
598
510
 
599
511
  // perform sample clamping here to avoid bright pixels
600
- throughputColor *= min( 1.0 / rrProb, 20.0 );
512
+ state.throughputColor *= min( 1.0 / rrProb, 20.0 );
601
513
 
602
514
  #endif
603
515
 
604
- throughputColor *= sampleRec.color / sampleRec.pdf;
605
-
606
- // attenuate the throughput color by the medium color
607
- if ( side == - 1.0 ) {
608
-
609
- throughputColor *= transmissionAttenuation( dist, surf.attenuationColor, surf.attenuationDistance );
610
-
611
- }
612
-
613
- // discard the sample if there are any NaNs
614
- if ( any( isnan( throughputColor ) ) || any( isinf( throughputColor ) ) ) {
516
+ // adjust the throughput and discard and exit if we find discard the sample if there are any NaNs
517
+ state.throughputColor *= scatterRec.color / scatterRec.pdf;
518
+ if ( any( isnan( state.throughputColor ) ) || any( isinf( state.throughputColor ) ) ) {
615
519
 
616
520
  break;
617
521
 
618
522
  }
619
523
 
524
+ //
525
+
526
+ // prepare for next ray
527
+ ray.direction = scatterRec.direction;
528
+ ray.origin = hitPoint;
620
529
 
621
530
  }
622
531
 
623
532
  gl_FragColor.a *= opacity;
624
533
 
534
+ #if DEBUG_MODE == 1
535
+
536
+ // output the number of rays checked in the path and number of
537
+ // transmissive rays encountered.
538
+ gl_FragColor.rgb = vec3(
539
+ float( state.depth ),
540
+ transmissiveBounces - state.transmissiveTraversals,
541
+ 0.0
542
+ );
543
+ gl_FragColor.a = 1.0;
544
+
545
+ #endif
546
+
625
547
  }
626
548
 
627
549
  `