three-gpu-pathtracer 0.0.11 → 0.0.13
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 +81 -6
- package/build/index.module.js +502 -125
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +501 -123
- package/build/index.umd.cjs.map +1 -1
- package/package.json +6 -2
- package/src/core/PathTracingRenderer.js +86 -15
- package/src/core/PathTracingSceneGenerator.js +1 -1
- package/src/core/QuiltPathTracingRenderer.js +223 -0
- package/src/index.js +1 -0
- package/src/materials/PhysicalPathTracingMaterial.js +80 -49
- package/src/shader/shaderBvhAnyHit.js +76 -0
- package/src/shader/shaderIridescenceFunctions.js +7 -2
- package/src/shader/shaderMaterialSampling.js +59 -47
- package/src/shader/shaderStructs.js +2 -0
- package/src/shader/shaderUtils.js +16 -0
- package/src/uniforms/EquirectHdrInfoUniform.js +20 -6
- package/src/uniforms/LightsInfoUniformStruct.js +9 -4
- package/src/uniforms/MaterialsTexture.js +1 -1
package/build/index.module.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ShaderMaterial, NoBlending, Vector2, WebGLRenderTarget, FloatType, RGBAFormat, NearestFilter, NormalBlending, Color, BufferAttribute, Mesh, BufferGeometry,
|
|
1
|
+
import { ShaderMaterial, NoBlending, Vector2, WebGLRenderTarget, FloatType, RGBAFormat, NearestFilter, Vector4, NormalBlending, Color, Vector3, MathUtils, Matrix4, PerspectiveCamera, BufferAttribute, Mesh, BufferGeometry, Camera, SpotLight, RectAreaLight, Spherical, DataTexture, EquirectangularReflectionMapping, RepeatWrapping, ClampToEdgeWrapping, LinearFilter, DoubleSide, BackSide, FrontSide, WebGLArrayRenderTarget, UnsignedByteType, MeshBasicMaterial, NoToneMapping, Source, HalfFloatType, DataUtils, RedFormat, Quaternion, Loader, FileLoader, PMREMGenerator, DataArrayTexture } from 'three';
|
|
2
2
|
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
|
|
3
3
|
import { StaticGeometryGenerator, SAH, MeshBVH, FloatVertexAttributeTexture, MeshBVHUniformStruct, UIntVertexAttributeTexture, shaderStructs, shaderIntersectFunction } from 'three-mesh-bvh';
|
|
4
4
|
import { mergeVertices, mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
@@ -456,6 +456,9 @@ class SobolNumberMapGenerator {
|
|
|
456
456
|
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
+
const _scissor = new Vector4();
|
|
460
|
+
const _viewport = new Vector4();
|
|
461
|
+
|
|
459
462
|
function* renderTask() {
|
|
460
463
|
|
|
461
464
|
const {
|
|
@@ -465,10 +468,13 @@ function* renderTask() {
|
|
|
465
468
|
_primaryTarget,
|
|
466
469
|
_blendTargets,
|
|
467
470
|
_sobolTarget,
|
|
471
|
+
_subframe,
|
|
468
472
|
alpha,
|
|
469
473
|
camera,
|
|
470
474
|
material,
|
|
471
475
|
} = this;
|
|
476
|
+
const _ogScissor = new Vector4();
|
|
477
|
+
const _ogViewport = new Vector4();
|
|
472
478
|
|
|
473
479
|
const blendMaterial = _blendQuad.material;
|
|
474
480
|
let [ blendTarget1, blendTarget2 ] = _blendTargets;
|
|
@@ -477,20 +483,22 @@ function* renderTask() {
|
|
|
477
483
|
|
|
478
484
|
if ( alpha ) {
|
|
479
485
|
|
|
480
|
-
blendMaterial.opacity =
|
|
486
|
+
blendMaterial.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
481
487
|
material.blending = NoBlending;
|
|
482
488
|
material.opacity = 1;
|
|
483
489
|
|
|
484
490
|
} else {
|
|
485
491
|
|
|
486
|
-
material.opacity =
|
|
492
|
+
material.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
487
493
|
material.blending = NormalBlending;
|
|
488
494
|
|
|
489
495
|
}
|
|
490
496
|
|
|
497
|
+
const [ subX, subY, subW, subH ] = _subframe;
|
|
498
|
+
|
|
491
499
|
const w = _primaryTarget.width;
|
|
492
500
|
const h = _primaryTarget.height;
|
|
493
|
-
material.resolution.set( w, h );
|
|
501
|
+
material.resolution.set( w * subW, h * subH );
|
|
494
502
|
material.sobolTexture = _sobolTarget.texture;
|
|
495
503
|
material.seed ++;
|
|
496
504
|
|
|
@@ -498,6 +506,7 @@ function* renderTask() {
|
|
|
498
506
|
const tilesY = this.tiles.y || 1;
|
|
499
507
|
const totalTiles = tilesX * tilesY;
|
|
500
508
|
const dprInv = ( 1 / _renderer.getPixelRatio() );
|
|
509
|
+
|
|
501
510
|
for ( let y = 0; y < tilesY; y ++ ) {
|
|
502
511
|
|
|
503
512
|
for ( let x = 0; x < tilesX; x ++ ) {
|
|
@@ -526,8 +535,12 @@ function* renderTask() {
|
|
|
526
535
|
|
|
527
536
|
material.setDefine( 'CAMERA_TYPE', cameraType );
|
|
528
537
|
|
|
538
|
+
// store og state
|
|
529
539
|
const ogRenderTarget = _renderer.getRenderTarget();
|
|
530
540
|
const ogAutoClear = _renderer.autoClear;
|
|
541
|
+
const ogScissorTest = _renderer.getScissorTest();
|
|
542
|
+
_renderer.getScissor( _ogScissor );
|
|
543
|
+
_renderer.getViewport( _ogViewport );
|
|
531
544
|
|
|
532
545
|
let tx = x;
|
|
533
546
|
let ty = y;
|
|
@@ -544,18 +557,48 @@ function* renderTask() {
|
|
|
544
557
|
// three.js renderer takes values relative to the current pixel ratio
|
|
545
558
|
_renderer.setRenderTarget( _primaryTarget );
|
|
546
559
|
_renderer.setScissorTest( true );
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
560
|
+
|
|
561
|
+
// set the scissor window for a subtile
|
|
562
|
+
_scissor.x = tx * w / tilesX;
|
|
563
|
+
_scissor.y = ( tilesY - ty - 1 ) * h / tilesY;
|
|
564
|
+
_scissor.z = w / tilesX;
|
|
565
|
+
_scissor.w = h / tilesY;
|
|
566
|
+
|
|
567
|
+
// adjust for the subframe
|
|
568
|
+
_scissor.x = subX * w + subW * _scissor.x;
|
|
569
|
+
_scissor.y = subY * h + subH * _scissor.y;
|
|
570
|
+
_scissor.z = subW * _scissor.z;
|
|
571
|
+
_scissor.w = subH * _scissor.w;
|
|
572
|
+
|
|
573
|
+
// round for floating point cases
|
|
574
|
+
_scissor.x = _scissor.x;
|
|
575
|
+
_scissor.y = _scissor.y;
|
|
576
|
+
_scissor.z = _scissor.z;
|
|
577
|
+
_scissor.w = _scissor.w;
|
|
578
|
+
|
|
579
|
+
// multiply inverse of DPR in because threes multiplies it in
|
|
580
|
+
_scissor.multiplyScalar( dprInv ).ceil();
|
|
581
|
+
|
|
582
|
+
_viewport.x = subX * w;
|
|
583
|
+
_viewport.y = subY * h;
|
|
584
|
+
_viewport.z = subW * w;
|
|
585
|
+
_viewport.w = subH * h;
|
|
586
|
+
_viewport.multiplyScalar( dprInv ).ceil();
|
|
587
|
+
|
|
588
|
+
_renderer.setScissor( _scissor );
|
|
589
|
+
_renderer.setViewport( _viewport );
|
|
590
|
+
|
|
552
591
|
_renderer.autoClear = false;
|
|
553
592
|
_fsQuad.render( _renderer );
|
|
554
593
|
|
|
555
|
-
|
|
594
|
+
// reset original renderer state
|
|
595
|
+
_renderer.setViewport( _ogViewport );
|
|
596
|
+
_renderer.setScissor( _ogScissor );
|
|
597
|
+
_renderer.setScissorTest( ogScissorTest );
|
|
556
598
|
_renderer.setRenderTarget( ogRenderTarget );
|
|
557
599
|
_renderer.autoClear = ogAutoClear;
|
|
558
600
|
|
|
601
|
+
// swap and blend alpha targets
|
|
559
602
|
if ( alpha ) {
|
|
560
603
|
|
|
561
604
|
blendMaterial.target1 = blendTarget1.texture;
|
|
@@ -567,7 +610,14 @@ function* renderTask() {
|
|
|
567
610
|
|
|
568
611
|
}
|
|
569
612
|
|
|
570
|
-
this.
|
|
613
|
+
this._samples += ( 1 / totalTiles );
|
|
614
|
+
|
|
615
|
+
// round the samples value if we've finished the tiles
|
|
616
|
+
if ( x === tilesX - 1 && y === tilesY - 1 ) {
|
|
617
|
+
|
|
618
|
+
this._samples = Math.round( this._samples );
|
|
619
|
+
|
|
620
|
+
}
|
|
571
621
|
|
|
572
622
|
yield;
|
|
573
623
|
|
|
@@ -577,8 +627,6 @@ function* renderTask() {
|
|
|
577
627
|
|
|
578
628
|
[ blendTarget1, blendTarget2 ] = [ blendTarget2, blendTarget1 ];
|
|
579
629
|
|
|
580
|
-
this.samples = Math.round( this.samples );
|
|
581
|
-
|
|
582
630
|
}
|
|
583
631
|
|
|
584
632
|
}
|
|
@@ -606,6 +654,12 @@ class PathTracingRenderer {
|
|
|
606
654
|
|
|
607
655
|
set alpha( v ) {
|
|
608
656
|
|
|
657
|
+
if ( this._alpha === v ) {
|
|
658
|
+
|
|
659
|
+
return;
|
|
660
|
+
|
|
661
|
+
}
|
|
662
|
+
|
|
609
663
|
if ( ! v ) {
|
|
610
664
|
|
|
611
665
|
this._blendTargets[ 0 ].dispose();
|
|
@@ -624,15 +678,23 @@ class PathTracingRenderer {
|
|
|
624
678
|
|
|
625
679
|
}
|
|
626
680
|
|
|
681
|
+
get samples() {
|
|
682
|
+
|
|
683
|
+
return this._samples;
|
|
684
|
+
|
|
685
|
+
}
|
|
686
|
+
|
|
627
687
|
constructor( renderer ) {
|
|
628
688
|
|
|
629
689
|
this.camera = null;
|
|
630
690
|
this.tiles = new Vector2( 1, 1 );
|
|
631
691
|
|
|
632
|
-
this.samples = 0;
|
|
633
692
|
this.stableNoise = false;
|
|
634
693
|
this.stableTiles = true;
|
|
635
694
|
|
|
695
|
+
this._samples = 0;
|
|
696
|
+
this._subframe = new Vector4( 0, 0, 1, 1 );
|
|
697
|
+
this._opacityFactor = 1.0;
|
|
636
698
|
this._renderer = renderer;
|
|
637
699
|
this._alpha = false;
|
|
638
700
|
this._fsQuad = new FullScreenQuad( null );
|
|
@@ -660,6 +722,15 @@ class PathTracingRenderer {
|
|
|
660
722
|
|
|
661
723
|
setSize( w, h ) {
|
|
662
724
|
|
|
725
|
+
w = Math.ceil( w );
|
|
726
|
+
h = Math.ceil( h );
|
|
727
|
+
|
|
728
|
+
if ( this._primaryTarget.width === w && this._primaryTarget.height === h ) {
|
|
729
|
+
|
|
730
|
+
return;
|
|
731
|
+
|
|
732
|
+
}
|
|
733
|
+
|
|
663
734
|
this._primaryTarget.setSize( w, h );
|
|
664
735
|
this._blendTargets[ 0 ].setSize( w, h );
|
|
665
736
|
this._blendTargets[ 1 ].setSize( w, h );
|
|
@@ -702,7 +773,7 @@ class PathTracingRenderer {
|
|
|
702
773
|
_renderer.setClearColor( ogClearColor, ogClearAlpha );
|
|
703
774
|
_renderer.setRenderTarget( ogRenderTarget );
|
|
704
775
|
|
|
705
|
-
this.
|
|
776
|
+
this._samples = 0;
|
|
706
777
|
this._task = null;
|
|
707
778
|
|
|
708
779
|
if ( this.stableNoise ) {
|
|
@@ -727,6 +798,227 @@ class PathTracingRenderer {
|
|
|
727
798
|
|
|
728
799
|
}
|
|
729
800
|
|
|
801
|
+
function* _task( cb ) {
|
|
802
|
+
|
|
803
|
+
const {
|
|
804
|
+
viewCount,
|
|
805
|
+
_camera,
|
|
806
|
+
_quiltUtility,
|
|
807
|
+
_subframe,
|
|
808
|
+
} = this;
|
|
809
|
+
|
|
810
|
+
const quiltViewInfo = {
|
|
811
|
+
subframe: _subframe,
|
|
812
|
+
projectionMatrix: _camera.projectionMatrix,
|
|
813
|
+
offsetDirection: new Vector3(),
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
while ( true ) {
|
|
817
|
+
|
|
818
|
+
for ( let i = 0; i < viewCount; i ++ ) {
|
|
819
|
+
|
|
820
|
+
// get the camera info for the current view index
|
|
821
|
+
_quiltUtility.near = this.camera.near;
|
|
822
|
+
_quiltUtility.far = this.camera.far;
|
|
823
|
+
_quiltUtility.getCameraViewInfo( i, quiltViewInfo );
|
|
824
|
+
|
|
825
|
+
// transform offset into world frame from camera frame
|
|
826
|
+
quiltViewInfo.offsetDirection.transformDirection( this.camera.matrixWorld );
|
|
827
|
+
|
|
828
|
+
// adjust the render camera with the view offset
|
|
829
|
+
this.camera.matrixWorld.decompose(
|
|
830
|
+
_camera.position,
|
|
831
|
+
_camera.quaternion,
|
|
832
|
+
_camera.scale,
|
|
833
|
+
);
|
|
834
|
+
_camera.position.addScaledVector( quiltViewInfo.offsetDirection, quiltViewInfo.offset );
|
|
835
|
+
_camera.updateMatrixWorld();
|
|
836
|
+
|
|
837
|
+
// get the inverse projection
|
|
838
|
+
_camera.projectionMatrixInverse
|
|
839
|
+
.copy( _camera.projectionMatrix )
|
|
840
|
+
.invert();
|
|
841
|
+
|
|
842
|
+
this._opacityFactor = Math.floor( this._samples + 1 ) / Math.floor( this._quiltSamples + 1 );
|
|
843
|
+
|
|
844
|
+
do {
|
|
845
|
+
|
|
846
|
+
const ogCamera = this.camera;
|
|
847
|
+
this.camera = _camera;
|
|
848
|
+
cb();
|
|
849
|
+
this.camera = ogCamera;
|
|
850
|
+
yield;
|
|
851
|
+
|
|
852
|
+
} while ( this._samples % 1 !== 0 );
|
|
853
|
+
|
|
854
|
+
this._quiltSamples += 1 / viewCount;
|
|
855
|
+
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
this._quiltSamples = Math.round( this._quiltSamples );
|
|
859
|
+
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Helper for extracting the camera projection, offset, and quilt subframe needed
|
|
865
|
+
// for rendering a quilt with the provided parameters.
|
|
866
|
+
class QuiltViewUtility {
|
|
867
|
+
|
|
868
|
+
constructor() {
|
|
869
|
+
|
|
870
|
+
this.viewCount = 48;
|
|
871
|
+
this.quiltDimensions = new Vector2( 8, 6 );
|
|
872
|
+
this.viewCone = 35 * MathUtils.DEG2RAD;
|
|
873
|
+
this.viewFoV = 14 * MathUtils.DEG2RAD;
|
|
874
|
+
this.displayDistance = 1;
|
|
875
|
+
this.displayAspect = 0.75;
|
|
876
|
+
this.near = 0.01;
|
|
877
|
+
this.far = 10;
|
|
878
|
+
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
getCameraViewInfo( i, target = {} ) {
|
|
882
|
+
|
|
883
|
+
const {
|
|
884
|
+
quiltDimensions,
|
|
885
|
+
viewCone,
|
|
886
|
+
displayDistance,
|
|
887
|
+
viewCount,
|
|
888
|
+
viewFoV,
|
|
889
|
+
displayAspect,
|
|
890
|
+
near,
|
|
891
|
+
far,
|
|
892
|
+
} = this;
|
|
893
|
+
|
|
894
|
+
// initialize defaults
|
|
895
|
+
target.subframe = target.subframe || new Vector4();
|
|
896
|
+
target.offsetDirection = target.offsetDirection || new Vector3();
|
|
897
|
+
target.projectionMatrix = target.projectionMatrix || new Matrix4();
|
|
898
|
+
|
|
899
|
+
// set camera offset
|
|
900
|
+
const halfWidth = Math.tan( 0.5 * viewCone ) * displayDistance;
|
|
901
|
+
const totalWidth = halfWidth * 2.0;
|
|
902
|
+
const stride = totalWidth / ( viewCount - 1 );
|
|
903
|
+
const offset = viewCount === 1 ? 0 : - halfWidth + stride * i;
|
|
904
|
+
target.offsetDirection.set( 1.0, 0, 0 );
|
|
905
|
+
target.offset = offset;
|
|
906
|
+
|
|
907
|
+
// set the projection matrix
|
|
908
|
+
const displayHalfHeight = Math.tan( viewFoV * 0.5 ) * displayDistance;
|
|
909
|
+
const displayHalfWidth = displayAspect * displayHalfHeight;
|
|
910
|
+
const nearScale = near / displayDistance;
|
|
911
|
+
|
|
912
|
+
target.projectionMatrix.makePerspective(
|
|
913
|
+
nearScale * ( - displayHalfWidth - offset ), nearScale * ( displayHalfWidth - offset ),
|
|
914
|
+
nearScale * displayHalfHeight, nearScale * - displayHalfHeight,
|
|
915
|
+
near, far,
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
// set the quilt subframe
|
|
919
|
+
const x = i % quiltDimensions.x;
|
|
920
|
+
const y = Math.floor( i / quiltDimensions.x );
|
|
921
|
+
|
|
922
|
+
const qw = 1 / quiltDimensions.x;
|
|
923
|
+
const qh = 1 / quiltDimensions.y;
|
|
924
|
+
target.subframe.set( x * qw, y * qh, qw, qh );
|
|
925
|
+
|
|
926
|
+
return target;
|
|
927
|
+
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
setFromDisplayView( viewerDistance, displayWidth, displayHeight ) {
|
|
931
|
+
|
|
932
|
+
this.displayAspect = displayWidth / displayHeight;
|
|
933
|
+
this.displayDistance = viewerDistance;
|
|
934
|
+
this.viewFoV = 2.0 * Math.atan( 0.5 * displayHeight / viewerDistance );
|
|
935
|
+
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
class QuiltPathTracingRenderer extends PathTracingRenderer {
|
|
941
|
+
|
|
942
|
+
get samples() {
|
|
943
|
+
|
|
944
|
+
return this._samples / this.viewCount;
|
|
945
|
+
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
constructor( ...args ) {
|
|
949
|
+
|
|
950
|
+
super( ...args );
|
|
951
|
+
|
|
952
|
+
[
|
|
953
|
+
'quiltDimensions',
|
|
954
|
+
'viewCount',
|
|
955
|
+
'viewCone',
|
|
956
|
+
'viewFoV',
|
|
957
|
+
'displayDistance',
|
|
958
|
+
'displayAspect',
|
|
959
|
+
].forEach( member => {
|
|
960
|
+
|
|
961
|
+
Object.defineProperty( this, member, {
|
|
962
|
+
|
|
963
|
+
enumerable: true,
|
|
964
|
+
|
|
965
|
+
set: v => {
|
|
966
|
+
|
|
967
|
+
this._quiltUtility[ member ] = v;
|
|
968
|
+
|
|
969
|
+
},
|
|
970
|
+
|
|
971
|
+
get: () => {
|
|
972
|
+
|
|
973
|
+
return this._quiltUtility[ member ];
|
|
974
|
+
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
} );
|
|
978
|
+
|
|
979
|
+
} );
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
this._quiltUtility = new QuiltViewUtility();
|
|
983
|
+
this._quiltSamples = 0;
|
|
984
|
+
this._camera = new PerspectiveCamera();
|
|
985
|
+
this._quiltTask = null;
|
|
986
|
+
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
setFromDisplayView( ...args ) {
|
|
990
|
+
|
|
991
|
+
this._quiltUtility.setFromDisplayView( ...args );
|
|
992
|
+
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
update() {
|
|
996
|
+
|
|
997
|
+
this.alpha = false;
|
|
998
|
+
if ( ! this._quiltTask ) {
|
|
999
|
+
|
|
1000
|
+
this._quiltTask = _task.call( this, () => {
|
|
1001
|
+
|
|
1002
|
+
super.update();
|
|
1003
|
+
|
|
1004
|
+
} );
|
|
1005
|
+
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
this._quiltTask.next();
|
|
1009
|
+
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
reset() {
|
|
1013
|
+
|
|
1014
|
+
super.reset();
|
|
1015
|
+
this._quiltTask = null;
|
|
1016
|
+
this._quiltSamples = 0;
|
|
1017
|
+
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
}
|
|
1021
|
+
|
|
730
1022
|
function getGroupMaterialIndicesAttribute( geometry, materials, allMaterials ) {
|
|
731
1023
|
|
|
732
1024
|
const indexAttr = geometry.index;
|
|
@@ -971,7 +1263,7 @@ class PathTracingSceneGenerator {
|
|
|
971
1263
|
|
|
972
1264
|
meshes.push( c );
|
|
973
1265
|
|
|
974
|
-
} else if ( c.isRectAreaLight || c.isSpotLight ) {
|
|
1266
|
+
} else if ( c.isRectAreaLight || c.isSpotLight || c.isDirectionalLight || c.isPointLight ) {
|
|
975
1267
|
|
|
976
1268
|
lights.push( c );
|
|
977
1269
|
|
|
@@ -1825,7 +2117,7 @@ class MaterialsTexture extends DataTexture {
|
|
|
1825
2117
|
}
|
|
1826
2118
|
|
|
1827
2119
|
index ++;
|
|
1828
|
-
index
|
|
2120
|
+
floatArray[ index ++ ] = getField( m, 'sheen', 0.0 );
|
|
1829
2121
|
|
|
1830
2122
|
// sample 7
|
|
1831
2123
|
// sheen
|
|
@@ -2170,31 +2462,45 @@ class EquirectHdrInfoUniform {
|
|
|
2170
2462
|
|
|
2171
2463
|
constructor() {
|
|
2172
2464
|
|
|
2465
|
+
// Default to a white texture and associated weights so we don't
|
|
2466
|
+
// just render black initially.
|
|
2467
|
+
const whiteTex = new DataTexture( new Float32Array( [ 1, 1, 1, 1 ] ), 1, 1 );
|
|
2468
|
+
whiteTex.type = FloatType;
|
|
2469
|
+
whiteTex.format = RGBAFormat;
|
|
2470
|
+
whiteTex.minFilter = LinearFilter;
|
|
2471
|
+
whiteTex.magFilter = LinearFilter;
|
|
2472
|
+
whiteTex.wrapS = RepeatWrapping;
|
|
2473
|
+
whiteTex.wrapT = RepeatWrapping;
|
|
2474
|
+
whiteTex.generateMipmaps = false;
|
|
2475
|
+
whiteTex.needsUpdate = true;
|
|
2476
|
+
|
|
2173
2477
|
// Stores a map of [0, 1] value -> cumulative importance row & pdf
|
|
2174
2478
|
// used to sampling a random value to a relevant row to sample from
|
|
2175
|
-
const marginalWeights = new DataTexture();
|
|
2479
|
+
const marginalWeights = new DataTexture( new Float32Array( [ 0, 1 ] ), 1, 2 );
|
|
2176
2480
|
marginalWeights.type = FloatType;
|
|
2177
2481
|
marginalWeights.format = RedFormat;
|
|
2178
2482
|
marginalWeights.minFilter = LinearFilter;
|
|
2179
2483
|
marginalWeights.magFilter = LinearFilter;
|
|
2180
2484
|
marginalWeights.generateMipmaps = false;
|
|
2485
|
+
marginalWeights.needsUpdate = true;
|
|
2181
2486
|
|
|
2182
2487
|
// Stores a map of [0, 1] value -> cumulative importance column & pdf
|
|
2183
2488
|
// used to sampling a random value to a relevant pixel to sample from
|
|
2184
|
-
const conditionalWeights = new DataTexture();
|
|
2489
|
+
const conditionalWeights = new DataTexture( new Float32Array( [ 0, 0, 1, 1 ] ), 2, 2 );
|
|
2185
2490
|
conditionalWeights.type = FloatType;
|
|
2186
2491
|
conditionalWeights.format = RedFormat;
|
|
2187
2492
|
conditionalWeights.minFilter = LinearFilter;
|
|
2188
2493
|
conditionalWeights.magFilter = LinearFilter;
|
|
2189
2494
|
conditionalWeights.generateMipmaps = false;
|
|
2495
|
+
conditionalWeights.needsUpdate = true;
|
|
2190
2496
|
|
|
2497
|
+
this.map = whiteTex;
|
|
2191
2498
|
this.marginalWeights = marginalWeights;
|
|
2192
2499
|
this.conditionalWeights = conditionalWeights;
|
|
2193
|
-
this.map = null;
|
|
2194
2500
|
|
|
2195
2501
|
// the total sum value is separated into two values to work around low precision
|
|
2196
2502
|
// storage of floating values in structs
|
|
2197
|
-
this.totalSumWhole =
|
|
2503
|
+
this.totalSumWhole = 1;
|
|
2198
2504
|
this.totalSumDecimal = 0;
|
|
2199
2505
|
|
|
2200
2506
|
}
|
|
@@ -2203,7 +2509,7 @@ class EquirectHdrInfoUniform {
|
|
|
2203
2509
|
|
|
2204
2510
|
this.marginalWeights.dispose();
|
|
2205
2511
|
this.conditionalWeights.dispose();
|
|
2206
|
-
|
|
2512
|
+
this.map.dispose();
|
|
2207
2513
|
|
|
2208
2514
|
}
|
|
2209
2515
|
|
|
@@ -2542,7 +2848,10 @@ class LightsInfoUniformStruct {
|
|
|
2542
2848
|
|
|
2543
2849
|
} else if ( l.isPointLight ) {
|
|
2544
2850
|
|
|
2545
|
-
const worldPosition =
|
|
2851
|
+
const worldPosition = u.setFromMatrixPosition( l.matrixWorld );
|
|
2852
|
+
|
|
2853
|
+
// sample 3
|
|
2854
|
+
// u vector
|
|
2546
2855
|
floatArray[ baseIndex + ( index ++ ) ] = worldPosition.x;
|
|
2547
2856
|
floatArray[ baseIndex + ( index ++ ) ] = worldPosition.y;
|
|
2548
2857
|
floatArray[ baseIndex + ( index ++ ) ] = worldPosition.z;
|
|
@@ -2559,10 +2868,12 @@ class LightsInfoUniformStruct {
|
|
|
2559
2868
|
|
|
2560
2869
|
} else if ( l.isDirectionalLight ) {
|
|
2561
2870
|
|
|
2562
|
-
const worldPosition =
|
|
2563
|
-
const targetPosition = l.target.
|
|
2564
|
-
|
|
2871
|
+
const worldPosition = u.setFromMatrixPosition( l.matrixWorld );
|
|
2872
|
+
const targetPosition = v.setFromMatrixPosition( l.target.matrixWorld );
|
|
2565
2873
|
target.subVectors( worldPosition, targetPosition ).normalize();
|
|
2874
|
+
|
|
2875
|
+
// sample 3
|
|
2876
|
+
// u vector
|
|
2566
2877
|
floatArray[ baseIndex + ( index ++ ) ] = target.x;
|
|
2567
2878
|
floatArray[ baseIndex + ( index ++ ) ] = target.y;
|
|
2568
2879
|
floatArray[ baseIndex + ( index ++ ) ] = target.z;
|
|
@@ -2984,6 +3295,22 @@ class IESProfilesTexture extends WebGLArrayRenderTarget {
|
|
|
2984
3295
|
|
|
2985
3296
|
const shaderUtils = /* glsl */`
|
|
2986
3297
|
|
|
3298
|
+
#ifndef RAY_OFFSET
|
|
3299
|
+
#define RAY_OFFSET 1e-4
|
|
3300
|
+
#endif
|
|
3301
|
+
|
|
3302
|
+
// adjust the hit point by the surface normal by a factor of some offset and the
|
|
3303
|
+
// maximum component-wise value of the current point to accommodate floating point
|
|
3304
|
+
// error as values increase.
|
|
3305
|
+
vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {
|
|
3306
|
+
|
|
3307
|
+
vec3 point = rayOrigin + rayDirection * dist;
|
|
3308
|
+
vec3 absPoint = abs( point );
|
|
3309
|
+
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
3310
|
+
return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;
|
|
3311
|
+
|
|
3312
|
+
}
|
|
3313
|
+
|
|
2987
3314
|
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
|
|
2988
3315
|
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
|
|
2989
3316
|
|
|
@@ -3915,6 +4242,7 @@ const shaderMaterialStructs = /* glsl */ `
|
|
|
3915
4242
|
float side;
|
|
3916
4243
|
bool matte;
|
|
3917
4244
|
|
|
4245
|
+
float sheen;
|
|
3918
4246
|
vec3 sheenColor;
|
|
3919
4247
|
int sheenColorMap;
|
|
3920
4248
|
float sheenRoughness;
|
|
@@ -4004,6 +4332,7 @@ const shaderMaterialStructs = /* glsl */ `
|
|
|
4004
4332
|
m.clearcoatNormalMap = int( round( s5.a ) );
|
|
4005
4333
|
m.clearcoatNormalScale = s6.rg;
|
|
4006
4334
|
|
|
4335
|
+
m.sheen = s6.a;
|
|
4007
4336
|
m.sheenColor = s7.rgb;
|
|
4008
4337
|
m.sheenColorMap = int( round( s7.a ) );
|
|
4009
4338
|
m.sheenRoughness = s8.r;
|
|
@@ -4443,6 +4772,7 @@ vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinF
|
|
|
4443
4772
|
phi12 = PI;
|
|
4444
4773
|
|
|
4445
4774
|
}
|
|
4775
|
+
|
|
4446
4776
|
float phi21 = PI - phi12;
|
|
4447
4777
|
|
|
4448
4778
|
// Second interface
|
|
@@ -4455,11 +4785,13 @@ vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinF
|
|
|
4455
4785
|
phi23[ 0 ] = PI;
|
|
4456
4786
|
|
|
4457
4787
|
}
|
|
4788
|
+
|
|
4458
4789
|
if ( baseIOR[1] < iridescenceIor ) {
|
|
4459
4790
|
|
|
4460
4791
|
phi23[ 1 ] = PI;
|
|
4461
4792
|
|
|
4462
4793
|
}
|
|
4794
|
+
|
|
4463
4795
|
if ( baseIOR[2] < iridescenceIor ) {
|
|
4464
4796
|
|
|
4465
4797
|
phi23[ 2 ] = PI;
|
|
@@ -4481,15 +4813,17 @@ vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinF
|
|
|
4481
4813
|
|
|
4482
4814
|
// Reflectance term for m > 0 (pairs of diracs)
|
|
4483
4815
|
vec3 Cm = Rs - T121;
|
|
4484
|
-
for ( int m = 1; m <= 2; ++ m )
|
|
4485
|
-
|
|
4816
|
+
for ( int m = 1; m <= 2; ++ m ) {
|
|
4817
|
+
|
|
4486
4818
|
Cm *= r123;
|
|
4487
4819
|
vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );
|
|
4488
4820
|
I += Cm * Sm;
|
|
4821
|
+
|
|
4489
4822
|
}
|
|
4490
4823
|
|
|
4491
4824
|
// Since out of gamut colors might be produced, negative color values are clamped to 0.
|
|
4492
4825
|
return max( I, vec3( 0.0 ) );
|
|
4826
|
+
|
|
4493
4827
|
}
|
|
4494
4828
|
|
|
4495
4829
|
`;
|
|
@@ -4523,6 +4857,7 @@ struct SurfaceRec {
|
|
|
4523
4857
|
float clearcoat;
|
|
4524
4858
|
float clearcoatRoughness;
|
|
4525
4859
|
float filteredClearcoatRoughness;
|
|
4860
|
+
float sheen;
|
|
4526
4861
|
vec3 sheenColor;
|
|
4527
4862
|
float sheenRoughness;
|
|
4528
4863
|
float iridescence;
|
|
@@ -4598,12 +4933,12 @@ float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, out vec3 color )
|
|
|
4598
4933
|
|
|
4599
4934
|
// if roughness is set to 0 then D === NaN which results in black pixels
|
|
4600
4935
|
float metalness = surf.metalness;
|
|
4601
|
-
float
|
|
4936
|
+
float roughness = surf.filteredRoughness;
|
|
4602
4937
|
|
|
4603
4938
|
float eta = surf.eta;
|
|
4604
4939
|
float f0 = surf.f0;
|
|
4605
|
-
float G = ggxShadowMaskG2( wi, wo,
|
|
4606
|
-
float D = ggxDistribution( wh,
|
|
4940
|
+
float G = ggxShadowMaskG2( wi, wo, roughness );
|
|
4941
|
+
float D = ggxDistribution( wh, roughness );
|
|
4607
4942
|
float FM = disneyFresnel( surf, wo, wi, wh );
|
|
4608
4943
|
float cosTheta = min( wo.z, 1.0 );
|
|
4609
4944
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
@@ -4614,20 +4949,23 @@ float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, out vec3 color )
|
|
|
4614
4949
|
|
|
4615
4950
|
}
|
|
4616
4951
|
|
|
4617
|
-
vec3
|
|
4618
|
-
vec3
|
|
4619
|
-
vec3 specColor = mix( dielectricColor, metalColor, surf.metalness );
|
|
4952
|
+
vec3 baseColor = mix( f0 * surf.specularColor * surf.specularIntensity, surf.color, surf.metalness );
|
|
4953
|
+
vec3 iridescenceFresnel = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, wh ), surf.iridescenceThickness, baseColor );
|
|
4620
4954
|
|
|
4621
|
-
vec3
|
|
4622
|
-
vec3
|
|
4623
|
-
vec3 F = mix( specColor, vec3( 1.0 ), iridescenceMix );
|
|
4955
|
+
vec3 metalMix = mix( surf.color, iridescenceFresnel, surf.iridescence );
|
|
4956
|
+
vec3 metalFresnel = mix( metalMix, vec3( 1.0 ), FM );
|
|
4624
4957
|
|
|
4625
|
-
|
|
4958
|
+
vec3 dielectricIriMix = mix( iridescenceFresnel, vec3( 1.0 ), FM );
|
|
4959
|
+
vec3 dielectricMix = mix( f0 * surf.specularColor, vec3( 1.0 ), FM ) * surf.specularIntensity;
|
|
4960
|
+
vec3 dielectricFresnel = mix( dielectricMix, dielectricIriMix, surf.iridescence );
|
|
4961
|
+
|
|
4962
|
+
vec3 F = mix( dielectricFresnel, metalFresnel, surf.metalness );
|
|
4963
|
+
color = wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );
|
|
4626
4964
|
|
|
4627
4965
|
// PDF
|
|
4628
4966
|
// See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/
|
|
4629
4967
|
float incidentTheta = acos( wo.z );
|
|
4630
|
-
float G1 = ggxShadowMaskG1( incidentTheta,
|
|
4968
|
+
float G1 = ggxShadowMaskG1( incidentTheta, roughness );
|
|
4631
4969
|
float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs ( wo.z );
|
|
4632
4970
|
return ggxPdf / ( 4.0 * dot( wo, wh ) );
|
|
4633
4971
|
|
|
@@ -4636,10 +4974,10 @@ float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, out vec3 color )
|
|
|
4636
4974
|
vec3 specularDirection( vec3 wo, SurfaceRec surf ) {
|
|
4637
4975
|
|
|
4638
4976
|
// sample ggx vndf distribution which gives a new normal
|
|
4639
|
-
float
|
|
4977
|
+
float roughness = surf.filteredRoughness;
|
|
4640
4978
|
vec3 halfVector = ggxDirection(
|
|
4641
4979
|
wo,
|
|
4642
|
-
vec2(
|
|
4980
|
+
vec2( roughness ),
|
|
4643
4981
|
sobol2( 12 )
|
|
4644
4982
|
);
|
|
4645
4983
|
|
|
@@ -4716,7 +5054,7 @@ float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, out vec3 col
|
|
|
4716
5054
|
|
|
4717
5055
|
vec3 transmissionDirection( vec3 wo, SurfaceRec surf ) {
|
|
4718
5056
|
|
|
4719
|
-
float roughness = surf.
|
|
5057
|
+
float roughness = surf.filteredRoughness;
|
|
4720
5058
|
float eta = surf.eta;
|
|
4721
5059
|
vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + sampleSphere( sobol2( 13 ) ) * roughness );
|
|
4722
5060
|
vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );
|
|
@@ -4736,11 +5074,11 @@ float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, inout vec3 colo
|
|
|
4736
5074
|
float ior = 1.5;
|
|
4737
5075
|
float f0 = iorRatioToF0( ior );
|
|
4738
5076
|
bool frontFace = surf.frontFace;
|
|
4739
|
-
float
|
|
5077
|
+
float roughness = surf.filteredClearcoatRoughness;
|
|
4740
5078
|
|
|
4741
5079
|
float eta = frontFace ? 1.0 / ior : ior;
|
|
4742
|
-
float G = ggxShadowMaskG2( wi, wo,
|
|
4743
|
-
float D = ggxDistribution( wh,
|
|
5080
|
+
float G = ggxShadowMaskG2( wi, wo, roughness );
|
|
5081
|
+
float D = ggxDistribution( wh, roughness );
|
|
4744
5082
|
float F = schlickFresnel( dot( wi, wh ), f0 );
|
|
4745
5083
|
float cosTheta = min( wo.z, 1.0 );
|
|
4746
5084
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
@@ -4756,17 +5094,17 @@ float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, inout vec3 colo
|
|
|
4756
5094
|
|
|
4757
5095
|
// PDF
|
|
4758
5096
|
// See equation (27) in http://jcgt.org/published/0003/02/03/
|
|
4759
|
-
return ggxPDF( wo, wh,
|
|
5097
|
+
return ggxPDF( wo, wh, roughness ) / ( 4.0 * dot( wi, wh ) );
|
|
4760
5098
|
|
|
4761
5099
|
}
|
|
4762
5100
|
|
|
4763
5101
|
vec3 clearcoatDirection( vec3 wo, SurfaceRec surf ) {
|
|
4764
5102
|
|
|
4765
5103
|
// sample ggx vndf distribution which gives a new normal
|
|
4766
|
-
float
|
|
5104
|
+
float roughness = surf.filteredClearcoatRoughness;
|
|
4767
5105
|
vec3 halfVector = ggxDirection(
|
|
4768
5106
|
wo,
|
|
4769
|
-
vec2(
|
|
5107
|
+
vec2( roughness ),
|
|
4770
5108
|
sobol2( 14 )
|
|
4771
5109
|
);
|
|
4772
5110
|
|
|
@@ -4795,11 +5133,10 @@ vec3 sheenColor( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf ) {
|
|
|
4795
5133
|
}
|
|
4796
5134
|
|
|
4797
5135
|
// bsdf
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
void getLobeWeights( vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRec surf, out float[ 4 ] weights ) {
|
|
5136
|
+
void getLobeWeights(
|
|
5137
|
+
vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRec surf,
|
|
5138
|
+
out float diffuseWeight, out float specularWeight, out float transmissionWeight, out float clearcoatWeight
|
|
5139
|
+
) {
|
|
4803
5140
|
|
|
4804
5141
|
float metalness = surf.metalness;
|
|
4805
5142
|
float transmission = surf.transmission;
|
|
@@ -4821,25 +5158,22 @@ void getLobeWeights( vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRec sur
|
|
|
4821
5158
|
float transSpecularProb = mix( max( 0.25, reflectance ), 1.0, metalness );
|
|
4822
5159
|
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
4823
5160
|
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
5161
|
+
diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );
|
|
5162
|
+
specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;
|
|
5163
|
+
transmissionWeight = transmission * ( 1.0 - transSpecularProb );
|
|
5164
|
+
clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );
|
|
4828
5165
|
|
|
4829
5166
|
float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
5167
|
+
diffuseWeight /= totalWeight;
|
|
5168
|
+
specularWeight /= totalWeight;
|
|
5169
|
+
transmissionWeight /= totalWeight;
|
|
5170
|
+
clearcoatWeight /= totalWeight;
|
|
4835
5171
|
}
|
|
4836
5172
|
|
|
4837
|
-
float bsdfEval(
|
|
4838
|
-
|
|
4839
|
-
float diffuseWeight
|
|
4840
|
-
|
|
4841
|
-
float transmissionWeight = weights[ TRANS_WEIGHT ];
|
|
4842
|
-
float clearcoatWeight = weights[ CC_WEIGHT ];
|
|
5173
|
+
float bsdfEval(
|
|
5174
|
+
vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf,
|
|
5175
|
+
float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, out float specularPdf, out vec3 color
|
|
5176
|
+
) {
|
|
4843
5177
|
|
|
4844
5178
|
float metalness = surf.metalness;
|
|
4845
5179
|
float transmission = surf.transmission;
|
|
@@ -4889,8 +5223,8 @@ float bsdfEval( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec
|
|
|
4889
5223
|
}
|
|
4890
5224
|
|
|
4891
5225
|
// sheen
|
|
4892
|
-
color *= sheenAlbedoScaling( wo, wi, surf );
|
|
4893
|
-
color += sheenColor( wo, wi, halfVector, surf );
|
|
5226
|
+
color *= mix( 1.0, sheenAlbedoScaling( wo, wi, surf ), surf.sheen );
|
|
5227
|
+
color += sheenColor( wo, wi, halfVector, surf ) * surf.sheen;
|
|
4894
5228
|
|
|
4895
5229
|
// clearcoat
|
|
4896
5230
|
if ( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
@@ -4915,20 +5249,32 @@ float bsdfEval( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec
|
|
|
4915
5249
|
|
|
4916
5250
|
float bsdfResult( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out vec3 color ) {
|
|
4917
5251
|
|
|
4918
|
-
float[ 4 ] pdf;
|
|
4919
5252
|
vec3 wh = getHalfVector( wo, wi, surf.eta );
|
|
4920
|
-
|
|
5253
|
+
float diffuseWeight;
|
|
5254
|
+
float specularWeight;
|
|
5255
|
+
float transmissionWeight;
|
|
5256
|
+
float clearcoatWeight;
|
|
5257
|
+
getLobeWeights( wo, wi, wh, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
4921
5258
|
|
|
4922
5259
|
float specularPdf;
|
|
4923
|
-
return bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf,
|
|
5260
|
+
return bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, specularPdf, color );
|
|
4924
5261
|
|
|
4925
5262
|
}
|
|
4926
5263
|
|
|
4927
5264
|
SampleRec bsdfSample( vec3 wo, vec3 clearcoatWo, mat3 normalBasis, mat3 invBasis, mat3 clearcoatNormalBasis, mat3 clearcoatInvBasis, SurfaceRec surf ) {
|
|
4928
5265
|
|
|
5266
|
+
float diffuseWeight;
|
|
5267
|
+
float specularWeight;
|
|
5268
|
+
float transmissionWeight;
|
|
5269
|
+
float clearcoatWeight;
|
|
4929
5270
|
// using normal and basically-reflected ray since we don't have proper half vector here
|
|
5271
|
+
getLobeWeights( wo, wo, vec3( 0, 0, 1 ), clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
5272
|
+
|
|
4930
5273
|
float pdf[4];
|
|
4931
|
-
|
|
5274
|
+
pdf[0] = diffuseWeight;
|
|
5275
|
+
pdf[1] = specularWeight;
|
|
5276
|
+
pdf[2] = transmissionWeight;
|
|
5277
|
+
pdf[3] = clearcoatWeight;
|
|
4932
5278
|
|
|
4933
5279
|
float cdf[4];
|
|
4934
5280
|
cdf[0] = pdf[0];
|
|
@@ -4980,7 +5326,7 @@ SampleRec bsdfSample( vec3 wo, vec3 clearcoatWo, mat3 normalBasis, mat3 invBasis
|
|
|
4980
5326
|
}
|
|
4981
5327
|
|
|
4982
5328
|
SampleRec result;
|
|
4983
|
-
result.pdf = bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf,
|
|
5329
|
+
result.pdf = bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, result.specularPdf, result.color );
|
|
4984
5330
|
result.direction = wi;
|
|
4985
5331
|
result.clearcoatDirection = clearcoatWi;
|
|
4986
5332
|
|
|
@@ -5580,9 +5926,9 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5580
5926
|
|
|
5581
5927
|
defines: {
|
|
5582
5928
|
FEATURE_MIS: 1,
|
|
5929
|
+
FEATURE_RUSSIAN_ROULETTE: 1,
|
|
5583
5930
|
FEATURE_DOF: 1,
|
|
5584
5931
|
FEATURE_BACKGROUND_MAP: 0,
|
|
5585
|
-
TRANSPARENT_TRAVERSALS: 5,
|
|
5586
5932
|
// 0 = Perspective
|
|
5587
5933
|
// 1 = Orthographic
|
|
5588
5934
|
// 2 = Equirectangular
|
|
@@ -5597,7 +5943,8 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5597
5943
|
uniforms: {
|
|
5598
5944
|
resolution: { value: new Vector2() },
|
|
5599
5945
|
|
|
5600
|
-
bounces: { value:
|
|
5946
|
+
bounces: { value: 10 },
|
|
5947
|
+
transmissiveBounces: { value: 10 },
|
|
5601
5948
|
physicalCamera: { value: new PhysicalCameraUniform() },
|
|
5602
5949
|
|
|
5603
5950
|
bvh: { value: new MeshBVHUniformStruct() },
|
|
@@ -5640,6 +5987,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5640
5987
|
|
|
5641
5988
|
fragmentShader: /* glsl */`
|
|
5642
5989
|
#define RAY_OFFSET 1e-4
|
|
5990
|
+
#define INFINITY 1e20
|
|
5643
5991
|
|
|
5644
5992
|
precision highp isampler2D;
|
|
5645
5993
|
precision highp usampler2D;
|
|
@@ -5678,6 +6026,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5678
6026
|
|
|
5679
6027
|
uniform vec2 resolution;
|
|
5680
6028
|
uniform int bounces;
|
|
6029
|
+
uniform int transmissiveBounces;
|
|
5681
6030
|
uniform mat4 cameraWorldMatrix;
|
|
5682
6031
|
uniform mat4 invProjectionMatrix;
|
|
5683
6032
|
uniform sampler2DArray attributesArray;
|
|
@@ -5727,7 +6076,10 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5727
6076
|
}
|
|
5728
6077
|
|
|
5729
6078
|
// step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
|
|
5730
|
-
bool attenuateHit(
|
|
6079
|
+
bool attenuateHit(
|
|
6080
|
+
BVH bvh, vec3 rayOrigin, vec3 rayDirection, float rayDist,
|
|
6081
|
+
int traversals, int transparentTraversals, bool isShadowRay, out vec3 color
|
|
6082
|
+
) {
|
|
5731
6083
|
|
|
5732
6084
|
// hit results
|
|
5733
6085
|
uvec4 faceIndices = uvec4( 0u );
|
|
@@ -5744,6 +6096,12 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5744
6096
|
|
|
5745
6097
|
if ( bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ) ) {
|
|
5746
6098
|
|
|
6099
|
+
if ( dist > rayDist ) {
|
|
6100
|
+
|
|
6101
|
+
return true;
|
|
6102
|
+
|
|
6103
|
+
}
|
|
6104
|
+
|
|
5747
6105
|
// TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
|
|
5748
6106
|
// Should be able to work using the material BSDF functions which will take into account specularity, etc.
|
|
5749
6107
|
// TODO: should we account for emissive surfaces here?
|
|
@@ -5755,11 +6113,8 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5755
6113
|
Material material = readMaterialInfo( materials, materialIndex );
|
|
5756
6114
|
|
|
5757
6115
|
// adjust the ray to the new surface
|
|
5758
|
-
bool
|
|
5759
|
-
|
|
5760
|
-
vec3 absPoint = abs( point );
|
|
5761
|
-
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
5762
|
-
rayOrigin = point + faceNormal * ( maxPoint + 1.0 ) * ( isBelowSurface ? - RAY_OFFSET : RAY_OFFSET );
|
|
6116
|
+
bool isEntering = side == 1.0;
|
|
6117
|
+
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
5763
6118
|
|
|
5764
6119
|
if ( ! material.castShadow && isShadowRay ) {
|
|
5765
6120
|
|
|
@@ -5829,7 +6184,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5829
6184
|
|
|
5830
6185
|
}
|
|
5831
6186
|
|
|
5832
|
-
if ( side == 1.0 &&
|
|
6187
|
+
if ( side == 1.0 && isEntering ) {
|
|
5833
6188
|
|
|
5834
6189
|
// only attenuate by surface color on the way in
|
|
5835
6190
|
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
|
|
@@ -5841,6 +6196,15 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5841
6196
|
|
|
5842
6197
|
}
|
|
5843
6198
|
|
|
6199
|
+
bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
|
|
6200
|
+
if ( ( isTransmissiveRay || isEntering ) && transparentTraversals > 0 ) {
|
|
6201
|
+
|
|
6202
|
+
transparentTraversals --;
|
|
6203
|
+
i --;
|
|
6204
|
+
|
|
6205
|
+
}
|
|
6206
|
+
|
|
6207
|
+
|
|
5844
6208
|
} else {
|
|
5845
6209
|
|
|
5846
6210
|
return false;
|
|
@@ -5853,19 +6217,6 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5853
6217
|
|
|
5854
6218
|
}
|
|
5855
6219
|
|
|
5856
|
-
// returns whether the ray hit anything before a certain distance, not just the first surface. Could be optimized to not check the full hierarchy.
|
|
5857
|
-
bool anyCloserHit( BVH bvh, vec3 rayOrigin, vec3 rayDirection, float maxDist ) {
|
|
5858
|
-
|
|
5859
|
-
uvec4 faceIndices = uvec4( 0u );
|
|
5860
|
-
vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
|
5861
|
-
vec3 barycoord = vec3( 0.0 );
|
|
5862
|
-
float side = 1.0;
|
|
5863
|
-
float dist = 0.0;
|
|
5864
|
-
bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
|
5865
|
-
return hit && dist < maxDist;
|
|
5866
|
-
|
|
5867
|
-
}
|
|
5868
|
-
|
|
5869
6220
|
vec3 ndcToRayOrigin( vec2 coord ) {
|
|
5870
6221
|
|
|
5871
6222
|
vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
|
|
@@ -5974,7 +6325,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5974
6325
|
float accumulatedRoughness = 0.0;
|
|
5975
6326
|
float accumulatedClearcoatRoughness = 0.0;
|
|
5976
6327
|
bool transmissiveRay = true;
|
|
5977
|
-
int transparentTraversals =
|
|
6328
|
+
int transparentTraversals = transmissiveBounces;
|
|
5978
6329
|
vec3 throughputColor = vec3( 1.0 );
|
|
5979
6330
|
SampleRec sampleRec;
|
|
5980
6331
|
int i;
|
|
@@ -5985,12 +6336,12 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
5985
6336
|
sobolBounceIndex ++;
|
|
5986
6337
|
|
|
5987
6338
|
bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
|
5988
|
-
|
|
6339
|
+
bool firstRay = i == 0 && transparentTraversals == transmissiveBounces;
|
|
5989
6340
|
LightSampleRec lightHit = lightsClosestHit( lights.tex, lights.count, rayOrigin, rayDirection );
|
|
5990
6341
|
|
|
5991
|
-
if ( lightHit.hit && ( lightHit.dist < dist || !hit ) ) {
|
|
6342
|
+
if ( lightHit.hit && ( lightHit.dist < dist || ! hit ) ) {
|
|
5992
6343
|
|
|
5993
|
-
if (
|
|
6344
|
+
if ( firstRay || transmissiveRay ) {
|
|
5994
6345
|
|
|
5995
6346
|
gl_FragColor.rgb += lightHit.emission * throughputColor;
|
|
5996
6347
|
|
|
@@ -6024,7 +6375,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6024
6375
|
|
|
6025
6376
|
if ( ! hit ) {
|
|
6026
6377
|
|
|
6027
|
-
if (
|
|
6378
|
+
if ( firstRay || transmissiveRay ) {
|
|
6028
6379
|
|
|
6029
6380
|
gl_FragColor.rgb += sampleBackground( envRotation3x3 * rayDirection, sobol2( 2 ) ) * throughputColor;
|
|
6030
6381
|
gl_FragColor.a = backgroundAlpha;
|
|
@@ -6059,7 +6410,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6059
6410
|
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
6060
6411
|
Material material = readMaterialInfo( materials, materialIndex );
|
|
6061
6412
|
|
|
6062
|
-
if ( material.matte &&
|
|
6413
|
+
if ( material.matte && firstRay ) {
|
|
6063
6414
|
|
|
6064
6415
|
gl_FragColor = vec4( 0.0 );
|
|
6065
6416
|
break;
|
|
@@ -6070,11 +6421,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6070
6421
|
// then skip it
|
|
6071
6422
|
if ( ! material.castShadow && isShadowRay ) {
|
|
6072
6423
|
|
|
6073
|
-
|
|
6074
|
-
vec3 absPoint = abs( point );
|
|
6075
|
-
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
6076
|
-
rayOrigin = point - ( maxPoint + 1.0 ) * faceNormal * RAY_OFFSET;
|
|
6077
|
-
|
|
6424
|
+
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
6078
6425
|
continue;
|
|
6079
6426
|
|
|
6080
6427
|
}
|
|
@@ -6123,10 +6470,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6123
6470
|
|| material.transparent && ! useAlphaTest && albedo.a < sobol( 3 )
|
|
6124
6471
|
) {
|
|
6125
6472
|
|
|
6126
|
-
|
|
6127
|
-
vec3 absPoint = abs( point );
|
|
6128
|
-
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
6129
|
-
rayOrigin = point - ( maxPoint + 1.0 ) * faceNormal * RAY_OFFSET;
|
|
6473
|
+
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
6130
6474
|
|
|
6131
6475
|
// only allow a limited number of transparency discards otherwise we could
|
|
6132
6476
|
// crash the context with too long a loop.
|
|
@@ -6333,6 +6677,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6333
6677
|
surfaceRec.metalness = metalness;
|
|
6334
6678
|
surfaceRec.color = albedo.rgb;
|
|
6335
6679
|
surfaceRec.clearcoat = clearcoat;
|
|
6680
|
+
surfaceRec.sheen = material.sheen;
|
|
6336
6681
|
surfaceRec.sheenColor = sheenColor;
|
|
6337
6682
|
surfaceRec.iridescence = iridescence;
|
|
6338
6683
|
surfaceRec.iridescenceIor = material.iridescenceIor;
|
|
@@ -6342,11 +6687,12 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6342
6687
|
surfaceRec.attenuationColor = material.attenuationColor;
|
|
6343
6688
|
surfaceRec.attenuationDistance = material.attenuationDistance;
|
|
6344
6689
|
|
|
6345
|
-
// apply perceptual roughness factor from gltf
|
|
6690
|
+
// apply perceptual roughness factor from gltf. sheen perceptual roughness is
|
|
6691
|
+
// applied by its brdf function
|
|
6346
6692
|
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
|
|
6347
6693
|
surfaceRec.roughness = roughness * roughness;
|
|
6348
6694
|
surfaceRec.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
|
|
6349
|
-
surfaceRec.sheenRoughness = sheenRoughness
|
|
6695
|
+
surfaceRec.sheenRoughness = sheenRoughness;
|
|
6350
6696
|
|
|
6351
6697
|
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
|
|
6352
6698
|
// then we can just always assume this is a front face.
|
|
@@ -6372,18 +6718,14 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6372
6718
|
vec3 clearcoatOutgoing = - normalize( clearcoatInvBasis * rayDirection );
|
|
6373
6719
|
sampleRec = bsdfSample( outgoing, clearcoatOutgoing, normalBasis, invBasis, clearcoatNormalBasis, clearcoatInvBasis, surfaceRec );
|
|
6374
6720
|
|
|
6721
|
+
bool wasBelowSurface = dot( rayDirection, faceNormal ) > 0.0;
|
|
6375
6722
|
isShadowRay = sampleRec.specularPdf < sobol( 4 );
|
|
6376
6723
|
|
|
6377
|
-
|
|
6378
|
-
// maximum component-wise value of the current point to accommodate floating point
|
|
6379
|
-
// error as values increase.
|
|
6380
|
-
vec3 point = rayOrigin + rayDirection * dist;
|
|
6381
|
-
vec3 absPoint = abs( point );
|
|
6382
|
-
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
6724
|
+
vec3 prevRayDirection = rayDirection;
|
|
6383
6725
|
rayDirection = normalize( normalBasis * sampleRec.direction );
|
|
6384
6726
|
|
|
6385
6727
|
bool isBelowSurface = dot( rayDirection, faceNormal ) < 0.0;
|
|
6386
|
-
rayOrigin =
|
|
6728
|
+
rayOrigin = stepRayOrigin( rayOrigin, prevRayDirection, isBelowSurface ? - faceNormal : faceNormal, dist );
|
|
6387
6729
|
|
|
6388
6730
|
// direct env map sampling
|
|
6389
6731
|
#if FEATURE_MIS
|
|
@@ -6402,10 +6744,11 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6402
6744
|
}
|
|
6403
6745
|
|
|
6404
6746
|
// check if a ray could even reach the light area
|
|
6747
|
+
vec3 attenuatedColor;
|
|
6405
6748
|
if (
|
|
6406
6749
|
lightSampleRec.pdf > 0.0 &&
|
|
6407
6750
|
isDirectionValid( lightSampleRec.direction, normal, faceNormal ) &&
|
|
6408
|
-
!
|
|
6751
|
+
! attenuateHit( bvh, rayOrigin, lightSampleRec.direction, lightSampleRec.dist, bounces - i, transparentTraversals, isShadowRay, attenuatedColor )
|
|
6409
6752
|
) {
|
|
6410
6753
|
|
|
6411
6754
|
// get the material pdf
|
|
@@ -6417,7 +6760,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6417
6760
|
// weight the direct light contribution
|
|
6418
6761
|
float lightPdf = lightSampleRec.pdf / float( lights.count + 1u );
|
|
6419
6762
|
float misWeight = lightSampleRec.type == SPOT_LIGHT_TYPE || lightSampleRec.type == DIR_LIGHT_TYPE || lightSampleRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
|
|
6420
|
-
gl_FragColor.rgb += lightSampleRec.emission * throughputColor * sampleColor * misWeight / lightPdf;
|
|
6763
|
+
gl_FragColor.rgb += attenuatedColor * lightSampleRec.emission * throughputColor * sampleColor * misWeight / lightPdf;
|
|
6421
6764
|
|
|
6422
6765
|
}
|
|
6423
6766
|
|
|
@@ -6445,7 +6788,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6445
6788
|
if (
|
|
6446
6789
|
envPdf > 0.0 &&
|
|
6447
6790
|
isDirectionValid( envDirection, normal, faceNormal ) &&
|
|
6448
|
-
! attenuateHit( bvh, rayOrigin, envDirection, bounces - i, isShadowRay, attenuatedColor )
|
|
6791
|
+
! attenuateHit( bvh, rayOrigin, envDirection, INFINITY, bounces - i, transparentTraversals, isShadowRay, attenuatedColor )
|
|
6449
6792
|
) {
|
|
6450
6793
|
|
|
6451
6794
|
// get the material pdf
|
|
@@ -6481,6 +6824,16 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6481
6824
|
|
|
6482
6825
|
}
|
|
6483
6826
|
|
|
6827
|
+
// if we're bouncing around the inside a transmissive material then decrement
|
|
6828
|
+
// perform this separate from a bounce
|
|
6829
|
+
bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
|
|
6830
|
+
if ( ( isTransmissiveRay || isBelowSurface ) && transparentTraversals > 0 ) {
|
|
6831
|
+
|
|
6832
|
+
transparentTraversals --;
|
|
6833
|
+
i --;
|
|
6834
|
+
|
|
6835
|
+
}
|
|
6836
|
+
|
|
6484
6837
|
// accumulate color
|
|
6485
6838
|
gl_FragColor.rgb += ( emission * throughputColor );
|
|
6486
6839
|
|
|
@@ -6491,6 +6844,29 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6491
6844
|
|
|
6492
6845
|
}
|
|
6493
6846
|
|
|
6847
|
+
#if FEATURE_RUSSIAN_ROULETTE
|
|
6848
|
+
|
|
6849
|
+
// russian roulette path termination
|
|
6850
|
+
// https://www.arnoldrenderer.com/research/physically_based_shader_design_in_arnold.pdf
|
|
6851
|
+
uint minBounces = 3u;
|
|
6852
|
+
float depthProb = float( sobolBounceIndex < minBounces );
|
|
6853
|
+
|
|
6854
|
+
float rrProb = luminance( throughputColor * sampleRec.color / sampleRec.pdf );
|
|
6855
|
+
rrProb /= luminance( throughputColor );
|
|
6856
|
+
rrProb = sqrt( rrProb );
|
|
6857
|
+
rrProb = max( rrProb, depthProb );
|
|
6858
|
+
rrProb = min( rrProb, 1.0 );
|
|
6859
|
+
if ( sobol( 8 ) > rrProb ) {
|
|
6860
|
+
|
|
6861
|
+
break;
|
|
6862
|
+
|
|
6863
|
+
}
|
|
6864
|
+
|
|
6865
|
+
// perform sample clamping here to avoid bright pixels
|
|
6866
|
+
throughputColor *= min( 1.0 / rrProb, 20.0 );
|
|
6867
|
+
|
|
6868
|
+
#endif
|
|
6869
|
+
|
|
6494
6870
|
throughputColor *= sampleRec.color / sampleRec.pdf;
|
|
6495
6871
|
|
|
6496
6872
|
// attenuate the throughput color by the medium color
|
|
@@ -6507,6 +6883,7 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6507
6883
|
|
|
6508
6884
|
}
|
|
6509
6885
|
|
|
6886
|
+
|
|
6510
6887
|
}
|
|
6511
6888
|
|
|
6512
6889
|
gl_FragColor.a *= opacity;
|
|
@@ -6525,5 +6902,5 @@ class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
6525
6902
|
|
|
6526
6903
|
// core
|
|
6527
6904
|
|
|
6528
|
-
export { BlurredEnvMapGenerator, DenoiseMaterial, DynamicPathTracingSceneGenerator, EquirectCamera, EquirectHdrInfoUniform, GradientEquirectTexture, GraphMaterial, IESLoader, IESProfilesTexture, LightsInfoUniformStruct, MaterialBase, MaterialReducer, MaterialsTexture, PathTracingRenderer, PathTracingSceneGenerator, PhysicalCamera, PhysicalCameraUniform, PhysicalPathTracingMaterial, PhysicalSpotLight, ProceduralEquirectTexture, RenderTarget2DArray, ShapedAreaLight, getGroupMaterialIndicesAttribute, mergeMeshes, setCommonAttributes, shaderLightStruct, shaderMaterialSampling, shaderMaterialStructs, shaderUtils, trimToAttributes };
|
|
6905
|
+
export { BlurredEnvMapGenerator, DenoiseMaterial, DynamicPathTracingSceneGenerator, EquirectCamera, EquirectHdrInfoUniform, GradientEquirectTexture, GraphMaterial, IESLoader, IESProfilesTexture, LightsInfoUniformStruct, MaterialBase, MaterialReducer, MaterialsTexture, PathTracingRenderer, PathTracingSceneGenerator, PhysicalCamera, PhysicalCameraUniform, PhysicalPathTracingMaterial, PhysicalSpotLight, ProceduralEquirectTexture, QuiltPathTracingRenderer, RenderTarget2DArray, ShapedAreaLight, getGroupMaterialIndicesAttribute, mergeMeshes, setCommonAttributes, shaderLightStruct, shaderMaterialSampling, shaderMaterialStructs, shaderUtils, trimToAttributes };
|
|
6529
6906
|
//# sourceMappingURL=index.module.js.map
|