rayzee 5.3.8 → 5.4.1
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/dist/rayzee.es.js +2933 -2888
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +53 -53
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +2 -2
- package/src/Passes/AIUpscaler.js +30 -6
- package/src/Passes/OIDNDenoiser.js +57 -15
- package/src/PathTracerApp.js +154 -21
- package/src/Pipeline/RenderPipeline.js +10 -1
- package/src/Processor/AssetLoader.js +40 -18
- package/src/Processor/EquirectHDRInfo.js +38 -29
- package/src/Processor/InstanceTable.js +16 -0
- package/src/Processor/SceneProcessor.js +22 -33
- package/src/Processor/ShaderBuilder.js +67 -22
- package/src/Processor/TLASBuilder.js +9 -4
- package/src/Stages/ASVGF.js +4 -4
- package/src/Stages/AdaptiveSampling.js +2 -2
- package/src/Stages/AutoExposure.js +42 -32
- package/src/Stages/BilateralFilter.js +2 -2
- package/src/Stages/Display.js +2 -1
- package/src/Stages/EdgeFilter.js +6 -3
- package/src/Stages/MotionVector.js +2 -2
- package/src/Stages/NormalDepth.js +1 -1
- package/src/Stages/PathTracer.js +88 -46
- package/src/Stages/SSRC.js +4 -4
- package/src/Stages/Variance.js +2 -2
- package/src/TSL/BVHTraversal.js +15 -63
- package/src/TSL/Clearcoat.js +1 -1
- package/src/TSL/Displacement.js +1 -1
- package/src/TSL/EmissiveSampling.js +17 -13
- package/src/TSL/Environment.js +12 -9
- package/src/TSL/LightBVHSampling.js +3 -2
- package/src/TSL/LightsCore.js +1 -1
- package/src/TSL/LightsDirect.js +1 -1
- package/src/TSL/LightsIndirect.js +0 -1
- package/src/TSL/LightsSampling.js +2 -2
- package/src/TSL/MaterialTransmission.js +1 -1
- package/src/TSL/PathTracer.js +4 -4
- package/src/TSL/PathTracerCore.js +6 -6
- package/src/TSL/Struct.js +1 -1
- package/src/TSL/patches.js +145 -0
- package/src/index.js +1 -1
- package/src/managers/EnvironmentManager.js +32 -56
- package/src/managers/LightManager.js +20 -0
- package/src/managers/UniformManager.js +22 -0
- package/src/managers/helpers/OutlineHelper.js +3 -1
- package/src/TSL/storageTexturePatch.js +0 -31
- package/src/TSL/structProxy.js +0 -87
|
@@ -352,7 +352,7 @@ export class NormalDepth extends RenderStage {
|
|
|
352
352
|
this._dispatchY = Math.ceil( height / 8 );
|
|
353
353
|
if ( this._computeNode ) {
|
|
354
354
|
|
|
355
|
-
this._computeNode.
|
|
355
|
+
this._computeNode.dispatchSize = [ this._dispatchX, this._dispatchY, 1 ];
|
|
356
356
|
|
|
357
357
|
}
|
|
358
358
|
|
package/src/Stages/PathTracer.js
CHANGED
|
@@ -180,17 +180,20 @@ export class PathTracer extends RenderStage {
|
|
|
180
180
|
// Blue noise
|
|
181
181
|
this.blueNoiseTexture = null;
|
|
182
182
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
// Packed light buffer — [lightBVH nodes (4 vec4s each) | emissive triangles (2 vec4s each)]
|
|
184
|
+
// emissiveVec4Offset uniform tracks the vec4-count offset where emissive data starts.
|
|
185
|
+
// Initialized with dummy data so TSL compilation never sees null.
|
|
186
|
+
this.lightStorageAttr = new StorageInstancedBufferAttribute( new Float32Array( 16 ), 4 );
|
|
187
|
+
this.lightStorageNode = storage( this.lightStorageAttr, 'vec4', 1 ).toReadOnly();
|
|
186
188
|
|
|
187
|
-
//
|
|
188
|
-
this.
|
|
189
|
-
this.
|
|
189
|
+
// Cached CPU-side data — rebuilt into the packed buffer whenever either source changes.
|
|
190
|
+
this._lbvhDataCache = null;
|
|
191
|
+
this._emissiveDataCache = null;
|
|
190
192
|
|
|
191
|
-
// Per-mesh visibility
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
// Per-mesh visibility is packed into the TLAS BLAS-pointer leaf's slot [2]
|
|
194
|
+
// (see TLASBuilder.flatten + BVHTraversal.js). The InstanceTable holds the
|
|
195
|
+
// tlasLeafIndex for each mesh so we can patch visibility in place.
|
|
196
|
+
this._instanceTable = null;
|
|
194
197
|
|
|
195
198
|
// Adaptive sampling
|
|
196
199
|
this.adaptiveSamplingTexture = null;
|
|
@@ -454,6 +457,7 @@ export class PathTracer extends RenderStage {
|
|
|
454
457
|
// Set data references
|
|
455
458
|
this.setTriangleData( this.sdfs.triangleData, this.sdfs.triangleCount );
|
|
456
459
|
this.setBVHData( this.sdfs.bvhData );
|
|
460
|
+
this.setInstanceTable( this.sdfs.instanceTable );
|
|
457
461
|
this.materialData.setMaterialData( this.sdfs.materialData );
|
|
458
462
|
|
|
459
463
|
// Update triangle count
|
|
@@ -768,61 +772,78 @@ export class PathTracer extends RenderStage {
|
|
|
768
772
|
}
|
|
769
773
|
|
|
770
774
|
/**
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
* @param {Array} meshes - Array of Three.js mesh objects
|
|
775
|
+
* Bind the InstanceTable used to locate each mesh's TLAS leaf for in-place
|
|
776
|
+
* visibility patching. Called by SceneProcessor during upload.
|
|
777
|
+
* @param {import('../Processor/InstanceTable.js').InstanceTable} instanceTable
|
|
775
778
|
*/
|
|
776
|
-
|
|
779
|
+
setInstanceTable( instanceTable ) {
|
|
780
|
+
|
|
781
|
+
this._instanceTable = instanceTable;
|
|
782
|
+
|
|
783
|
+
}
|
|
777
784
|
|
|
778
|
-
|
|
785
|
+
/**
|
|
786
|
+
* Initialize packed visibility for each mesh from current world-visibility.
|
|
787
|
+
* Patches the TLAS leaf slots in the combined BVH buffer that was just uploaded.
|
|
788
|
+
* @param {Array} meshes - Array of Three.js mesh objects, ordered by meshIndex
|
|
789
|
+
*/
|
|
790
|
+
setMeshVisibilityData( meshes ) {
|
|
779
791
|
|
|
780
|
-
|
|
781
|
-
// One vec4 per mesh — visibility stored in .x (simple indexing on GPU)
|
|
782
|
-
const data = new Float32Array( meshCount * 4 );
|
|
792
|
+
if ( ! meshes || meshes.length === 0 || ! this._instanceTable ) return;
|
|
783
793
|
|
|
784
|
-
for ( let i = 0; i <
|
|
794
|
+
for ( let i = 0; i < meshes.length; i ++ ) {
|
|
785
795
|
|
|
786
|
-
|
|
796
|
+
this._patchTLASLeafVisibility( i, this._isWorldVisible( meshes[ i ] ) );
|
|
787
797
|
|
|
788
798
|
}
|
|
789
799
|
|
|
790
|
-
this.
|
|
791
|
-
this.meshVisibilityStorageNode.value = this.meshVisibilityStorageAttr;
|
|
792
|
-
this.meshVisibilityStorageNode.bufferCount = meshCount;
|
|
800
|
+
if ( this.bvhStorageAttr ) this.bvhStorageAttr.needsUpdate = true;
|
|
793
801
|
|
|
794
802
|
}
|
|
795
803
|
|
|
796
804
|
/**
|
|
797
|
-
* Update visibility for a single mesh
|
|
805
|
+
* Update visibility for a single mesh by patching its TLAS leaf slot [2].
|
|
798
806
|
* @param {number} meshIndex
|
|
799
807
|
* @param {boolean} visible
|
|
800
808
|
*/
|
|
801
809
|
updateMeshVisibility( meshIndex, visible ) {
|
|
802
810
|
|
|
803
|
-
if ( ! this.
|
|
804
|
-
|
|
805
|
-
this.meshVisibilityStorageAttr.array[ meshIndex * 4 ] = visible ? 1.0 : 0.0;
|
|
806
|
-
this.meshVisibilityStorageAttr.needsUpdate = true;
|
|
811
|
+
if ( ! this._patchTLASLeafVisibility( meshIndex, visible ) ) return;
|
|
812
|
+
if ( this.bvhStorageAttr ) this.bvhStorageAttr.needsUpdate = true;
|
|
807
813
|
|
|
808
814
|
}
|
|
809
815
|
|
|
810
816
|
/**
|
|
811
|
-
* Recompute world-visibility for all meshes and
|
|
817
|
+
* Recompute world-visibility for all meshes and patch TLAS leaves in place.
|
|
812
818
|
* Call this when group visibility changes at runtime.
|
|
813
819
|
*/
|
|
814
820
|
updateAllMeshVisibility() {
|
|
815
821
|
|
|
816
|
-
if ( ! this._meshRefs || ! this.
|
|
822
|
+
if ( ! this._meshRefs || ! this._instanceTable ) return;
|
|
817
823
|
|
|
818
|
-
const data = this.meshVisibilityStorageAttr.array;
|
|
819
824
|
for ( let i = 0; i < this._meshRefs.length; i ++ ) {
|
|
820
825
|
|
|
821
|
-
|
|
826
|
+
this._patchTLASLeafVisibility( i, this._isWorldVisible( this._meshRefs[ i ] ) );
|
|
822
827
|
|
|
823
828
|
}
|
|
824
829
|
|
|
825
|
-
this.
|
|
830
|
+
if ( this.bvhStorageAttr ) this.bvhStorageAttr.needsUpdate = true;
|
|
831
|
+
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Patch a single TLAS leaf's visibility flag in the combined BVH buffer.
|
|
836
|
+
* Returns true if the patch was applied.
|
|
837
|
+
* @private
|
|
838
|
+
*/
|
|
839
|
+
_patchTLASLeafVisibility( meshIndex, visible ) {
|
|
840
|
+
|
|
841
|
+
const entry = this._instanceTable?.entries?.[ meshIndex ];
|
|
842
|
+
if ( ! entry || entry.tlasLeafIndex < 0 || ! this.bvhStorageAttr ) return false;
|
|
843
|
+
|
|
844
|
+
entry.visible = visible;
|
|
845
|
+
this.bvhStorageAttr.array[ entry.tlasLeafIndex * 16 + 2 ] = visible ? 1.0 : 0.0;
|
|
846
|
+
return true;
|
|
826
847
|
|
|
827
848
|
}
|
|
828
849
|
|
|
@@ -1135,9 +1156,6 @@ export class PathTracer extends RenderStage {
|
|
|
1135
1156
|
// Update frame uniform
|
|
1136
1157
|
this.frame.value = frameValue;
|
|
1137
1158
|
|
|
1138
|
-
// Force-compile compute nodes on first frame
|
|
1139
|
-
this.shaderBuilder.forceCompile( this.renderer );
|
|
1140
|
-
|
|
1141
1159
|
// Set dispatch region — tile-only dispatch for tiled mode, full-screen otherwise
|
|
1142
1160
|
if ( tileInfo.tileIndex >= 0 && tileInfo.tileBounds ) {
|
|
1143
1161
|
|
|
@@ -1496,18 +1514,43 @@ export class PathTracer extends RenderStage {
|
|
|
1496
1514
|
|
|
1497
1515
|
}
|
|
1498
1516
|
|
|
1499
|
-
|
|
1517
|
+
/**
|
|
1518
|
+
* Rebuild the packed light buffer from cached lightBVH + emissive data.
|
|
1519
|
+
* Layout: [ lightBVH (LBVH_STRIDE vec4s per node) | emissive (EMISSIVE_STRIDE vec4s per entry) ].
|
|
1520
|
+
* Also updates `emissiveVec4Offset` uniform (in vec4 elements).
|
|
1521
|
+
* @private
|
|
1522
|
+
*/
|
|
1523
|
+
_rebuildLightBuffer() {
|
|
1500
1524
|
|
|
1501
|
-
|
|
1525
|
+
const LBVH_STRIDE = 4; // vec4s per LBVH node — must match LightBVHSampling.js
|
|
1526
|
+
const lbvh = this._lbvhDataCache;
|
|
1527
|
+
const emis = this._emissiveDataCache;
|
|
1528
|
+
const lbvhLen = lbvh ? lbvh.length : 0;
|
|
1529
|
+
const emisLen = emis ? emis.length : 0;
|
|
1502
1530
|
|
|
1503
|
-
|
|
1531
|
+
// Ensure at least a minimal non-empty buffer so GPU allocation remains valid.
|
|
1532
|
+
const totalLen = Math.max( lbvhLen + emisLen, 4 );
|
|
1533
|
+
const combined = new Float32Array( totalLen );
|
|
1534
|
+
if ( lbvh ) combined.set( lbvh, 0 );
|
|
1535
|
+
if ( emis ) combined.set( emis, lbvhLen );
|
|
1504
1536
|
|
|
1505
|
-
this.
|
|
1506
|
-
this.
|
|
1507
|
-
this.
|
|
1537
|
+
this.lightStorageAttr = new StorageInstancedBufferAttribute( combined, 4 );
|
|
1538
|
+
this.lightStorageNode.value = this.lightStorageAttr;
|
|
1539
|
+
this.lightStorageNode.bufferCount = combined.length / 4;
|
|
1540
|
+
|
|
1541
|
+
// Offset (in vec4 elements) where emissive data starts.
|
|
1542
|
+
this.emissiveVec4Offset.value = ( this.lightBVHNodeCount.value || 0 ) * LBVH_STRIDE;
|
|
1543
|
+
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
setEmissiveTriangleData( emissiveData, count, totalPower = 0 ) {
|
|
1547
|
+
|
|
1548
|
+
if ( ! emissiveData ) return;
|
|
1508
1549
|
|
|
1550
|
+
this._emissiveDataCache = emissiveData;
|
|
1509
1551
|
this.emissiveTriangleCount.value = count;
|
|
1510
1552
|
this.emissiveTotalPower.value = totalPower;
|
|
1553
|
+
this._rebuildLightBuffer();
|
|
1511
1554
|
console.log( `PathTracer: ${count} emissive triangles, totalPower=${totalPower.toFixed( 4 )} (storage buffer)` );
|
|
1512
1555
|
|
|
1513
1556
|
}
|
|
@@ -1516,11 +1559,9 @@ export class PathTracer extends RenderStage {
|
|
|
1516
1559
|
|
|
1517
1560
|
if ( ! nodeData ) return;
|
|
1518
1561
|
|
|
1519
|
-
|
|
1520
|
-
this.lightBVHStorageAttr = new StorageInstancedBufferAttribute( nodeData, 4 );
|
|
1521
|
-
this.lightBVHStorageNode.value = this.lightBVHStorageAttr;
|
|
1522
|
-
this.lightBVHStorageNode.bufferCount = vec4Count;
|
|
1562
|
+
this._lbvhDataCache = nodeData;
|
|
1523
1563
|
this.lightBVHNodeCount.value = nodeCount;
|
|
1564
|
+
this._rebuildLightBuffer();
|
|
1524
1565
|
console.log( `PathTracer: Light BVH ${nodeCount} nodes` );
|
|
1525
1566
|
|
|
1526
1567
|
}
|
|
@@ -1616,6 +1657,7 @@ export class PathTracer extends RenderStage {
|
|
|
1616
1657
|
this.materialData?.dispose();
|
|
1617
1658
|
this.environment?.dispose();
|
|
1618
1659
|
this.shaderBuilder?.dispose();
|
|
1660
|
+
this.uniforms?.dispose();
|
|
1619
1661
|
|
|
1620
1662
|
// Dispose storage textures
|
|
1621
1663
|
this.storageTextures?.dispose();
|
package/src/Stages/SSRC.js
CHANGED
|
@@ -175,10 +175,10 @@ export class SSRC extends RenderStage {
|
|
|
175
175
|
this._dispatchX = Math.ceil( width / 8 );
|
|
176
176
|
this._dispatchY = Math.ceil( height / 8 );
|
|
177
177
|
|
|
178
|
-
const
|
|
179
|
-
if ( this._pass1NodeA ) this._pass1NodeA.
|
|
180
|
-
if ( this._pass1NodeB ) this._pass1NodeB.
|
|
181
|
-
if ( this._pass2Node ) this._pass2Node.
|
|
178
|
+
const dispatchSize = [ this._dispatchX, this._dispatchY, 1 ];
|
|
179
|
+
if ( this._pass1NodeA ) this._pass1NodeA.dispatchSize = dispatchSize;
|
|
180
|
+
if ( this._pass1NodeB ) this._pass1NodeB.dispatchSize = dispatchSize;
|
|
181
|
+
if ( this._pass2Node ) this._pass2Node.dispatchSize = dispatchSize;
|
|
182
182
|
|
|
183
183
|
this._resetCache();
|
|
184
184
|
|
package/src/Stages/Variance.js
CHANGED
|
@@ -360,8 +360,8 @@ export class Variance extends RenderStage {
|
|
|
360
360
|
// Update dispatch dimensions
|
|
361
361
|
this._dispatchX = Math.ceil( width / 8 );
|
|
362
362
|
this._dispatchY = Math.ceil( height / 8 );
|
|
363
|
-
this._computeNodeA.
|
|
364
|
-
this._computeNodeB.
|
|
363
|
+
this._computeNodeA.dispatchSize = [ this._dispatchX, this._dispatchY, 1 ];
|
|
364
|
+
this._computeNodeB.dispatchSize = [ this._dispatchX, this._dispatchY, 1 ];
|
|
365
365
|
|
|
366
366
|
}
|
|
367
367
|
|
package/src/TSL/BVHTraversal.js
CHANGED
|
@@ -43,19 +43,8 @@ const BVH_STRIDE = 4;
|
|
|
43
43
|
const TRI_STRIDE = 8;
|
|
44
44
|
const HUGE_VAL = 1e8;
|
|
45
45
|
|
|
46
|
-
// Per-mesh visibility
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Set the per-mesh visibility storage buffer node.
|
|
51
|
-
* Must be called before the shader graph is constructed (i.e., before setupCompute).
|
|
52
|
-
* @param {StorageNode} buffer - TSL storage node indexed by meshIndex
|
|
53
|
-
*/
|
|
54
|
-
export function setMeshVisibilityBuffer( buffer ) {
|
|
55
|
-
|
|
56
|
-
_meshVisibilityBuffer = buffer;
|
|
57
|
-
|
|
58
|
-
}
|
|
46
|
+
// Per-mesh visibility is now packed into the TLAS BLAS-pointer leaf's slot [2]
|
|
47
|
+
// by TLASBuilder.flatten() — eliminates the dedicated meshVisibility storage buffer.
|
|
59
48
|
|
|
60
49
|
// ================================================================================
|
|
61
50
|
// STACK HELPERS (Native WGSL array via TSL ArrayNode)
|
|
@@ -276,35 +265,17 @@ export const traverseBVH = Fn( ( [
|
|
|
276
265
|
|
|
277
266
|
} ).Else( () => {
|
|
278
267
|
|
|
279
|
-
// BLAS-pointer leaf (marker -2) — push BLAS root
|
|
280
|
-
// nodeData0: [blasRootNodeIndex, meshIndex,
|
|
268
|
+
// BLAS-pointer leaf (marker -2) — push BLAS root onto stack if mesh is visible
|
|
269
|
+
// nodeData0: [blasRootNodeIndex, meshIndex, visibility, -2]
|
|
270
|
+
// Visibility is free-fetched with the leaf — no extra storage read.
|
|
281
271
|
const blasRoot = int( nodeData0.x ).toVar();
|
|
282
272
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
// Per-mesh visibility check — skip entire BLAS if mesh is hidden
|
|
286
|
-
// getDatafromStorageBuffer( buffer, stride=1, sampleIndex=meshIdx, dataOffset=0 )
|
|
287
|
-
const meshIdx = int( nodeData0.y ).toVar();
|
|
288
|
-
const meshVis = getDatafromStorageBuffer( _meshVisibilityBuffer, int( 1 ), meshIdx, int( 0 ) ).x;
|
|
289
|
-
|
|
290
|
-
If( meshVis.greaterThan( 0.5 ).and( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ) ), () => {
|
|
291
|
-
|
|
292
|
-
stack.element( stackPtr ).assign( blasRoot );
|
|
293
|
-
stackPtr.addAssign( 1 );
|
|
294
|
-
|
|
295
|
-
} );
|
|
296
|
-
|
|
297
|
-
} else {
|
|
298
|
-
|
|
299
|
-
// No visibility buffer — push unconditionally (original behavior)
|
|
300
|
-
If( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ), () => {
|
|
301
|
-
|
|
302
|
-
stack.element( stackPtr ).assign( blasRoot );
|
|
303
|
-
stackPtr.addAssign( 1 );
|
|
273
|
+
If( nodeData0.z.greaterThan( 0.5 ).and( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ) ), () => {
|
|
304
274
|
|
|
305
|
-
|
|
275
|
+
stack.element( stackPtr ).assign( blasRoot );
|
|
276
|
+
stackPtr.addAssign( 1 );
|
|
306
277
|
|
|
307
|
-
}
|
|
278
|
+
} );
|
|
308
279
|
|
|
309
280
|
} );
|
|
310
281
|
|
|
@@ -466,35 +437,16 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
466
437
|
|
|
467
438
|
} ).Else( () => {
|
|
468
439
|
|
|
469
|
-
// BLAS-pointer leaf (marker -2) — push BLAS root
|
|
470
|
-
// nodeData0: [blasRootNodeIndex, meshIndex,
|
|
440
|
+
// BLAS-pointer leaf (marker -2) — push BLAS root onto stack if mesh is visible
|
|
441
|
+
// nodeData0: [blasRootNodeIndex, meshIndex, visibility, -2]
|
|
471
442
|
const blasRoot = int( nodeData0.x ).toVar();
|
|
472
443
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
// Per-mesh visibility check — skip entire BLAS if mesh is hidden
|
|
476
|
-
// getDatafromStorageBuffer( buffer, stride=1, sampleIndex=meshIdx, dataOffset=0 )
|
|
477
|
-
const meshIdx = int( nodeData0.y ).toVar();
|
|
478
|
-
const meshVis = getDatafromStorageBuffer( _meshVisibilityBuffer, int( 1 ), meshIdx, int( 0 ) ).x;
|
|
479
|
-
|
|
480
|
-
If( meshVis.greaterThan( 0.5 ).and( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ) ), () => {
|
|
481
|
-
|
|
482
|
-
stack.element( stackPtr ).assign( blasRoot );
|
|
483
|
-
stackPtr.addAssign( 1 );
|
|
484
|
-
|
|
485
|
-
} );
|
|
486
|
-
|
|
487
|
-
} else {
|
|
444
|
+
If( nodeData0.z.greaterThan( 0.5 ).and( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ) ), () => {
|
|
488
445
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
stack.element( stackPtr ).assign( blasRoot );
|
|
493
|
-
stackPtr.addAssign( 1 );
|
|
494
|
-
|
|
495
|
-
} );
|
|
446
|
+
stack.element( stackPtr ).assign( blasRoot );
|
|
447
|
+
stackPtr.addAssign( 1 );
|
|
496
448
|
|
|
497
|
-
}
|
|
449
|
+
} );
|
|
498
450
|
|
|
499
451
|
} );
|
|
500
452
|
|
package/src/TSL/Clearcoat.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
If,
|
|
14
14
|
} from 'three/tsl';
|
|
15
15
|
|
|
16
|
-
import { struct } from './
|
|
16
|
+
import { struct } from './patches.js';
|
|
17
17
|
|
|
18
18
|
import { Ray, HitInfo, RayTracingMaterial, DotProducts } from './Struct.js';
|
|
19
19
|
import { PI, MIN_CLEARCOAT_ROUGHNESS, computeDotProducts } from './Common.js';
|
package/src/TSL/Displacement.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fn, float, vec2, int, If, Loop, abs, normalize, dot, max } from 'three/tsl';
|
|
2
2
|
|
|
3
|
-
import { struct } from './
|
|
3
|
+
import { struct } from './patches.js';
|
|
4
4
|
import { getDatafromStorageBuffer } from './Common.js';
|
|
5
5
|
import { sampleDisplacementMap } from './TextureSampling.js';
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
atan,
|
|
28
28
|
} from 'three/tsl';
|
|
29
29
|
|
|
30
|
-
import { struct } from './
|
|
30
|
+
import { struct } from './patches.js';
|
|
31
31
|
import { MIN_PDF, getDatafromStorageBuffer, powerHeuristic, MATERIAL_SLOTS, MATERIAL_SLOT } from './Common.js';
|
|
32
32
|
import { RandomValue } from './Random.js';
|
|
33
33
|
import { calculateMaterialPDF } from './LightsSampling.js';
|
|
@@ -361,8 +361,10 @@ export const calculateEmissiveLightPdf = Fn( ( [
|
|
|
361
361
|
// ================================================================================
|
|
362
362
|
|
|
363
363
|
// Binary search in CDF for importance-weighted triangle selection
|
|
364
|
-
// CDF values are stored in the .b channel of the emissive buffer
|
|
365
|
-
|
|
364
|
+
// CDF values are stored in the .b channel of the emissive buffer.
|
|
365
|
+
// `emissiveOffset` is the vec4-element offset into the packed light buffer
|
|
366
|
+
// where emissive entries start (0 if using a non-packed buffer).
|
|
367
|
+
const binarySearchCDF = Fn( ( [ emissiveTriangleBuffer, emissiveOffset, emissiveTriangleCount, rand ] ) => {
|
|
366
368
|
|
|
367
369
|
const lo = int( 0 ).toVar();
|
|
368
370
|
const hi = emissiveTriangleCount.sub( 1 ).toVar();
|
|
@@ -370,7 +372,7 @@ const binarySearchCDF = Fn( ( [ emissiveTriangleBuffer, emissiveTriangleCount, r
|
|
|
370
372
|
Loop( lo.lessThan( hi ), () => {
|
|
371
373
|
|
|
372
374
|
const mid = lo.add( hi ).div( 2 ).toVar();
|
|
373
|
-
const cdfVal = emissiveTriangleBuffer.element( mid.mul( EMISSIVE_STRIDE ) ).b;
|
|
375
|
+
const cdfVal = emissiveTriangleBuffer.element( emissiveOffset.add( mid.mul( int( EMISSIVE_STRIDE ) ) ) ).b;
|
|
374
376
|
|
|
375
377
|
If( cdfVal.lessThan( rand ), () => {
|
|
376
378
|
|
|
@@ -388,11 +390,13 @@ const binarySearchCDF = Fn( ( [ emissiveTriangleBuffer, emissiveTriangleCount, r
|
|
|
388
390
|
|
|
389
391
|
} );
|
|
390
392
|
|
|
391
|
-
// Sample from emissive triangle index using CDF importance sampling
|
|
393
|
+
// Sample from emissive triangle index using CDF importance sampling.
|
|
394
|
+
// `emissiveTriangleBuffer` may be the shared packed light buffer; `emissiveVec4Offset`
|
|
395
|
+
// gives the vec4 offset where emissive entries begin.
|
|
392
396
|
export const sampleEmissiveTriangle = Fn( ( [
|
|
393
397
|
hitPoint, surfaceNormal, totalTriangleCount,
|
|
394
398
|
rngState,
|
|
395
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower,
|
|
399
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
396
400
|
triangleBuffer,
|
|
397
401
|
] ) => {
|
|
398
402
|
|
|
@@ -413,12 +417,12 @@ export const sampleEmissiveTriangle = Fn( ( [
|
|
|
413
417
|
|
|
414
418
|
// CDF importance-weighted triangle selection (brighter triangles sampled more)
|
|
415
419
|
const randEmissive = RandomValue( rngState );
|
|
416
|
-
const emissiveIndex = binarySearchCDF( emissiveTriangleBuffer, emissiveTriangleCount, randEmissive ).toVar();
|
|
420
|
+
const emissiveIndex = binarySearchCDF( emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, randEmissive ).toVar();
|
|
417
421
|
|
|
418
|
-
// Fetch emissive triangle data from
|
|
422
|
+
// Fetch emissive triangle data from packed light buffer (2 vec4s per entry)
|
|
419
423
|
// vec4[0] = (triangleIndex, power, cdf, selectionPdf)
|
|
420
424
|
// vec4[1] = (emission.r, emission.g, emission.b, area)
|
|
421
|
-
const baseIdx = emissiveIndex.mul( EMISSIVE_STRIDE );
|
|
425
|
+
const baseIdx = emissiveVec4Offset.add( emissiveIndex.mul( int( EMISSIVE_STRIDE ) ) );
|
|
422
426
|
const emissiveData0 = emissiveTriangleBuffer.element( baseIdx );
|
|
423
427
|
const emissiveData1 = emissiveTriangleBuffer.element( baseIdx.add( 1 ) );
|
|
424
428
|
const triangleIndex = int( emissiveData0.r );
|
|
@@ -534,7 +538,7 @@ export const calculateEmissiveTriangleContributionDebug = Fn( ( [
|
|
|
534
538
|
hitPoint, normal, viewDir, material,
|
|
535
539
|
totalTriangleCount, bounceIndex, rngState,
|
|
536
540
|
emissiveBoost,
|
|
537
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower,
|
|
541
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
538
542
|
triangleBuffer,
|
|
539
543
|
// Callback functions to avoid circular deps
|
|
540
544
|
traceShadowRayFn,
|
|
@@ -557,7 +561,7 @@ export const calculateEmissiveTriangleContributionDebug = Fn( ( [
|
|
|
557
561
|
// Sample emissive triangle (CDF importance-weighted)
|
|
558
562
|
const emissiveSample = EmissiveSample.wrap( sampleEmissiveTriangle(
|
|
559
563
|
hitPoint, normal, totalTriangleCount, rngState,
|
|
560
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower,
|
|
564
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
561
565
|
triangleBuffer,
|
|
562
566
|
) );
|
|
563
567
|
|
|
@@ -619,7 +623,7 @@ export const calculateEmissiveTriangleContribution = Fn( ( [
|
|
|
619
623
|
hitPoint, normal, viewDir, material,
|
|
620
624
|
totalTriangleCount, bounceIndex, rngState,
|
|
621
625
|
emissiveBoost,
|
|
622
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower,
|
|
626
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
623
627
|
triangleBuffer,
|
|
624
628
|
traceShadowRayFn,
|
|
625
629
|
evaluateMaterialResponseFn,
|
|
@@ -630,7 +634,7 @@ export const calculateEmissiveTriangleContribution = Fn( ( [
|
|
|
630
634
|
hitPoint, normal, viewDir, material,
|
|
631
635
|
totalTriangleCount, bounceIndex, rngState,
|
|
632
636
|
emissiveBoost,
|
|
633
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower,
|
|
637
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
634
638
|
triangleBuffer,
|
|
635
639
|
traceShadowRayFn,
|
|
636
640
|
evaluateMaterialResponseFn,
|
package/src/TSL/Environment.js
CHANGED
|
@@ -82,8 +82,7 @@ export const sampleEquirect = Fn( ( [ environment, direction, environmentMatrix,
|
|
|
82
82
|
// Exact implementation from three-gpu-pathtracer
|
|
83
83
|
export const sampleEquirectProbability = Fn( ( [
|
|
84
84
|
environment,
|
|
85
|
-
|
|
86
|
-
envConditionalWeights,
|
|
85
|
+
envCDFBuffer,
|
|
87
86
|
environmentMatrix,
|
|
88
87
|
environmentIntensity,
|
|
89
88
|
envTotalSum,
|
|
@@ -92,15 +91,19 @@ export const sampleEquirectProbability = Fn( ( [
|
|
|
92
91
|
colorOutput
|
|
93
92
|
] ) => {
|
|
94
93
|
|
|
95
|
-
//
|
|
94
|
+
// Packed CDF layout: [marginal (envResolution.y floats) | conditional (envResolution.x * envResolution.y floats)]
|
|
95
|
+
// The conditional offset equals the marginal length, which is envResolution.y.
|
|
96
|
+
const condOffset = int( envResolution.y ).toVar();
|
|
97
|
+
|
|
98
|
+
// Sample marginal CDF for V coordinate (1D, linear interpolation)
|
|
96
99
|
const marginalSize = envResolution.y;
|
|
97
100
|
const mIdx = clamp( r.x.mul( marginalSize.sub( 1.0 ) ), 0.0, marginalSize.sub( 1.0 ) );
|
|
98
101
|
const mI0 = int( floor( mIdx ) );
|
|
99
102
|
const mI1 = min( mI0.add( 1 ), int( marginalSize ).sub( 1 ) );
|
|
100
103
|
const mFrac = fract( mIdx );
|
|
101
|
-
const v = mix(
|
|
104
|
+
const v = mix( envCDFBuffer.element( mI0 ), envCDFBuffer.element( mI1 ), mFrac ).toVar();
|
|
102
105
|
|
|
103
|
-
// Sample conditional CDF for U coordinate (2D
|
|
106
|
+
// Sample conditional CDF for U coordinate (2D grid, bilinear interpolation)
|
|
104
107
|
const condW = envResolution.x;
|
|
105
108
|
const condH = envResolution.y;
|
|
106
109
|
const cxf = clamp( r.y.mul( condW.sub( 1.0 ) ), 0.0, condW.sub( 1.0 ) );
|
|
@@ -112,10 +115,10 @@ export const sampleEquirectProbability = Fn( ( [
|
|
|
112
115
|
const fx = fract( cxf );
|
|
113
116
|
const fy = fract( cyf );
|
|
114
117
|
const condWi = int( condW );
|
|
115
|
-
const v00 =
|
|
116
|
-
const v10 =
|
|
117
|
-
const v01 =
|
|
118
|
-
const v11 =
|
|
118
|
+
const v00 = envCDFBuffer.element( condOffset.add( cy0.mul( condWi ).add( cx0 ) ) );
|
|
119
|
+
const v10 = envCDFBuffer.element( condOffset.add( cy0.mul( condWi ).add( cx1 ) ) );
|
|
120
|
+
const v01 = envCDFBuffer.element( condOffset.add( cy1.mul( condWi ).add( cx0 ) ) );
|
|
121
|
+
const v11 = envCDFBuffer.element( condOffset.add( cy1.mul( condWi ).add( cx1 ) ) );
|
|
119
122
|
const u = mix( mix( v00, v10, fx ), mix( v01, v11, fx ), fy ).toVar();
|
|
120
123
|
|
|
121
124
|
const uv = vec2( u, v ).toVar();
|
|
@@ -53,6 +53,7 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
53
53
|
rngState,
|
|
54
54
|
lbvhBuffer,
|
|
55
55
|
emissiveTriangleBuffer,
|
|
56
|
+
emissiveVec4Offset,
|
|
56
57
|
triangleBuffer,
|
|
57
58
|
] ) => {
|
|
58
59
|
|
|
@@ -185,7 +186,7 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
185
186
|
Loop( { start: int( 0 ), end: emissiveCount }, ( { i } ) => {
|
|
186
187
|
|
|
187
188
|
const entryIdx = emissiveStart.add( i );
|
|
188
|
-
const baseIdx = entryIdx.mul( int( EMISSIVE_STRIDE ) );
|
|
189
|
+
const baseIdx = emissiveVec4Offset.add( entryIdx.mul( int( EMISSIVE_STRIDE ) ) );
|
|
189
190
|
const emData0 = emissiveTriangleBuffer.element( baseIdx );
|
|
190
191
|
const triPower = max( emData0.g, float( 0.0 ) );
|
|
191
192
|
cumPower.addAssign( triPower );
|
|
@@ -204,7 +205,7 @@ export const sampleLightBVHTriangle = Fn( ( [
|
|
|
204
205
|
selectionPdf.mulAssign( selectedPower.div( leafTotalPower ) );
|
|
205
206
|
|
|
206
207
|
// Now sample the selected triangle (same path as flat CDF sampling)
|
|
207
|
-
const baseIdx = selectedEmissiveIndex.mul( int( EMISSIVE_STRIDE ) );
|
|
208
|
+
const baseIdx = emissiveVec4Offset.add( selectedEmissiveIndex.mul( int( EMISSIVE_STRIDE ) ) );
|
|
208
209
|
const emissiveData0 = emissiveTriangleBuffer.element( baseIdx );
|
|
209
210
|
const emissiveData1 = emissiveTriangleBuffer.element( baseIdx.add( int( 1 ) ) );
|
|
210
211
|
|
package/src/TSL/LightsCore.js
CHANGED
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -41,7 +41,7 @@ import { RandomValue } from './Random.js';
|
|
|
41
41
|
import { getTransformedUV } from './TextureSampling.js';
|
|
42
42
|
|
|
43
43
|
// Module-level state for alpha-cutout shadow testing.
|
|
44
|
-
// Set by ShaderBuilder before graph construction
|
|
44
|
+
// Set by ShaderBuilder before graph construction.
|
|
45
45
|
let _shadowAlbedoMaps = null;
|
|
46
46
|
let _enableAlphaShadows = null;
|
|
47
47
|
|
|
@@ -273,7 +273,6 @@ export const calculateIndirectLighting = Fn( ( [
|
|
|
273
273
|
samplingInfo,
|
|
274
274
|
// Environment resources
|
|
275
275
|
envTexture, environmentIntensity, envMatrix,
|
|
276
|
-
envMarginalWeights, envConditionalWeights,
|
|
277
276
|
envTotalSum, envResolution,
|
|
278
277
|
enableEnvironmentLight, useEnvMapIS,
|
|
279
278
|
] ) => {
|
|
@@ -934,7 +934,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
934
934
|
materialBuffer,
|
|
935
935
|
// Environment resources
|
|
936
936
|
envTexture, environmentIntensity, envMatrix,
|
|
937
|
-
|
|
937
|
+
envCDFBuffer,
|
|
938
938
|
envTotalSum, envResolution,
|
|
939
939
|
enableEnvironmentLight,
|
|
940
940
|
] ) => {
|
|
@@ -1203,7 +1203,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
1203
1203
|
|
|
1204
1204
|
// Sample direction + PDF + color from importance-sampled environment
|
|
1205
1205
|
const envSampleResult = sampleEquirectProbability(
|
|
1206
|
-
envTexture,
|
|
1206
|
+
envTexture, envCDFBuffer,
|
|
1207
1207
|
envMatrix, environmentIntensity, envTotalSum, envResolution, envRandom, envColor
|
|
1208
1208
|
).toVar();
|
|
1209
1209
|
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
fract,
|
|
31
31
|
} from 'three/tsl';
|
|
32
32
|
|
|
33
|
-
import { struct } from './
|
|
33
|
+
import { struct } from './patches.js';
|
|
34
34
|
import { Ray, RayTracingMaterial, RenderState, HitInfo, DotProducts, DirectionSample } from './Struct.js';
|
|
35
35
|
import { PI, EPSILON, MIN_ROUGHNESS, MIN_CLEARCOAT_ROUGHNESS, computeDotProducts } from './Common.js';
|
|
36
36
|
import { iorToFresnel0, fresnelSchlickFloat } from './Fresnel.js';
|
package/src/TSL/PathTracer.js
CHANGED
|
@@ -137,14 +137,14 @@ export const pathTracerMain = ( params ) => {
|
|
|
137
137
|
pointLightsBuffer, numPointLights,
|
|
138
138
|
spotLightsBuffer, numSpotLights,
|
|
139
139
|
envTexture, environmentIntensity, envMatrix,
|
|
140
|
-
|
|
140
|
+
envCDFBuffer,
|
|
141
141
|
envTotalSum, envResolution,
|
|
142
142
|
enableEnvironmentLight, useEnvMapIS,
|
|
143
143
|
maxBounceCount, transmissiveBounces,
|
|
144
144
|
showBackground, transparentBackground, backgroundIntensity,
|
|
145
145
|
fireflyThreshold, globalIlluminationIntensity,
|
|
146
146
|
totalTriangleCount, enableEmissiveTriangleSampling,
|
|
147
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower, emissiveBoost,
|
|
147
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower, emissiveBoost,
|
|
148
148
|
lightBVHBuffer, lightBVHNodeCount,
|
|
149
149
|
debugVisScale,
|
|
150
150
|
enableAccumulation, hasPreviousAccumulated,
|
|
@@ -284,14 +284,14 @@ export const pathTracerMain = ( params ) => {
|
|
|
284
284
|
pointLightsBuffer, numPointLights,
|
|
285
285
|
spotLightsBuffer, numSpotLights,
|
|
286
286
|
envTexture, environmentIntensity, envMatrix,
|
|
287
|
-
|
|
287
|
+
envCDFBuffer,
|
|
288
288
|
envTotalSum, envResolution,
|
|
289
289
|
enableEnvironmentLight, useEnvMapIS,
|
|
290
290
|
maxBounceCount, transmissiveBounces,
|
|
291
291
|
backgroundIntensity, showBackground, transparentBackground,
|
|
292
292
|
fireflyThreshold, globalIlluminationIntensity,
|
|
293
293
|
totalTriangleCount, enableEmissiveTriangleSampling,
|
|
294
|
-
emissiveTriangleBuffer, emissiveTriangleCount, emissiveTotalPower, emissiveBoost,
|
|
294
|
+
emissiveTriangleBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower, emissiveBoost,
|
|
295
295
|
lightBVHBuffer, lightBVHNodeCount,
|
|
296
296
|
pixelCoord, resolution, frame,
|
|
297
297
|
) );
|