three-gpu-pathtracer 0.0.21 → 0.0.23
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/build/index.module.js +411 -44
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +410 -43
- package/build/index.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/core/PathTracingRenderer.js +48 -1
- package/src/core/WebGLPathTracer.js +62 -8
- package/src/core/utils/BakedGeometry.js +23 -0
- package/src/core/utils/BufferAttributeUtils.js +11 -3
- package/src/core/utils/MeshDiff.js +6 -13
- package/src/core/utils/StaticGeometryGenerator.js +19 -4
- package/src/materials/MaterialBase.js +11 -0
- package/src/uniforms/StratifiedSamplesTexture.js +55 -3
- package/src/uniforms/stratified/StratifiedSampler.js +19 -7
- package/src/uniforms/stratified/StratifiedSamplerCombined.js +14 -4
- package/src/utils/CubeToEquirectGenerator.js +159 -0
package/build/index.umd.cjs
CHANGED
|
@@ -45,12 +45,18 @@
|
|
|
45
45
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// Confirms that the two provided attributes are compatible
|
|
48
|
+
// Confirms that the two provided attributes are compatible. Returns false if they are not.
|
|
49
49
|
function validateAttributes( attr1, attr2 ) {
|
|
50
50
|
|
|
51
51
|
if ( ! attr1 && ! attr2 ) {
|
|
52
52
|
|
|
53
|
-
return;
|
|
53
|
+
return true;
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if ( Boolean( attr1 ) !== Boolean( attr2 ) ) {
|
|
58
|
+
|
|
59
|
+
return false;
|
|
54
60
|
|
|
55
61
|
}
|
|
56
62
|
|
|
@@ -61,10 +67,12 @@
|
|
|
61
67
|
|
|
62
68
|
if ( ! sameCount || ! sameNormalized || ! sameType || ! sameItemSize ) {
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
return false;
|
|
65
71
|
|
|
66
72
|
}
|
|
67
73
|
|
|
74
|
+
return true;
|
|
75
|
+
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
function validateMergeability( geometries ) {
|
|
@@ -432,29 +440,22 @@
|
|
|
432
440
|
|
|
433
441
|
}
|
|
434
442
|
|
|
435
|
-
function attributeSort( a, b ) {
|
|
436
|
-
|
|
437
|
-
if ( a.uuid > b.uuid ) return 1;
|
|
438
|
-
if ( a.uuid < b.uuid ) return - 1;
|
|
439
|
-
return 0;
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
443
|
function getGeometryHash( geometry ) {
|
|
444
444
|
|
|
445
|
-
let hash =
|
|
445
|
+
let hash = geometry.uuid;
|
|
446
446
|
const attributes = Object.values( geometry.attributes );
|
|
447
447
|
if ( geometry.index ) {
|
|
448
448
|
|
|
449
449
|
attributes.push( geometry.index );
|
|
450
|
+
hash += `index|${ geometry.index.version }`;
|
|
450
451
|
|
|
451
452
|
}
|
|
452
453
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
for ( const attr of attributes ) {
|
|
454
|
+
const keys = Object.keys( attributes ).sort();
|
|
455
|
+
for ( const key of keys ) {
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
const attr = attributes[ key ];
|
|
458
|
+
hash += `${ key }_${ attr.version }|`;
|
|
458
459
|
|
|
459
460
|
}
|
|
460
461
|
|
|
@@ -885,6 +886,28 @@
|
|
|
885
886
|
|
|
886
887
|
}
|
|
887
888
|
|
|
889
|
+
// returns whether the passed mesh is compatible with this baked geometry
|
|
890
|
+
// such that it can be updated without resizing attributes
|
|
891
|
+
isCompatible( mesh, attributes ) {
|
|
892
|
+
|
|
893
|
+
const geometry = mesh.geometry;
|
|
894
|
+
for ( let i = 0; i < attributes.length; i ++ ) {
|
|
895
|
+
|
|
896
|
+
const key = attributes[ i ];
|
|
897
|
+
const attr1 = geometry.attributes[ key ];
|
|
898
|
+
const attr2 = this.attributes[ key ];
|
|
899
|
+
if ( attr1 && ! validateAttributes( attr1, attr2 ) ) {
|
|
900
|
+
|
|
901
|
+
return false;
|
|
902
|
+
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return true;
|
|
908
|
+
|
|
909
|
+
}
|
|
910
|
+
|
|
888
911
|
updateFrom( mesh, options ) {
|
|
889
912
|
|
|
890
913
|
const diff = this._diff;
|
|
@@ -916,7 +939,7 @@
|
|
|
916
939
|
for ( let i = 0, l = objects.length; i < l; i ++ ) {
|
|
917
940
|
|
|
918
941
|
const object = objects[ i ];
|
|
919
|
-
object.
|
|
942
|
+
object.traverseVisible( o => {
|
|
920
943
|
|
|
921
944
|
if ( o.isMesh ) {
|
|
922
945
|
|
|
@@ -1074,15 +1097,24 @@
|
|
|
1074
1097
|
unusedMeshKeys.delete( meshKey );
|
|
1075
1098
|
|
|
1076
1099
|
// initialize the intermediate geometry
|
|
1077
|
-
if
|
|
1100
|
+
// if the mesh and source geometry have changed in such a way that they are no longer
|
|
1101
|
+
// compatible then regenerate the baked geometry from scratch
|
|
1102
|
+
let geom = _intermediateGeometry.get( meshKey );
|
|
1103
|
+
if ( ! geom || ! geom.isCompatible( mesh, this.attributes ) ) {
|
|
1104
|
+
|
|
1105
|
+
if ( geom ) {
|
|
1106
|
+
|
|
1107
|
+
geom.dispose();
|
|
1108
|
+
|
|
1109
|
+
}
|
|
1078
1110
|
|
|
1079
|
-
|
|
1111
|
+
geom = new BakedGeometry();
|
|
1112
|
+
_intermediateGeometry.set( meshKey, geom );
|
|
1080
1113
|
|
|
1081
1114
|
}
|
|
1082
1115
|
|
|
1083
1116
|
// transform the geometry into the intermediate buffer geometry, saving whether
|
|
1084
1117
|
// or not it changed.
|
|
1085
|
-
const geom = _intermediateGeometry.get( meshKey );
|
|
1086
1118
|
if ( geom.updateFrom( mesh, convertOptions ) ) {
|
|
1087
1119
|
|
|
1088
1120
|
// TODO: provide option for only generating the set of attributes that are present
|
|
@@ -1134,6 +1166,12 @@
|
|
|
1134
1166
|
|
|
1135
1167
|
// get the list of geometries to merge
|
|
1136
1168
|
let forceUpdate = false;
|
|
1169
|
+
if ( meshes.length !== previousMergeInfo.length ) {
|
|
1170
|
+
|
|
1171
|
+
forceUpdate = true;
|
|
1172
|
+
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1137
1175
|
for ( let i = 0, l = meshes.length; i < l; i ++ ) {
|
|
1138
1176
|
|
|
1139
1177
|
const mesh = meshes[ i ];
|
|
@@ -1445,6 +1483,17 @@
|
|
|
1445
1483
|
|
|
1446
1484
|
class MaterialBase extends three.ShaderMaterial {
|
|
1447
1485
|
|
|
1486
|
+
set needsUpdate( v ) {
|
|
1487
|
+
|
|
1488
|
+
super.needsUpdate = true;
|
|
1489
|
+
this.dispatchEvent( {
|
|
1490
|
+
|
|
1491
|
+
type: 'recompilation',
|
|
1492
|
+
|
|
1493
|
+
} );
|
|
1494
|
+
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1448
1497
|
constructor( shader ) {
|
|
1449
1498
|
|
|
1450
1499
|
super( shader );
|
|
@@ -3445,11 +3494,11 @@
|
|
|
3445
3494
|
// - https://github.com/hoverinc/ray-tracing-renderer
|
|
3446
3495
|
// - http://www.pbr-book.org/3ed-2018/Sampling_and_Reconstruction/Stratified_Sampling.html
|
|
3447
3496
|
|
|
3448
|
-
function shuffle( arr ) {
|
|
3497
|
+
function shuffle( arr, random = Math.random() ) {
|
|
3449
3498
|
|
|
3450
3499
|
for ( let i = arr.length - 1; i > 0; i -- ) {
|
|
3451
3500
|
|
|
3452
|
-
const j = Math.floor(
|
|
3501
|
+
const j = Math.floor( random() * ( i + 1 ) );
|
|
3453
3502
|
const x = arr[ i ];
|
|
3454
3503
|
arr[ i ] = arr[ j ];
|
|
3455
3504
|
arr[ j ] = x;
|
|
@@ -3464,7 +3513,7 @@
|
|
|
3464
3513
|
// dimensions : The number of dimensions to generate stratified values for
|
|
3465
3514
|
class StratifiedSampler {
|
|
3466
3515
|
|
|
3467
|
-
constructor( strataCount, dimensions ) {
|
|
3516
|
+
constructor( strataCount, dimensions, random = Math.random ) {
|
|
3468
3517
|
|
|
3469
3518
|
const l = strataCount ** dimensions;
|
|
3470
3519
|
const strata = new Uint16Array( l );
|
|
@@ -3481,7 +3530,19 @@
|
|
|
3481
3530
|
|
|
3482
3531
|
this.strataCount = strataCount;
|
|
3483
3532
|
|
|
3484
|
-
this.
|
|
3533
|
+
this.reset = function () {
|
|
3534
|
+
|
|
3535
|
+
for ( let i = 0; i < l; i ++ ) {
|
|
3536
|
+
|
|
3537
|
+
strata[ i ] = i;
|
|
3538
|
+
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3541
|
+
index = 0;
|
|
3542
|
+
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
this.reshuffle = function () {
|
|
3485
3546
|
|
|
3486
3547
|
index = 0;
|
|
3487
3548
|
|
|
@@ -3493,8 +3554,8 @@
|
|
|
3493
3554
|
|
|
3494
3555
|
if ( index >= strata.length ) {
|
|
3495
3556
|
|
|
3496
|
-
shuffle( strata );
|
|
3497
|
-
this.
|
|
3557
|
+
shuffle( strata, random );
|
|
3558
|
+
this.reshuffle();
|
|
3498
3559
|
|
|
3499
3560
|
}
|
|
3500
3561
|
|
|
@@ -3502,7 +3563,7 @@
|
|
|
3502
3563
|
|
|
3503
3564
|
for ( let i = 0; i < dimensions; i ++ ) {
|
|
3504
3565
|
|
|
3505
|
-
samples[ i ] = ( stratum % strataCount +
|
|
3566
|
+
samples[ i ] = ( stratum % strataCount + random() ) / strataCount;
|
|
3506
3567
|
stratum = Math.floor( stratum / strataCount );
|
|
3507
3568
|
|
|
3508
3569
|
}
|
|
@@ -3520,7 +3581,7 @@
|
|
|
3520
3581
|
// Stratified set of data with each tuple stratified separately and combined
|
|
3521
3582
|
class StratifiedSamplerCombined {
|
|
3522
3583
|
|
|
3523
|
-
constructor( strataCount, listOfDimensions ) {
|
|
3584
|
+
constructor( strataCount, listOfDimensions, random = Math.random ) {
|
|
3524
3585
|
|
|
3525
3586
|
let totalDim = 0;
|
|
3526
3587
|
for ( const dim of listOfDimensions ) {
|
|
@@ -3534,7 +3595,7 @@
|
|
|
3534
3595
|
let offset = 0;
|
|
3535
3596
|
for ( const dim of listOfDimensions ) {
|
|
3536
3597
|
|
|
3537
|
-
const sampler = new StratifiedSampler( strataCount, dim );
|
|
3598
|
+
const sampler = new StratifiedSampler( strataCount, dim, random );
|
|
3538
3599
|
sampler.samples = new Float32Array( combined.buffer, offset, sampler.samples.length );
|
|
3539
3600
|
offset += sampler.samples.length * 4;
|
|
3540
3601
|
strataObjs.push( sampler );
|
|
@@ -3557,11 +3618,21 @@
|
|
|
3557
3618
|
|
|
3558
3619
|
};
|
|
3559
3620
|
|
|
3560
|
-
this.
|
|
3621
|
+
this.reshuffle = function () {
|
|
3561
3622
|
|
|
3562
3623
|
for ( const strata of strataObjs ) {
|
|
3563
3624
|
|
|
3564
|
-
strata.
|
|
3625
|
+
strata.reshuffle();
|
|
3626
|
+
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
};
|
|
3630
|
+
|
|
3631
|
+
this.reset = function () {
|
|
3632
|
+
|
|
3633
|
+
for ( const strata of strataObjs ) {
|
|
3634
|
+
|
|
3635
|
+
strata.reset();
|
|
3565
3636
|
|
|
3566
3637
|
}
|
|
3567
3638
|
|
|
@@ -3571,6 +3642,36 @@
|
|
|
3571
3642
|
|
|
3572
3643
|
}
|
|
3573
3644
|
|
|
3645
|
+
// https://stackoverflow.com/questions/424292/seedable-javascript-random-number-generator
|
|
3646
|
+
class RandomGenerator {
|
|
3647
|
+
|
|
3648
|
+
constructor( seed = 0 ) {
|
|
3649
|
+
|
|
3650
|
+
// LCG using GCC's constants
|
|
3651
|
+
this.m = 0x80000000; // 2**31;
|
|
3652
|
+
this.a = 1103515245;
|
|
3653
|
+
this.c = 12345;
|
|
3654
|
+
|
|
3655
|
+
this.seed = seed;
|
|
3656
|
+
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
nextInt() {
|
|
3660
|
+
|
|
3661
|
+
this.seed = ( this.a * this.seed + this.c ) % this.m;
|
|
3662
|
+
return this.seed;
|
|
3663
|
+
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
nextFloat() {
|
|
3667
|
+
|
|
3668
|
+
// returns in range [0,1]
|
|
3669
|
+
return this.nextInt() / ( this.m - 1 );
|
|
3670
|
+
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3574
3675
|
class StratifiedSamplesTexture extends three.DataTexture {
|
|
3575
3676
|
|
|
3576
3677
|
constructor( count = 1, depth = 1, strata = 8 ) {
|
|
@@ -3581,22 +3682,37 @@
|
|
|
3581
3682
|
|
|
3582
3683
|
this.strata = strata;
|
|
3583
3684
|
this.sampler = null;
|
|
3685
|
+
this.generator = new RandomGenerator();
|
|
3686
|
+
this.stableNoise = false;
|
|
3687
|
+
this.random = () => {
|
|
3688
|
+
|
|
3689
|
+
if ( this.stableNoise ) {
|
|
3690
|
+
|
|
3691
|
+
return this.generator.nextFloat();
|
|
3692
|
+
|
|
3693
|
+
} else {
|
|
3694
|
+
|
|
3695
|
+
return Math.random();
|
|
3696
|
+
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3699
|
+
};
|
|
3584
3700
|
|
|
3585
3701
|
this.init( count, depth, strata );
|
|
3586
3702
|
|
|
3587
3703
|
}
|
|
3588
3704
|
|
|
3589
|
-
init( count, depth, strata = this.strata ) {
|
|
3705
|
+
init( count = this.image.height, depth = this.image.width, strata = this.strata ) {
|
|
3590
3706
|
|
|
3591
3707
|
const { image } = this;
|
|
3592
|
-
if ( image.width === depth && image.height === count ) {
|
|
3708
|
+
if ( image.width === depth && image.height === count && this.sampler !== null ) {
|
|
3593
3709
|
|
|
3594
3710
|
return;
|
|
3595
3711
|
|
|
3596
3712
|
}
|
|
3597
3713
|
|
|
3598
3714
|
const dimensions = new Array( count * depth ).fill( 4 );
|
|
3599
|
-
const sampler = new StratifiedSamplerCombined( strata, dimensions );
|
|
3715
|
+
const sampler = new StratifiedSamplerCombined( strata, dimensions, this.random );
|
|
3600
3716
|
|
|
3601
3717
|
image.width = depth;
|
|
3602
3718
|
image.height = count;
|
|
@@ -3616,6 +3732,13 @@
|
|
|
3616
3732
|
|
|
3617
3733
|
}
|
|
3618
3734
|
|
|
3735
|
+
reset() {
|
|
3736
|
+
|
|
3737
|
+
this.sampler.reset();
|
|
3738
|
+
this.generator.seed = 0;
|
|
3739
|
+
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3619
3742
|
}
|
|
3620
3743
|
|
|
3621
3744
|
function shuffleArray( array, random = Math.random ) {
|
|
@@ -7779,6 +7902,9 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7779
7902
|
|
|
7780
7903
|
set material( v ) {
|
|
7781
7904
|
|
|
7905
|
+
this._fsQuad.material.removeEventListener( 'recompilation', this._compileFunction );
|
|
7906
|
+
v.addEventListener( 'recompilation', this._compileFunction );
|
|
7907
|
+
|
|
7782
7908
|
this._fsQuad.material = v;
|
|
7783
7909
|
|
|
7784
7910
|
}
|
|
@@ -7815,6 +7941,12 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7815
7941
|
|
|
7816
7942
|
}
|
|
7817
7943
|
|
|
7944
|
+
get isCompiling() {
|
|
7945
|
+
|
|
7946
|
+
return Boolean( this._compilePromise );
|
|
7947
|
+
|
|
7948
|
+
}
|
|
7949
|
+
|
|
7818
7950
|
constructor( renderer ) {
|
|
7819
7951
|
|
|
7820
7952
|
this.camera = null;
|
|
@@ -7832,6 +7964,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7832
7964
|
this._blendQuad = new Pass_js.FullScreenQuad( new BlendMaterial() );
|
|
7833
7965
|
this._task = null;
|
|
7834
7966
|
this._currentTile = 0;
|
|
7967
|
+
this._compilePromise = null;
|
|
7835
7968
|
|
|
7836
7969
|
this._sobolTarget = new SobolNumberMapGenerator().generate( renderer );
|
|
7837
7970
|
|
|
@@ -7856,6 +7989,33 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7856
7989
|
} ),
|
|
7857
7990
|
];
|
|
7858
7991
|
|
|
7992
|
+
// function for listening to for triggered compilation so we can wait for compilation to finish
|
|
7993
|
+
// before starting to render
|
|
7994
|
+
this._compileFunction = () => {
|
|
7995
|
+
|
|
7996
|
+
const promise = this.compileMaterial( this._fsQuad._mesh );
|
|
7997
|
+
promise.then( () => {
|
|
7998
|
+
|
|
7999
|
+
if ( this._compilePromise === promise ) {
|
|
8000
|
+
|
|
8001
|
+
this._compilePromise = null;
|
|
8002
|
+
|
|
8003
|
+
}
|
|
8004
|
+
|
|
8005
|
+
} );
|
|
8006
|
+
|
|
8007
|
+
this._compilePromise = promise;
|
|
8008
|
+
|
|
8009
|
+
};
|
|
8010
|
+
|
|
8011
|
+
this.material.addEventListener( 'recompilation', this._compileFunction );
|
|
8012
|
+
|
|
8013
|
+
}
|
|
8014
|
+
|
|
8015
|
+
compileMaterial() {
|
|
8016
|
+
|
|
8017
|
+
return this._renderer.compileAsync( this._fsQuad._mesh );
|
|
8018
|
+
|
|
7859
8019
|
}
|
|
7860
8020
|
|
|
7861
8021
|
setCamera( camera ) {
|
|
@@ -7887,7 +8047,6 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7887
8047
|
material.setDefine( 'CAMERA_TYPE', cameraType );
|
|
7888
8048
|
|
|
7889
8049
|
this.camera = camera;
|
|
7890
|
-
// this.reset();
|
|
7891
8050
|
|
|
7892
8051
|
}
|
|
7893
8052
|
|
|
@@ -7954,9 +8113,11 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7954
8113
|
this.samples = 0;
|
|
7955
8114
|
this._task = null;
|
|
7956
8115
|
|
|
8116
|
+
this.material.stratifiedTexture.stableNoise = this.stableNoise;
|
|
7957
8117
|
if ( this.stableNoise ) {
|
|
7958
8118
|
|
|
7959
8119
|
this.material.seed = 0;
|
|
8120
|
+
this.material.stratifiedTexture.reset();
|
|
7960
8121
|
|
|
7961
8122
|
}
|
|
7962
8123
|
|
|
@@ -7964,6 +8125,15 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7964
8125
|
|
|
7965
8126
|
update() {
|
|
7966
8127
|
|
|
8128
|
+
// ensure we've updated our defines before rendering so we can ensure we
|
|
8129
|
+
// can wait for compilation to finish
|
|
8130
|
+
this.material.onBeforeRender();
|
|
8131
|
+
if ( this.isCompiling ) {
|
|
8132
|
+
|
|
8133
|
+
return;
|
|
8134
|
+
|
|
8135
|
+
}
|
|
8136
|
+
|
|
7967
8137
|
if ( ! this._task ) {
|
|
7968
8138
|
|
|
7969
8139
|
this._task = renderTask.call( this );
|
|
@@ -8183,6 +8353,150 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8183
8353
|
|
|
8184
8354
|
}
|
|
8185
8355
|
|
|
8356
|
+
class CubeToEquirectMaterial extends three.ShaderMaterial {
|
|
8357
|
+
|
|
8358
|
+
constructor() {
|
|
8359
|
+
|
|
8360
|
+
super( {
|
|
8361
|
+
|
|
8362
|
+
uniforms: {
|
|
8363
|
+
|
|
8364
|
+
envMap: { value: null },
|
|
8365
|
+
flipEnvMap: { value: - 1 },
|
|
8366
|
+
|
|
8367
|
+
},
|
|
8368
|
+
|
|
8369
|
+
vertexShader: /* glsl */`
|
|
8370
|
+
varying vec2 vUv;
|
|
8371
|
+
void main() {
|
|
8372
|
+
|
|
8373
|
+
vUv = uv;
|
|
8374
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
8375
|
+
|
|
8376
|
+
}`,
|
|
8377
|
+
|
|
8378
|
+
fragmentShader: /* glsl */`
|
|
8379
|
+
#define ENVMAP_TYPE_CUBE_UV
|
|
8380
|
+
|
|
8381
|
+
uniform samplerCube envMap;
|
|
8382
|
+
uniform float flipEnvMap;
|
|
8383
|
+
varying vec2 vUv;
|
|
8384
|
+
|
|
8385
|
+
#include <common>
|
|
8386
|
+
#include <cube_uv_reflection_fragment>
|
|
8387
|
+
|
|
8388
|
+
${ util_functions }
|
|
8389
|
+
|
|
8390
|
+
void main() {
|
|
8391
|
+
|
|
8392
|
+
vec3 rayDirection = equirectUvToDirection( vUv );
|
|
8393
|
+
rayDirection.x *= flipEnvMap;
|
|
8394
|
+
gl_FragColor = textureCube( envMap, rayDirection );
|
|
8395
|
+
|
|
8396
|
+
}`
|
|
8397
|
+
} );
|
|
8398
|
+
|
|
8399
|
+
this.depthWrite = false;
|
|
8400
|
+
this.depthTest = false;
|
|
8401
|
+
|
|
8402
|
+
}
|
|
8403
|
+
|
|
8404
|
+
}
|
|
8405
|
+
|
|
8406
|
+
class CubeToEquirectGenerator {
|
|
8407
|
+
|
|
8408
|
+
constructor( renderer ) {
|
|
8409
|
+
|
|
8410
|
+
this._renderer = renderer;
|
|
8411
|
+
this._quad = new Pass_js.FullScreenQuad( new CubeToEquirectMaterial() );
|
|
8412
|
+
|
|
8413
|
+
}
|
|
8414
|
+
|
|
8415
|
+
generate( source, width = null, height = null ) {
|
|
8416
|
+
|
|
8417
|
+
if ( ! source.isCubeTexture ) {
|
|
8418
|
+
|
|
8419
|
+
throw new Error( 'CubeToEquirectMaterial: Source can only be cube textures.' );
|
|
8420
|
+
|
|
8421
|
+
}
|
|
8422
|
+
|
|
8423
|
+
const image = source.images[ 0 ];
|
|
8424
|
+
const renderer = this._renderer;
|
|
8425
|
+
const quad = this._quad;
|
|
8426
|
+
|
|
8427
|
+
// determine the dimensions if not provided
|
|
8428
|
+
if ( width === null ) {
|
|
8429
|
+
|
|
8430
|
+
width = 4 * image.height;
|
|
8431
|
+
|
|
8432
|
+
}
|
|
8433
|
+
|
|
8434
|
+
if ( height === null ) {
|
|
8435
|
+
|
|
8436
|
+
height = 2 * image.height;
|
|
8437
|
+
|
|
8438
|
+
}
|
|
8439
|
+
|
|
8440
|
+
const target = new three.WebGLRenderTarget( width, height, {
|
|
8441
|
+
type: three.FloatType,
|
|
8442
|
+
colorSpace: image.colorSpace,
|
|
8443
|
+
} );
|
|
8444
|
+
|
|
8445
|
+
// prep the cube map data
|
|
8446
|
+
const imageHeight = image.height;
|
|
8447
|
+
const maxMip = Math.log2( imageHeight ) - 2;
|
|
8448
|
+
const texelHeight = 1.0 / imageHeight;
|
|
8449
|
+
const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
|
|
8450
|
+
|
|
8451
|
+
quad.material.defines.CUBEUV_MAX_MIP = `${ maxMip }.0`;
|
|
8452
|
+
quad.material.defines.CUBEUV_TEXEL_WIDTH = texelWidth;
|
|
8453
|
+
quad.material.defines.CUBEUV_TEXEL_HEIGHT = texelHeight;
|
|
8454
|
+
quad.material.uniforms.envMap.value = source;
|
|
8455
|
+
quad.material.uniforms.flipEnvMap.value = source.isRenderTargetTexture ? 1 : - 1;
|
|
8456
|
+
quad.material.needsUpdate = true;
|
|
8457
|
+
|
|
8458
|
+
// save state and render the contents
|
|
8459
|
+
const currentTarget = renderer.getRenderTarget();
|
|
8460
|
+
const currentAutoClear = renderer.autoClear;
|
|
8461
|
+
renderer.autoClear = true;
|
|
8462
|
+
renderer.setRenderTarget( target );
|
|
8463
|
+
quad.render( renderer );
|
|
8464
|
+
renderer.setRenderTarget( currentTarget );
|
|
8465
|
+
renderer.autoClear = currentAutoClear;
|
|
8466
|
+
|
|
8467
|
+
// read the data back
|
|
8468
|
+
const buffer = new Uint16Array( width * height * 4 );
|
|
8469
|
+
const readBuffer = new Float32Array( width * height * 4 );
|
|
8470
|
+
renderer.readRenderTargetPixels( target, 0, 0, width, height, readBuffer );
|
|
8471
|
+
target.dispose();
|
|
8472
|
+
|
|
8473
|
+
for ( let i = 0, l = readBuffer.length; i < l; i ++ ) {
|
|
8474
|
+
|
|
8475
|
+
buffer[ i ] = three.DataUtils.toHalfFloat( readBuffer[ i ] );
|
|
8476
|
+
|
|
8477
|
+
}
|
|
8478
|
+
|
|
8479
|
+
// produce the data texture
|
|
8480
|
+
const result = new three.DataTexture( buffer, width, height, three.RGBAFormat, three.HalfFloatType );
|
|
8481
|
+
result.minFilter = three.LinearMipMapLinearFilter;
|
|
8482
|
+
result.magFilter = three.LinearFilter;
|
|
8483
|
+
result.wrapS = three.RepeatWrapping;
|
|
8484
|
+
result.wrapT = three.RepeatWrapping;
|
|
8485
|
+
result.mapping = three.EquirectangularReflectionMapping;
|
|
8486
|
+
result.needsUpdate = true;
|
|
8487
|
+
|
|
8488
|
+
return result;
|
|
8489
|
+
|
|
8490
|
+
}
|
|
8491
|
+
|
|
8492
|
+
dispose() {
|
|
8493
|
+
|
|
8494
|
+
this._quad.dispose();
|
|
8495
|
+
|
|
8496
|
+
}
|
|
8497
|
+
|
|
8498
|
+
}
|
|
8499
|
+
|
|
8186
8500
|
function supportsFloatBlending( renderer ) {
|
|
8187
8501
|
|
|
8188
8502
|
return renderer.extensions.get( 'EXT_float_blend' );
|
|
@@ -8258,6 +8572,24 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8258
8572
|
|
|
8259
8573
|
}
|
|
8260
8574
|
|
|
8575
|
+
get stableNoise() {
|
|
8576
|
+
|
|
8577
|
+
return this._pathTracer.stableNoise;
|
|
8578
|
+
|
|
8579
|
+
}
|
|
8580
|
+
|
|
8581
|
+
set stableNoise( v ) {
|
|
8582
|
+
|
|
8583
|
+
this._pathTracer.stableNoise = v;
|
|
8584
|
+
|
|
8585
|
+
}
|
|
8586
|
+
|
|
8587
|
+
get isCompiling() {
|
|
8588
|
+
|
|
8589
|
+
return Boolean( this._pathTracer.isCompiling );
|
|
8590
|
+
|
|
8591
|
+
}
|
|
8592
|
+
|
|
8261
8593
|
constructor( renderer ) {
|
|
8262
8594
|
|
|
8263
8595
|
// members
|
|
@@ -8266,6 +8598,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8266
8598
|
this._pathTracer = new PathTracingRenderer( renderer );
|
|
8267
8599
|
this._queueReset = false;
|
|
8268
8600
|
this._clock = new three.Clock();
|
|
8601
|
+
this._compilePromise = null;
|
|
8269
8602
|
|
|
8270
8603
|
this._lowResPathTracer = new PathTracingRenderer( renderer );
|
|
8271
8604
|
this._lowResPathTracer.tiles.set( 1, 1 );
|
|
@@ -8278,6 +8611,10 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8278
8611
|
} ) );
|
|
8279
8612
|
this._materials = null;
|
|
8280
8613
|
|
|
8614
|
+
this._previousEnvironment = null;
|
|
8615
|
+
this._previousBackground = null;
|
|
8616
|
+
this._internalBackground = null;
|
|
8617
|
+
|
|
8281
8618
|
// options
|
|
8282
8619
|
this.renderDelay = 100;
|
|
8283
8620
|
this.minSamples = 5;
|
|
@@ -8406,6 +8743,13 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8406
8743
|
const scene = this.scene;
|
|
8407
8744
|
const material = this._pathTracer.material;
|
|
8408
8745
|
|
|
8746
|
+
if ( this._internalBackground ) {
|
|
8747
|
+
|
|
8748
|
+
this._internalBackground.dispose();
|
|
8749
|
+
this._internalBackground = null;
|
|
8750
|
+
|
|
8751
|
+
}
|
|
8752
|
+
|
|
8409
8753
|
// update scene background
|
|
8410
8754
|
material.backgroundBlur = scene.backgroundBlurriness;
|
|
8411
8755
|
material.backgroundIntensity = scene.backgroundIntensity ?? 1;
|
|
@@ -8433,6 +8777,17 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8433
8777
|
material.backgroundMap = colorBackground;
|
|
8434
8778
|
material.backgroundAlpha = 1;
|
|
8435
8779
|
|
|
8780
|
+
} else if ( scene.background.isCubeTexture ) {
|
|
8781
|
+
|
|
8782
|
+
if ( scene.background !== this._previousBackground ) {
|
|
8783
|
+
|
|
8784
|
+
const background = new CubeToEquirectGenerator( this._renderer ).generate( scene.background );
|
|
8785
|
+
this._internalBackground = background;
|
|
8786
|
+
material.backgroundMap = background;
|
|
8787
|
+
material.backgroundAlpha = 1;
|
|
8788
|
+
|
|
8789
|
+
}
|
|
8790
|
+
|
|
8436
8791
|
} else {
|
|
8437
8792
|
|
|
8438
8793
|
material.backgroundMap = scene.background;
|
|
@@ -8445,12 +8800,21 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8445
8800
|
material.environmentRotation.makeRotationFromEuler( scene.environmentRotation ).invert();
|
|
8446
8801
|
if ( this._previousEnvironment !== scene.environment ) {
|
|
8447
8802
|
|
|
8448
|
-
if ( scene.environment ) {
|
|
8803
|
+
if ( scene.environment !== null ) {
|
|
8804
|
+
|
|
8805
|
+
if ( scene.environment.isCubeTexture ) {
|
|
8449
8806
|
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8807
|
+
const environment = new CubeToEquirectGenerator( this._renderer ).generate( scene.environment );
|
|
8808
|
+
material.envMapInfo.updateFrom( environment );
|
|
8809
|
+
|
|
8810
|
+
} else {
|
|
8811
|
+
|
|
8812
|
+
// TODO: Consider setting this to the highest supported bit depth by checking for
|
|
8813
|
+
// OES_texture_float_linear or OES_texture_half_float_linear. Requires changes to
|
|
8814
|
+
// the equirect uniform
|
|
8815
|
+
material.envMapInfo.updateFrom( scene.environment );
|
|
8816
|
+
|
|
8817
|
+
}
|
|
8454
8818
|
|
|
8455
8819
|
} else {
|
|
8456
8820
|
|
|
@@ -8461,6 +8825,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8461
8825
|
}
|
|
8462
8826
|
|
|
8463
8827
|
this._previousEnvironment = scene.environment;
|
|
8828
|
+
this._previousBackground = scene.background;
|
|
8464
8829
|
this.reset();
|
|
8465
8830
|
|
|
8466
8831
|
}
|
|
@@ -8531,7 +8896,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8531
8896
|
// render the path tracing sample after enough time has passed
|
|
8532
8897
|
const delta = clock.getDelta() * 1e3;
|
|
8533
8898
|
const elapsedTime = clock.getElapsedTime() * 1e3;
|
|
8534
|
-
if ( ! this.pausePathTracing && this.enablePathTracing && this.renderDelay <= elapsedTime ) {
|
|
8899
|
+
if ( ! this.pausePathTracing && this.enablePathTracing && this.renderDelay <= elapsedTime && ! this.isCompiling ) {
|
|
8535
8900
|
|
|
8536
8901
|
pathTracer.update();
|
|
8537
8902
|
|
|
@@ -8564,7 +8929,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8564
8929
|
// render the fallback if we haven't rendered enough samples, are paused, or are occluded
|
|
8565
8930
|
if ( ! this.enablePathTracing || this.samples < minSamples || quad.material.opacity < 1 ) {
|
|
8566
8931
|
|
|
8567
|
-
if ( this.dynamicLowRes ) {
|
|
8932
|
+
if ( this.dynamicLowRes && ! this.isCompiling ) {
|
|
8568
8933
|
|
|
8569
8934
|
if ( lowResPathTracer.samples < 1 ) {
|
|
8570
8935
|
|
|
@@ -8579,7 +8944,9 @@ bool bvhIntersectFogVolumeHit(
|
|
|
8579
8944
|
quad.render( renderer );
|
|
8580
8945
|
quad.material.opacity = currentOpacity;
|
|
8581
8946
|
|
|
8582
|
-
}
|
|
8947
|
+
}
|
|
8948
|
+
|
|
8949
|
+
if ( ! this.dynamicLowRes && this.rasterizeScene || this.dynamicLowRes && this.isCompiling ) {
|
|
8583
8950
|
|
|
8584
8951
|
this.rasterizeSceneCallback( this.scene, this.camera );
|
|
8585
8952
|
|