rayzee 9.3.0 → 10.0.0
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 +3343 -3320
- package/dist/rayzee.umd.js +87 -87
- package/package.json +1 -1
- package/src/EngineDefaults.js +4 -1
- package/src/PathTracerApp.js +21 -0
- package/src/Processor/GeometryExtractor.js +2 -1
- package/src/TSL/BVHTraversal.js +37 -21
- package/src/index.js +1 -0
- package/src/managers/MaterialDataManager.js +34 -3
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -544,7 +544,10 @@ export const TRIANGLE_DATA_LAYOUT = {
|
|
|
544
544
|
};
|
|
545
545
|
|
|
546
546
|
export const TRI_MATERIAL_MASK = 0xffffff;
|
|
547
|
-
export const TRI_SIDE_SHIFT = 24; // 0 front, 1 back, 2 double
|
|
547
|
+
export const TRI_SIDE_SHIFT = 24; // 0 front, 1 back, 2 double, 3 cutaway
|
|
548
|
+
// Front only for every ray, shadow rays too: a cut-away wall or roof. Set by `material.userData.cutaway`
|
|
549
|
+
// at extraction, or `app.setMaterialsSide( indices, MATERIAL_SIDE_CUTAWAY )` on a built scene.
|
|
550
|
+
export const MATERIAL_SIDE_CUTAWAY = 3;
|
|
548
551
|
export const TRI_BLOCKER_SHIFT = 26; // 1 = blocks shadow rays whatever the settings
|
|
549
552
|
export const TRI_BLOCKER_ALPHA_SHIFT = 27; // 1 = blocks them unless alpha-cutout shadows are on
|
|
550
553
|
|
package/src/PathTracerApp.js
CHANGED
|
@@ -3531,6 +3531,27 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
3531
3531
|
|
|
3532
3532
|
}
|
|
3533
3533
|
|
|
3534
|
+
/**
|
|
3535
|
+
* Sets one side on many materials at once — `MATERIAL_SIDE_CUTAWAY` for a cut-away room — in a
|
|
3536
|
+
* single pass over the triangles, where `setMaterialProperty( i, 'side', … )` makes one per material.
|
|
3537
|
+
* @param {Iterable<number>} materialIndices
|
|
3538
|
+
* @param {number} side
|
|
3539
|
+
*/
|
|
3540
|
+
setMaterialsSide( materialIndices, side ) {
|
|
3541
|
+
|
|
3542
|
+
const indices = [ ...materialIndices ];
|
|
3543
|
+
if ( this._sdf?.spilled ) {
|
|
3544
|
+
|
|
3545
|
+
this.ensureSceneResident().then( () => this.setMaterialsSide( indices, side ) );
|
|
3546
|
+
return;
|
|
3547
|
+
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
this.stages.pathTracer?.materialData.setMaterialsSide( indices, side );
|
|
3551
|
+
this.reset();
|
|
3552
|
+
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3534
3555
|
setMaterialProperty( materialIndex, property, value ) {
|
|
3535
3556
|
|
|
3536
3557
|
// These rewrite triangle records, which a spilled scene has to read back first.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BufferAttribute, Vector3, Vector2, Color, Matrix3, Matrix4, FrontSide, BackSide, DoubleSide, RGBAFormat } from "three";
|
|
2
2
|
import {
|
|
3
|
-
TEXTURE_CONSTANTS, TRIANGLE_DATA_LAYOUT, MATERIAL_DEFAULTS, packNormalOct, packTriangleFlags
|
|
3
|
+
TEXTURE_CONSTANTS, TRIANGLE_DATA_LAYOUT, MATERIAL_DEFAULTS, packNormalOct, packTriangleFlags, MATERIAL_SIDE_CUTAWAY
|
|
4
4
|
} from '../EngineDefaults.js';
|
|
5
5
|
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
6
6
|
import { ChunkedRecords, SHARED_MEMORY_AVAILABLE } from './ChunkedRecords.js';
|
|
@@ -1171,6 +1171,7 @@ export class GeometryExtractor {
|
|
|
1171
1171
|
getMaterialSide( material ) {
|
|
1172
1172
|
|
|
1173
1173
|
if ( material.transmission > 0.0 ) return 2;
|
|
1174
|
+
if ( material.userData?.cutaway === true ) return MATERIAL_SIDE_CUTAWAY;
|
|
1174
1175
|
switch ( material.side ) {
|
|
1175
1176
|
|
|
1176
1177
|
case FrontSide: return 0;
|
package/src/TSL/BVHTraversal.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
bool as tslBool,
|
|
25
25
|
} from 'three/tsl';
|
|
26
26
|
|
|
27
|
-
import { BVH_LEAF_MARKERS, BVH_MAX_INDEX, BVH_FOLDED_LEAF_MAX, TRI_MATERIAL_MASK, TRI_SIDE_SHIFT, TLAS_LEAF_IDENTITY } from '../EngineDefaults.js';
|
|
27
|
+
import { BVH_LEAF_MARKERS, BVH_MAX_INDEX, BVH_FOLDED_LEAF_MAX, TRI_MATERIAL_MASK, TRI_SIDE_SHIFT, TLAS_LEAF_IDENTITY, MATERIAL_SIDE_CUTAWAY } from '../EngineDefaults.js';
|
|
28
28
|
import { HitInfo } from './Struct.js';
|
|
29
29
|
import {
|
|
30
30
|
getDatafromStorageBuffer, instanceRows, instanceNormalToWorld, unpackTriangleNormal, triangleRow, shadowFlagsSettle
|
|
@@ -213,12 +213,12 @@ const fastRayAABBDst = wgslFn( `
|
|
|
213
213
|
// MAIN BVH TRAVERSAL
|
|
214
214
|
// ================================================================================
|
|
215
215
|
|
|
216
|
-
// Side from a triangle's flags word (row 4 .z): 0 front, 1 back, 2 double.
|
|
216
|
+
// Side from a triangle's flags word (row 4 .z): 0 front, 1 back, 2 double, 3 cutaway (front, every ray).
|
|
217
217
|
export const triangleSide = ( flags ) => int( flags.shiftRight( uint( TRI_SIDE_SHIFT ) ).bitAnd( uint( 3 ) ) );
|
|
218
218
|
|
|
219
219
|
// Whether a face of this side is seen by a ray; rayDotNormal < 0 is a front hit.
|
|
220
220
|
export const sideAccepts = ( side, rayDotNormal ) => side.equal( int( 2 ) )
|
|
221
|
-
.or( side.equal( int( 0 ) ).and( rayDotNormal.lessThan( - 0.0001 ) ) )
|
|
221
|
+
.or( side.equal( int( 0 ) ).or( side.equal( int( MATERIAL_SIDE_CUTAWAY ) ) ).and( rayDotNormal.lessThan( - 0.0001 ) ) )
|
|
222
222
|
.or( side.equal( int( 1 ) ).and( rayDotNormal.greaterThan( 0.0001 ) ) );
|
|
223
223
|
|
|
224
224
|
// Factory: the boxTests/triTests debug counters are compiled OUT of the hot closest-hit
|
|
@@ -324,7 +324,7 @@ const makeTraverseBVH = ( trackStats ) => Fn( ( [
|
|
|
324
324
|
);
|
|
325
325
|
|
|
326
326
|
// Side culling (inline; per-mesh visibility is at the BLAS-pointer level).
|
|
327
|
-
If( eitherSide.or( sideAccepts( side, rayDotNormal ) ), () => {
|
|
327
|
+
If( eitherSide.and( side.notEqual( int( MATERIAL_SIDE_CUTAWAY ) ) ).or( sideAccepts( side, rayDotNormal ) ), () => {
|
|
328
328
|
|
|
329
329
|
closestHit.didHit.assign( true );
|
|
330
330
|
closestHit.dst.assign( t );
|
|
@@ -579,27 +579,43 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
579
579
|
// Per-mesh visibility is handled at the BLAS-pointer level.
|
|
580
580
|
const uvData2 = triangleRow( triangleBuffer, triIndex, 4 ).toVar();
|
|
581
581
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
586
|
-
closestHit.instanceLeaf.assign( instLeaf );
|
|
582
|
+
// A cutaway face is see-through from behind for shadow rays too.
|
|
583
|
+
const seen = tslBool( true ).toVar();
|
|
584
|
+
If( triangleSide( uvData2.z ).equal( int( MATERIAL_SIDE_CUTAWAY ) ), () => {
|
|
587
585
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
586
|
+
const w = float( 1.0 ).sub( triResult.y ).sub( triResult.z );
|
|
587
|
+
const n = unpackTriangleNormal( triangleRow( triangleBuffer, triIndex, 0 ).w ).mul( w )
|
|
588
|
+
.add( unpackTriangleNormal( triangleRow( triangleBuffer, triIndex, 1 ).w ).mul( triResult.y ) )
|
|
589
|
+
.add( unpackTriangleNormal( triangleRow( triangleBuffer, triIndex, 2 ).w ).mul( triResult.z ) );
|
|
590
|
+
seen.assign( rayDirection.dot( normalize( n ) ).lessThan( - 0.0001 ) );
|
|
593
591
|
|
|
594
|
-
|
|
595
|
-
|
|
592
|
+
} );
|
|
593
|
+
|
|
594
|
+
If( seen, () => {
|
|
595
|
+
|
|
596
|
+
closestHit.didHit.assign( true );
|
|
597
|
+
closestHit.dst.assign( triResult.x );
|
|
598
|
+
closestHit.materialIndex.assign( int( uvData2.z.bitAnd( uint( TRI_MATERIAL_MASK ) ) ) );
|
|
599
|
+
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
600
|
+
closestHit.instanceLeaf.assign( instLeaf );
|
|
596
601
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
602
|
+
// Hit point is cheap (origin + dir*t). Geometric normal is deferred
|
|
603
|
+
// to traceShadowRay — only the transmission branch needs it, so we
|
|
604
|
+
// skip the cross+normalize for the (much more common) opaque-blocker
|
|
605
|
+
// and alpha-cutout paths. Normal stays vec3(0) from struct init.
|
|
606
|
+
closestHit.hitPoint.assign( worldOrigin.add( worldDirection.mul( triResult.x ) ) );
|
|
600
607
|
|
|
601
|
-
|
|
602
|
-
|
|
608
|
+
closestHit.uv.assign( vec2( triResult.y, triResult.z ) );
|
|
609
|
+
closestHit.triangleIndex.assign( triIndex );
|
|
610
|
+
|
|
611
|
+
// An opaque blocker settles the ray. A surface light passes through has to be
|
|
612
|
+
// the nearest one, or the layers behind the first find are never counted.
|
|
613
|
+
If( shadowFlagsSettle( uvData2.z ), () => {
|
|
614
|
+
|
|
615
|
+
blocked.assign( true );
|
|
616
|
+
Break();
|
|
617
|
+
|
|
618
|
+
} );
|
|
603
619
|
|
|
604
620
|
} );
|
|
605
621
|
|
package/src/index.js
CHANGED
|
@@ -672,12 +672,43 @@ export class MaterialDataManager {
|
|
|
672
672
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
|
+
/**
|
|
676
|
+
* One side for several materials in a single pass over the triangles; per-material edits scan
|
|
677
|
+
* every triangle once each.
|
|
678
|
+
* @param {Iterable<number>} materialIndices
|
|
679
|
+
* @param {number} side - 0 front, 1 back, 2 double, MATERIAL_SIDE_CUTAWAY
|
|
680
|
+
*/
|
|
681
|
+
setMaterialsSide( materialIndices, side ) {
|
|
682
|
+
|
|
683
|
+
if ( ! this.materialStorageAttr ) return;
|
|
684
|
+
|
|
685
|
+
const indices = new Set( materialIndices );
|
|
686
|
+
const data = this.materialStorageAttr.array;
|
|
687
|
+
for ( const i of indices ) {
|
|
688
|
+
|
|
689
|
+
data[ i * M.FLOATS_PER_MATERIAL + M.SIDE ] = side;
|
|
690
|
+
( this._hostSet[ i ] ??= new Map() ).set( 'side', side );
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
this._patchTriangleFlagForMaterials( indices, TRI_SIDE_SHIFT, 2, side );
|
|
695
|
+
this.materialStorageAttr.needsUpdate = true;
|
|
696
|
+
this._notifyReset();
|
|
697
|
+
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
_patchTriangleFlagForMaterial( materialIndex, shift, width, value ) {
|
|
701
|
+
|
|
702
|
+
this._patchTriangleFlagForMaterials( new Set( [ materialIndex ] ), shift, width, value );
|
|
703
|
+
|
|
704
|
+
}
|
|
705
|
+
|
|
675
706
|
/**
|
|
676
707
|
* Generic helper: rewrite `width` bits at `shift` in the flags lane of every triangle
|
|
677
|
-
* whose materialIndex
|
|
708
|
+
* whose materialIndex is in `indices`, then fire onTriangleDataChanged.
|
|
678
709
|
* @private
|
|
679
710
|
*/
|
|
680
|
-
|
|
711
|
+
_patchTriangleFlagForMaterials( indices, shift, width, value ) {
|
|
681
712
|
|
|
682
713
|
const triInfo = this.callbacks.getTriangleData?.();
|
|
683
714
|
// Chunked past the ~2 GB array cap; a flat array is the single-chunk case.
|
|
@@ -694,7 +725,7 @@ export class MaterialDataManager {
|
|
|
694
725
|
|
|
695
726
|
const triData = records ? records.chunkFor( i ) : flat;
|
|
696
727
|
const base = records ? records.baseOf( i ) : i * stride;
|
|
697
|
-
if ( ( triData[ base + TRI_FLAGS_OFFSET ] & TRI_MATERIAL_MASK )
|
|
728
|
+
if ( indices.has( triData[ base + TRI_FLAGS_OFFSET ] & TRI_MATERIAL_MASK ) ) {
|
|
698
729
|
|
|
699
730
|
triData[ base + TRI_FLAGS_OFFSET ] = ( ( triData[ base + TRI_FLAGS_OFFSET ] & ~ mask ) | bits ) >>> 0;
|
|
700
731
|
patched ++;
|