rayzee 5.0.2 → 5.1.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/README.md +6 -1
- package/dist/rayzee.es.js +948 -916
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +41 -50
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +2 -2
- package/src/PathTracerApp.js +30 -1
- package/src/Pipeline/RenderStage.js +0 -1
- package/src/Processor/AssetLoader.js +2 -5
- package/src/Processor/EmissiveTriangleBuilder.js +3 -5
- package/src/Processor/EquirectHDRInfo.js +42 -5
- package/src/Processor/GeometryExtractor.js +5 -7
- package/src/Processor/SceneProcessor.js +3 -4
- package/src/Processor/ShaderBuilder.js +4 -0
- package/src/Processor/TLASBuilder.js +1 -1
- package/src/Stages/PathTracer.js +111 -0
- package/src/TSL/BVHTraversal.js +100 -93
- package/src/TSL/Common.js +0 -1
- package/src/TSL/Debugger.js +2 -1
- package/src/TSL/LightsCore.js +1 -1
- package/src/TSL/LightsDirect.js +9 -7
- package/src/TSL/LightsSampling.js +3 -2
- package/src/TSL/PathTracerCore.js +4 -3
- package/src/TSL/Struct.js +0 -1
- package/src/managers/EnvironmentManager.js +1 -1
- package/src/managers/MaterialDataManager.js +1 -2
package/src/TSL/BVHTraversal.js
CHANGED
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
array,
|
|
26
26
|
} from 'three/tsl';
|
|
27
27
|
|
|
28
|
-
import { struct } from './structProxy.js';
|
|
29
28
|
import { Ray, HitInfo } from './Struct.js';
|
|
30
29
|
import { getDatafromStorageBuffer, MATERIAL_SLOTS } from './Common.js';
|
|
31
30
|
import { RandomPointInCircle } from './Random.js';
|
|
@@ -34,14 +33,6 @@ import { RandomPointInCircle } from './Random.js';
|
|
|
34
33
|
// STRUCTS
|
|
35
34
|
// ================================================================================
|
|
36
35
|
|
|
37
|
-
// Combined visibility data structure
|
|
38
|
-
export const VisibilityData = struct( {
|
|
39
|
-
visible: 'bool',
|
|
40
|
-
side: 'int',
|
|
41
|
-
transparent: 'bool',
|
|
42
|
-
opacity: 'float'
|
|
43
|
-
} );
|
|
44
|
-
|
|
45
36
|
// ================================================================================
|
|
46
37
|
// CONSTANTS
|
|
47
38
|
// ================================================================================
|
|
@@ -52,6 +43,20 @@ const BVH_STRIDE = 4;
|
|
|
52
43
|
const TRI_STRIDE = 8;
|
|
53
44
|
const HUGE_VAL = 1e8;
|
|
54
45
|
|
|
46
|
+
// Per-mesh visibility buffer (set by ShaderBuilder before graph construction)
|
|
47
|
+
let _meshVisibilityBuffer = null;
|
|
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
|
+
}
|
|
59
|
+
|
|
55
60
|
// ================================================================================
|
|
56
61
|
// STACK HELPERS (Native WGSL array via TSL ArrayNode)
|
|
57
62
|
// ================================================================================
|
|
@@ -127,48 +132,17 @@ const fastRayAABBDst = wgslFn( `
|
|
|
127
132
|
// VISIBILITY FUNCTIONS
|
|
128
133
|
// ================================================================================
|
|
129
134
|
|
|
130
|
-
//
|
|
131
|
-
|
|
135
|
+
// Side culling — 1 buffer read (slot 10 only)
|
|
136
|
+
// Per-mesh visibility handled at BLAS-pointer level; material visibility always 1.
|
|
137
|
+
export const passesSideCulling = Fn( ( [ materialIndex, rayDirection, normal, materialBuffer ] ) => {
|
|
132
138
|
|
|
133
|
-
// Read visibility flag from slot 4
|
|
134
|
-
const visData = getDatafromStorageBuffer( materialBuffer, materialIndex, int( 4 ), int( MATERIAL_SLOTS ) );
|
|
135
|
-
// Read side and transparency data from slot 10
|
|
136
139
|
const sideData = getDatafromStorageBuffer( materialBuffer, materialIndex, int( 10 ), int( MATERIAL_SLOTS ) );
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
} );
|
|
144
|
-
|
|
145
|
-
} );
|
|
146
|
-
|
|
147
|
-
// Fast visibility check using material texture
|
|
148
|
-
export const isTriangleVisible = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
149
|
-
|
|
150
|
-
const visData = getDatafromStorageBuffer( materialBuffer, materialIndex, int( 4 ), int( MATERIAL_SLOTS ) );
|
|
151
|
-
return visData.g.greaterThan( 0.5 );
|
|
152
|
-
|
|
153
|
-
} );
|
|
154
|
-
|
|
155
|
-
// Complete visibility check with side culling
|
|
156
|
-
export const isMaterialVisibleOptimized = wgslFn( `
|
|
157
|
-
fn isMaterialVisibleOptimized( visible: bool, side: i32, rayDirection: vec3f, normal: vec3f ) -> bool {
|
|
158
|
-
if ( !visible ) { return false; }
|
|
159
|
-
let rayDotNormal = dot( rayDirection, normal );
|
|
160
|
-
let doubleSide = side == 2;
|
|
161
|
-
let frontSide = side == 0 && rayDotNormal < -0.0001f;
|
|
162
|
-
let backSide = side == 1 && rayDotNormal > 0.0001f;
|
|
163
|
-
return doubleSide || frontSide || backSide;
|
|
164
|
-
}
|
|
165
|
-
` );
|
|
166
|
-
|
|
167
|
-
// Single visibility check with combined data fetch
|
|
168
|
-
export const isMaterialVisible = Fn( ( [ materialIndex, rayDirection, normal, materialBuffer ] ) => {
|
|
169
|
-
|
|
170
|
-
const vis = VisibilityData.wrap( getVisibilityData( materialIndex, materialBuffer ) );
|
|
171
|
-
return isMaterialVisibleOptimized( { visible: vis.visible, side: vis.side, rayDirection, normal } );
|
|
140
|
+
const side = int( sideData.g );
|
|
141
|
+
const rayDotNormal = rayDirection.dot( normal );
|
|
142
|
+
const doubleSide = side.equal( int( 2 ) );
|
|
143
|
+
const frontSide = side.equal( int( 0 ) ).and( rayDotNormal.lessThan( - 0.0001 ) );
|
|
144
|
+
const backSide = side.equal( int( 1 ) ).and( rayDotNormal.greaterThan( 0.0001 ) );
|
|
145
|
+
return doubleSide.or( frontSide ).or( backSide );
|
|
172
146
|
|
|
173
147
|
} );
|
|
174
148
|
|
|
@@ -269,28 +243,23 @@ export const traverseBVH = Fn( ( [
|
|
|
269
243
|
|
|
270
244
|
const matIdx = int( uvData2.z );
|
|
271
245
|
|
|
272
|
-
//
|
|
273
|
-
|
|
246
|
+
// Interpolate normal
|
|
247
|
+
const w = float( 1.0 ).sub( u ).sub( v );
|
|
248
|
+
const normal = normalize( nA.mul( w ).add( nB.mul( u ) ).add( nC.mul( v ) ) ).toVar();
|
|
274
249
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const normal = normalize( nA.mul( w ).add( nB.mul( u ) ).add( nC.mul( v ) ) ).toVar();
|
|
250
|
+
// Side culling check (per-mesh visibility handled at BLAS-pointer level)
|
|
251
|
+
If( passesSideCulling( matIdx, rayDirection, normal, materialBuffer ), () => {
|
|
278
252
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
closestHit.normal.assign( normal );
|
|
285
|
-
closestHit.materialIndex.assign( matIdx );
|
|
286
|
-
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
287
|
-
|
|
288
|
-
// Defer hitPoint + UV computation to post-traversal
|
|
289
|
-
closestTriIdx.assign( triIndex );
|
|
290
|
-
closestU.assign( u );
|
|
291
|
-
closestV.assign( v );
|
|
253
|
+
closestHit.didHit.assign( true );
|
|
254
|
+
closestHit.dst.assign( t );
|
|
255
|
+
closestHit.normal.assign( normal );
|
|
256
|
+
closestHit.materialIndex.assign( matIdx );
|
|
257
|
+
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
292
258
|
|
|
293
|
-
|
|
259
|
+
// Defer hitPoint + UV computation to post-traversal
|
|
260
|
+
closestTriIdx.assign( triIndex );
|
|
261
|
+
closestU.assign( u );
|
|
262
|
+
closestV.assign( v );
|
|
294
263
|
|
|
295
264
|
} );
|
|
296
265
|
|
|
@@ -299,7 +268,7 @@ export const traverseBVH = Fn( ( [
|
|
|
299
268
|
} );
|
|
300
269
|
|
|
301
270
|
// If we found a very close hit, we can terminate early
|
|
302
|
-
If( closestHit.didHit.and( closestHit.dst.lessThan(
|
|
271
|
+
If( closestHit.didHit.and( closestHit.dst.lessThan( 1e-6 ) ), () => {
|
|
303
272
|
|
|
304
273
|
Break();
|
|
305
274
|
|
|
@@ -308,13 +277,34 @@ export const traverseBVH = Fn( ( [
|
|
|
308
277
|
} ).Else( () => {
|
|
309
278
|
|
|
310
279
|
// BLAS-pointer leaf (marker -2) — push BLAS root node onto stack
|
|
280
|
+
// nodeData0: [blasRootNodeIndex, meshIndex, 0, -2]
|
|
311
281
|
const blasRoot = int( nodeData0.x ).toVar();
|
|
312
|
-
If( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ), () => {
|
|
313
282
|
|
|
314
|
-
|
|
315
|
-
stackPtr.addAssign( 1 );
|
|
283
|
+
if ( _meshVisibilityBuffer ) {
|
|
316
284
|
|
|
317
|
-
|
|
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 );
|
|
304
|
+
|
|
305
|
+
} );
|
|
306
|
+
|
|
307
|
+
}
|
|
318
308
|
|
|
319
309
|
} );
|
|
320
310
|
|
|
@@ -390,7 +380,7 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
390
380
|
ray,
|
|
391
381
|
bvhBuffer,
|
|
392
382
|
triangleBuffer,
|
|
393
|
-
|
|
383
|
+
_materialBuffer, // eslint-disable-line no-unused-vars -- kept for call-site compatibility
|
|
394
384
|
maxShadowDist,
|
|
395
385
|
] ) => {
|
|
396
386
|
|
|
@@ -448,25 +438,21 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
448
438
|
|
|
449
439
|
If( triResult.w.greaterThan( 0.5 ), () => {
|
|
450
440
|
|
|
441
|
+
// Per-mesh visibility handled at BLAS-pointer level — accept any hit
|
|
451
442
|
const uvData2 = getDatafromStorageBuffer( triangleBuffer, triIndex, int( 7 ), int( TRI_STRIDE ) );
|
|
452
|
-
const matIdx = int( uvData2.z );
|
|
453
|
-
|
|
454
|
-
If( isTriangleVisible( matIdx, materialBuffer ), () => {
|
|
455
|
-
|
|
456
|
-
closestHit.didHit.assign( true );
|
|
457
|
-
closestHit.dst.assign( triResult.x );
|
|
458
|
-
closestHit.materialIndex.assign( matIdx );
|
|
459
|
-
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
460
443
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
444
|
+
closestHit.didHit.assign( true );
|
|
445
|
+
closestHit.dst.assign( triResult.x );
|
|
446
|
+
closestHit.materialIndex.assign( int( uvData2.z ) );
|
|
447
|
+
closestHit.meshIndex.assign( int( uvData2.w ) );
|
|
465
448
|
|
|
466
|
-
|
|
467
|
-
|
|
449
|
+
// Compute hit point and geometric normal -- required for transmissive
|
|
450
|
+
// Fresnel in traceShadowRay (cosThetaI needs a real normal, not vec3(0))
|
|
451
|
+
closestHit.hitPoint.assign( ray.origin.add( ray.direction.mul( triResult.x ) ) );
|
|
452
|
+
closestHit.normal.assign( normalize( cross( pB.sub( pA ), pC.sub( pA ) ) ) );
|
|
468
453
|
|
|
469
|
-
|
|
454
|
+
// Shadow ray only needs any hit — skip remaining triangles in leaf
|
|
455
|
+
Break();
|
|
470
456
|
|
|
471
457
|
} );
|
|
472
458
|
|
|
@@ -475,13 +461,34 @@ export const traverseBVHShadow = Fn( ( [
|
|
|
475
461
|
} ).Else( () => {
|
|
476
462
|
|
|
477
463
|
// BLAS-pointer leaf (marker -2) — push BLAS root node onto stack
|
|
464
|
+
// nodeData0: [blasRootNodeIndex, meshIndex, 0, -2]
|
|
478
465
|
const blasRoot = int( nodeData0.x ).toVar();
|
|
479
|
-
If( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ), () => {
|
|
480
466
|
|
|
481
|
-
|
|
482
|
-
stackPtr.addAssign( 1 );
|
|
467
|
+
if ( _meshVisibilityBuffer ) {
|
|
483
468
|
|
|
484
|
-
|
|
469
|
+
// Per-mesh visibility check — skip entire BLAS if mesh is hidden
|
|
470
|
+
// getDatafromStorageBuffer( buffer, stride=1, sampleIndex=meshIdx, dataOffset=0 )
|
|
471
|
+
const meshIdx = int( nodeData0.y ).toVar();
|
|
472
|
+
const meshVis = getDatafromStorageBuffer( _meshVisibilityBuffer, int( 1 ), meshIdx, int( 0 ) ).x;
|
|
473
|
+
|
|
474
|
+
If( meshVis.greaterThan( 0.5 ).and( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ) ), () => {
|
|
475
|
+
|
|
476
|
+
stack.element( stackPtr ).assign( blasRoot );
|
|
477
|
+
stackPtr.addAssign( 1 );
|
|
478
|
+
|
|
479
|
+
} );
|
|
480
|
+
|
|
481
|
+
} else {
|
|
482
|
+
|
|
483
|
+
// No visibility buffer — push unconditionally (original behavior)
|
|
484
|
+
If( stackPtr.lessThan( int( MAX_STACK_DEPTH ) ), () => {
|
|
485
|
+
|
|
486
|
+
stack.element( stackPtr ).assign( blasRoot );
|
|
487
|
+
stackPtr.addAssign( 1 );
|
|
488
|
+
|
|
489
|
+
} );
|
|
490
|
+
|
|
491
|
+
}
|
|
485
492
|
|
|
486
493
|
} );
|
|
487
494
|
|
package/src/TSL/Common.js
CHANGED
|
@@ -353,7 +353,6 @@ export const getMaterial = Fn( ( [ materialIndex, materialBuffer ] ) => {
|
|
|
353
353
|
attenuationColor: data3.rgb,
|
|
354
354
|
attenuationDistance: data3.a,
|
|
355
355
|
dispersion: data4.r,
|
|
356
|
-
visible: data4.g,
|
|
357
356
|
sheen: data4.b,
|
|
358
357
|
sheenRoughness: data4.a,
|
|
359
358
|
sheenColor: data5.rgb,
|
package/src/TSL/Debugger.js
CHANGED
|
@@ -356,7 +356,8 @@ export const TraceDebugMode = Fn( ( [
|
|
|
356
356
|
const bounceDir = cosineWeightedSample( { N: normalA, xi } ).toVar();
|
|
357
357
|
|
|
358
358
|
// Trace secondary ray from the hit point (offset along normal to avoid self-intersection)
|
|
359
|
-
const
|
|
359
|
+
const debugEps = max( float( 1e-4 ), length( hitInfo.hitPoint ).mul( 1e-6 ) );
|
|
360
|
+
const bounceOrigin = hitInfo.hitPoint.add( normalA.mul( debugEps ) ).toVar();
|
|
360
361
|
const bounceRay = Ray( { origin: bounceOrigin, direction: bounceDir } );
|
|
361
362
|
|
|
362
363
|
const bounceHit = HitInfo.wrap( traverseBVH(
|
package/src/TSL/LightsCore.js
CHANGED
|
@@ -257,7 +257,7 @@ export const intersectAreaLight = Fn( ( [ light, rayOrigin, rayDirection ] ) =>
|
|
|
257
257
|
const t = dot( light.position.sub( rayOrigin ), normal ).mul( invDenom ).toVar();
|
|
258
258
|
|
|
259
259
|
// Skip intersections behind the ray
|
|
260
|
-
If( t.greaterThan(
|
|
260
|
+
If( t.greaterThan( 1e-5 ), () => {
|
|
261
261
|
|
|
262
262
|
// Optimized rectangle test using vector rejection
|
|
263
263
|
const hitPoint = rayOrigin.add( rayDirection.mul( t ) );
|
package/src/TSL/LightsDirect.js
CHANGED
|
@@ -142,8 +142,9 @@ export const traceShadowRay = Fn( ( [
|
|
|
142
142
|
} );
|
|
143
143
|
|
|
144
144
|
// Continue ray past transmissive surface
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
const transEps = max( float( 1e-5 ), length( shadowHit.hitPoint ).mul( 1e-6 ) );
|
|
146
|
+
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( transEps ) ) );
|
|
147
|
+
remainingDist.subAssign( shadowHit.dst.add( transEps ) );
|
|
147
148
|
|
|
148
149
|
} ).ElseIf( shadowMaterial.transparent, () => {
|
|
149
150
|
|
|
@@ -158,8 +159,9 @@ export const traceShadowRay = Fn( ( [
|
|
|
158
159
|
} );
|
|
159
160
|
|
|
160
161
|
// Continue ray past transparent surface
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
const alphaEps = max( float( 1e-5 ), length( shadowHit.hitPoint ).mul( 1e-6 ) );
|
|
163
|
+
rayOrigin.assign( shadowHit.hitPoint.add( dir.mul( alphaEps ) ) );
|
|
164
|
+
remainingDist.subAssign( shadowHit.dst.add( alphaEps ) );
|
|
163
165
|
|
|
164
166
|
} ).Else( () => {
|
|
165
167
|
|
|
@@ -257,7 +259,7 @@ export const estimateLightImportance = Fn( ( [ light, hitPoint, normal, material
|
|
|
257
259
|
|
|
258
260
|
If( lightFacing.greaterThan( 0.0 ), () => {
|
|
259
261
|
|
|
260
|
-
const solidAngle = light.area.div( max( distSq,
|
|
262
|
+
const solidAngle = light.area.div( max( distSq, 1e-4 ) );
|
|
261
263
|
const power = light.intensity.mul( dot( light.color, REC709_LUMINANCE_COEFFICIENTS ) ).mul( light.area );
|
|
262
264
|
|
|
263
265
|
// Material-aware weighting
|
|
@@ -659,7 +661,7 @@ export const calculatePointLightContribution = Fn( ( [
|
|
|
659
661
|
const rayOffset = calculateRayOffset( hitPoint, normal, material );
|
|
660
662
|
const rayOrigin = hitPoint.add( rayOffset );
|
|
661
663
|
|
|
662
|
-
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.
|
|
664
|
+
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.mul( 0.999 ), rngState );
|
|
663
665
|
|
|
664
666
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
665
667
|
|
|
@@ -711,7 +713,7 @@ export const calculateSpotLightContribution = Fn( ( [
|
|
|
711
713
|
const rayOffset = calculateRayOffset( hitPoint, normal, material );
|
|
712
714
|
const rayOrigin = hitPoint.add( rayOffset );
|
|
713
715
|
|
|
714
|
-
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.
|
|
716
|
+
const visibility = traceShadowRayFn( rayOrigin, lightDir, distance.mul( 0.999 ), rngState );
|
|
715
717
|
|
|
716
718
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
717
719
|
|
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
calculatePointLightImportance,
|
|
72
72
|
calculateSpotLightImportance,
|
|
73
73
|
traceShadowRay,
|
|
74
|
+
calculateRayOffset,
|
|
74
75
|
} from './LightsDirect.js';
|
|
75
76
|
|
|
76
77
|
import { traverseBVHShadow } from './BVHTraversal.js';
|
|
@@ -940,7 +941,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
940
941
|
] ) => {
|
|
941
942
|
|
|
942
943
|
const totalContribution = vec3( 0.0 ).toVar();
|
|
943
|
-
const rayOrigin = hitPoint.add(
|
|
944
|
+
const rayOrigin = hitPoint.add( calculateRayOffset( hitPoint, hitNormal, material ) ).toVar();
|
|
944
945
|
|
|
945
946
|
// Early exit for highly emissive surfaces
|
|
946
947
|
If( material.emissiveIntensity.lessThanEqual( 10.0 ), () => {
|
|
@@ -1041,7 +1042,7 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
1041
1042
|
|
|
1042
1043
|
If( NoL.greaterThan( 0.0 ).and( lightImportance.mul( NoL ).greaterThan( importanceThreshold ) ).and( isDirectionValid( { direction: lightSample.direction, surfaceNormal: hitNormal } ) ), () => {
|
|
1043
1044
|
|
|
1044
|
-
const shadowDistance = min( lightSample.distance.
|
|
1045
|
+
const shadowDistance = min( lightSample.distance.mul( 0.999 ), float( 1000.0 ) ).toVar();
|
|
1045
1046
|
const visibility = traceShadowRay(
|
|
1046
1047
|
rayOrigin, lightSample.direction, shadowDistance, rngState,
|
|
1047
1048
|
traverseBVHShadow,
|
|
@@ -880,7 +880,8 @@ export const Trace = Fn( ( [
|
|
|
880
880
|
// For transmission: offset along the old ray direction to push through the surface
|
|
881
881
|
const reflectOffsetDir = select( interaction.entering, N, N.negate() );
|
|
882
882
|
const offsetDir = select( interaction.didReflect, reflectOffsetDir, rayDirection );
|
|
883
|
-
|
|
883
|
+
const bounceEps = max( float( 1e-4 ), length( hitInfo.hitPoint ).mul( 1e-6 ) );
|
|
884
|
+
rayOrigin.assign( hitInfo.hitPoint.add( offsetDir.mul( bounceEps ) ) );
|
|
884
885
|
rayDirection.assign( interaction.direction );
|
|
885
886
|
|
|
886
887
|
stateIsPrimaryRay.assign( tslBool( false ) );
|
|
@@ -1054,7 +1055,7 @@ export const Trace = Fn( ( [
|
|
|
1054
1055
|
|
|
1055
1056
|
const rayOffset = calculateRayOffset( hitInfo.hitPoint, N, material );
|
|
1056
1057
|
const rayOrigin = hitInfo.hitPoint.add( rayOffset );
|
|
1057
|
-
const shadowDist = emissiveSample.distance.
|
|
1058
|
+
const shadowDist = emissiveSample.distance.mul( 0.999 );
|
|
1058
1059
|
const visibility = traceShadowRayWrapped( rayOrigin, emissiveSample.direction, shadowDist, rngState );
|
|
1059
1060
|
|
|
1060
1061
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
@@ -1137,7 +1138,7 @@ export const Trace = Fn( ( [
|
|
|
1137
1138
|
throughput.mulAssign( indirectResult.throughput );
|
|
1138
1139
|
|
|
1139
1140
|
// Prepare for next bounce
|
|
1140
|
-
rayOrigin.assign( hitInfo.hitPoint.add(
|
|
1141
|
+
rayOrigin.assign( hitInfo.hitPoint.add( calculateRayOffset( hitInfo.hitPoint, N, material ) ) );
|
|
1141
1142
|
rayDirection.assign( indirectResult.direction );
|
|
1142
1143
|
prevBouncePdf.assign( indirectResult.combinedPdf );
|
|
1143
1144
|
|
package/src/TSL/Struct.js
CHANGED
|
@@ -312,7 +312,7 @@ export class EnvironmentManager {
|
|
|
312
312
|
const startTime = performance.now();
|
|
313
313
|
const textureForCDF = this.scene.environment;
|
|
314
314
|
|
|
315
|
-
if ( ! textureForCDF.image
|
|
315
|
+
if ( ! textureForCDF.image ) {
|
|
316
316
|
|
|
317
317
|
this._updateCDFStorageBuffers();
|
|
318
318
|
this.uniforms.set( 'envTotalSum', 0.0 );
|
|
@@ -229,7 +229,6 @@ export class MaterialDataManager {
|
|
|
229
229
|
break;
|
|
230
230
|
case 'attenuationDistance': data[ stride + 15 ] = value; break;
|
|
231
231
|
case 'dispersion': data[ stride + 16 ] = value; break;
|
|
232
|
-
case 'visible': data[ stride + 17 ] = value; break;
|
|
233
232
|
case 'sheen': data[ stride + 18 ] = value; break;
|
|
234
233
|
case 'sheenRoughness': data[ stride + 19 ] = value; break;
|
|
235
234
|
case 'sheenColor':
|
|
@@ -378,7 +377,7 @@ export class MaterialDataManager {
|
|
|
378
377
|
|
|
379
378
|
data[ stride + 15 ] = materialData.attenuationDistance ?? Infinity;
|
|
380
379
|
data[ stride + 16 ] = materialData.dispersion ?? 0;
|
|
381
|
-
data[ stride + 17 ] =
|
|
380
|
+
data[ stride + 17 ] = 1; // Reserved slot (per-mesh visibility handled at BLAS-pointer level)
|
|
382
381
|
data[ stride + 18 ] = materialData.sheen ?? 0;
|
|
383
382
|
data[ stride + 19 ] = materialData.sheenRoughness ?? 1;
|
|
384
383
|
|