rayzee 7.17.0 → 7.18.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/README.md +1 -1
- package/dist/assets/BVHSubtreeWorker-D7KMbrQ-.js +2 -0
- package/dist/assets/BVHSubtreeWorker-D7KMbrQ-.js.map +1 -0
- package/dist/assets/BVHWorker-DOaGn6uN.js +2 -0
- package/dist/assets/BVHWorker-DOaGn6uN.js.map +1 -0
- package/dist/rayzee.es.js +2773 -2615
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +48 -48
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +7 -6
- package/src/Passes/OIDNDenoiser.js +17 -14
- package/src/PathTracerApp.js +32 -12
- package/src/Processor/BVHBuilder.js +11 -7
- package/src/Processor/BuildTimer.js +20 -6
- package/src/Processor/EmissiveTriangleBuilder.js +11 -7
- package/src/Processor/GeometryExtractor.js +11 -5
- package/src/Processor/KernelManager.js +48 -1
- package/src/Processor/PackedRayBuffer.js +20 -12
- package/src/Processor/ParallelBVHBuilder.js +9 -6
- package/src/Processor/QueueManager.js +6 -8
- package/src/Processor/SceneProcessor.js +47 -21
- package/src/Processor/ShaderBuilder.js +4 -1
- package/src/Processor/StorageTexturePool.js +4 -1
- package/src/Processor/Workers/BVHWorker.js +12 -6
- package/src/RenderSettings.js +1 -1
- package/src/Stages/PathTracer.js +15 -4
- package/src/Stages/PathTracerStage.js +17 -14
- package/src/TSL/FinalWriteKernel.js +11 -6
- package/src/TSL/ShadeKernel.js +46 -24
- package/src/TSL/TextureSampling.js +12 -2
- package/src/index.js +3 -0
- package/src/managers/EnvironmentManager.js +12 -8
- package/src/managers/MaterialDataManager.js +12 -9
- package/src/managers/UniformManager.js +1 -1
- package/src/utils/Logger.js +291 -0
- package/dist/assets/BVHSubtreeWorker-sNzvxn66.js +0 -2
- package/dist/assets/BVHSubtreeWorker-sNzvxn66.js.map +0 -1
- package/dist/assets/BVHWorker-CiVdFrwe.js +0 -2
- package/dist/assets/BVHWorker-CiVdFrwe.js.map +0 -1
|
@@ -25,6 +25,9 @@ import { LightSerializer } from '../Processor/LightSerializer';
|
|
|
25
25
|
// Constants
|
|
26
26
|
import { ENGINE_DEFAULTS as DEFAULT_STATE } from '../EngineDefaults.js';
|
|
27
27
|
import { getAssetConfig } from '../AssetConfig.js';
|
|
28
|
+
import { createLogger, fmt } from '../utils/Logger.js';
|
|
29
|
+
|
|
30
|
+
const log = createLogger( 'pathtracer' );
|
|
28
31
|
|
|
29
32
|
/**
|
|
30
33
|
* Data layout constants
|
|
@@ -377,7 +380,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
377
380
|
|
|
378
381
|
this.stbnScalarTexture = configure( tex );
|
|
379
382
|
stbnScalarTextureNode.value = tex;
|
|
380
|
-
|
|
383
|
+
log.debug( `STBN scalar atlas ${fmt.px( tex.image.width, tex.image.height )}` );
|
|
381
384
|
|
|
382
385
|
} );
|
|
383
386
|
|
|
@@ -385,7 +388,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
385
388
|
|
|
386
389
|
this.stbnVec2Texture = configure( tex );
|
|
387
390
|
stbnVec2TextureNode.value = tex;
|
|
388
|
-
|
|
391
|
+
log.debug( `STBN vec2 atlas ${fmt.px( tex.image.width, tex.image.height )}` );
|
|
389
392
|
|
|
390
393
|
} );
|
|
391
394
|
|
|
@@ -548,7 +551,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
548
551
|
|
|
549
552
|
this.directionalLightsData = mockMaterial.uniforms.directionalLights.value;
|
|
550
553
|
|
|
551
|
-
|
|
554
|
+
log.debug( `sun added as directional light · intensity ${scaledSunIntensity.toFixed( 2 )}` );
|
|
552
555
|
|
|
553
556
|
}
|
|
554
557
|
|
|
@@ -716,7 +719,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
716
719
|
|
|
717
720
|
this.triangleCount = triangleCount;
|
|
718
721
|
|
|
719
|
-
|
|
722
|
+
log.debug( `${fmt.n( this.triangleCount )} triangles (storage buffer)` );
|
|
720
723
|
|
|
721
724
|
}
|
|
722
725
|
|
|
@@ -744,7 +747,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
744
747
|
}
|
|
745
748
|
|
|
746
749
|
this.bvhNodeCount = Math.floor( vec4Count / BVH_VEC4_PER_NODE );
|
|
747
|
-
|
|
750
|
+
log.debug( `${fmt.n( this.bvhNodeCount )} BVH nodes (storage buffer)` );
|
|
748
751
|
|
|
749
752
|
}
|
|
750
753
|
|
|
@@ -983,14 +986,14 @@ export class PathTracerStage extends RenderStage {
|
|
|
983
986
|
|
|
984
987
|
if ( ! this.triangleStorageNode ) {
|
|
985
988
|
|
|
986
|
-
|
|
989
|
+
log.error( 'triangle data required' );
|
|
987
990
|
return;
|
|
988
991
|
|
|
989
992
|
}
|
|
990
993
|
|
|
991
994
|
if ( ! this.bvhStorageNode ) {
|
|
992
995
|
|
|
993
|
-
|
|
996
|
+
log.error( 'BVH data required' );
|
|
994
997
|
return;
|
|
995
998
|
|
|
996
999
|
}
|
|
@@ -1348,7 +1351,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1348
1351
|
this.emissiveTriangleCount.value = count;
|
|
1349
1352
|
this.emissiveTotalPower.value = totalPower;
|
|
1350
1353
|
this._rebuildLightBuffer();
|
|
1351
|
-
|
|
1354
|
+
log.debug( `${fmt.n( count )} emissive triangles · totalPower ${totalPower.toFixed( 4 )} (storage buffer)` );
|
|
1352
1355
|
|
|
1353
1356
|
}
|
|
1354
1357
|
|
|
@@ -1359,7 +1362,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1359
1362
|
this._lbvhDataCache = nodeData;
|
|
1360
1363
|
this.lightBVHNodeCount.value = nodeCount;
|
|
1361
1364
|
this._rebuildLightBuffer();
|
|
1362
|
-
|
|
1365
|
+
log.debug( `light BVH ${fmt.n( nodeCount )} nodes` );
|
|
1363
1366
|
|
|
1364
1367
|
}
|
|
1365
1368
|
|
|
@@ -1402,7 +1405,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1402
1405
|
|
|
1403
1406
|
try {
|
|
1404
1407
|
|
|
1405
|
-
|
|
1408
|
+
log.debug( 'material rebuild started' );
|
|
1406
1409
|
|
|
1407
1410
|
await this.sdfs.rebuildMaterials( scene );
|
|
1408
1411
|
this.updateSceneUniforms();
|
|
@@ -1410,20 +1413,20 @@ export class PathTracerStage extends RenderStage {
|
|
|
1410
1413
|
this.updateLights();
|
|
1411
1414
|
this.reset();
|
|
1412
1415
|
|
|
1413
|
-
|
|
1416
|
+
log.debug( 'material rebuild complete' );
|
|
1414
1417
|
|
|
1415
1418
|
} catch ( error ) {
|
|
1416
1419
|
|
|
1417
|
-
|
|
1420
|
+
log.error( 'material rebuild failed:', error );
|
|
1418
1421
|
|
|
1419
1422
|
try {
|
|
1420
1423
|
|
|
1421
|
-
|
|
1424
|
+
log.warn( 'attempting recovery by resetting the path tracer' );
|
|
1422
1425
|
this.reset();
|
|
1423
1426
|
|
|
1424
1427
|
} catch ( recoveryError ) {
|
|
1425
1428
|
|
|
1426
|
-
|
|
1429
|
+
log.error( 'recovery failed:', recoveryError );
|
|
1427
1430
|
|
|
1428
1431
|
}
|
|
1429
1432
|
|
|
@@ -50,7 +50,8 @@ export function buildFinalWriteKernel( params ) {
|
|
|
50
50
|
// OIDN models (calb_cnrm/high, alb_nrm/balanced); off for fast/ASVGF which want the bump normal.
|
|
51
51
|
cleanAuxNormalEnabled,
|
|
52
52
|
// Tier-1 convergence early-stop: per-pixel Welford luminance second moment + converged-pixel counter.
|
|
53
|
-
counters, m2BufferRW, useAdaptiveSampling, noiseThreshold,
|
|
53
|
+
counters, m2BufferRW, useAdaptiveSampling, noiseThreshold, adaptiveMinSamples,
|
|
54
|
+
|
|
54
55
|
// Tier-2 per-pixel freeze: streakBufferRW = per-pixel freeze-candidate streak (stamped here);
|
|
55
56
|
// frozenMaskRO = dilated frozen mask from buildActivePixels (pass-through gates on it, not streak).
|
|
56
57
|
usePixelFreeze, pixelFreezeThreshold, pixelFreezeStability, streakBufferRW, frozenMaskRO,
|
|
@@ -141,7 +142,7 @@ export function buildFinalWriteKernel( params ) {
|
|
|
141
142
|
// Tier-1 convergence: per-pixel running second moment of LUMINANCE (Welford). luminance() is linear,
|
|
142
143
|
// so luminance(running-mean color) == running-mean luminance == E[L]; m2 tracks E[L²] under the SAME
|
|
143
144
|
// global 1/(frame+1) alpha (NO per-pixel alpha). sampleVar = E[L²]-E[L]²; varOfMean = sampleVar/(N);
|
|
144
|
-
//
|
|
145
|
+
// absSE = SE(mean); a pixel converges once frame>=minSamples AND the √-normalized error < threshold.
|
|
145
146
|
// The m2 write runs every frame (incl. frame 0, where alpha==1 self-inits it → no explicit clear).
|
|
146
147
|
// Sits AFTER the accumulation mix (finalColor is the mean) and BEFORE the visMode-11 mutation.
|
|
147
148
|
If( convOn, () => {
|
|
@@ -158,11 +159,15 @@ export function buildFinalWriteKernel( params ) {
|
|
|
158
159
|
// Combined criterion: bright pixels converge on relErr<threshold; dark/dim pixels (where relErr
|
|
159
160
|
// stays high forever) converge on absSE<absFloor, since their absolute noise is imperceptible.
|
|
160
161
|
const absSE = varOfMean.sqrt().toVar();
|
|
161
|
-
const relErr = absSE.div( meanLum.add( float( 1e-4 ) ) );
|
|
162
|
+
const relErr = absSE.div( meanLum.add( float( 1e-4 ) ) ); // Tier-2 freeze predicate reads this
|
|
163
|
+
|
|
164
|
+
// Cycles-style convergence: normalize the standard error by √luminance for dim pixels (lum<1),
|
|
165
|
+
// by luminance for bright ones. The √ loosens the relative bar in shadows so dark pixels converge
|
|
166
|
+
// on their small absolute noise instead of stalling forever on a pure relative bar.
|
|
167
|
+
const convNorm = select( meanLum.lessThan( float( 1.0 ) ), meanLum.sqrt(), meanLum );
|
|
168
|
+
const converged = absSE.div( convNorm.add( float( 1e-4 ) ) ).lessThan( noiseThreshold );
|
|
162
169
|
|
|
163
|
-
If( frame.greaterThanEqual( uint( adaptiveMinSamples ) ).and(
|
|
164
|
-
relErr.lessThan( noiseThreshold ).or( absSE.lessThan( darkNoiseFloor ) )
|
|
165
|
-
), () => {
|
|
170
|
+
If( frame.greaterThanEqual( uint( adaptiveMinSamples ) ).and( converged ), () => {
|
|
166
171
|
|
|
167
172
|
atomicAdd( counters.element( uint( COUNTER.CONVERGED_COUNT ) ), uint( 1 ) );
|
|
168
173
|
|
package/src/TSL/ShadeKernel.js
CHANGED
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
readRayOrigin, readRayDirection, readRayBounceFlags, readRayThroughput, readRayPdf,
|
|
54
54
|
readMediumStack, writeMediumStack, readMediumSigmaA, writeMediumSigmaA,
|
|
55
55
|
readPathBounces, readSssSteps, readSSSMedium, writeSSSMedium,
|
|
56
|
+
readTransparentCount,
|
|
56
57
|
readHitDistance, readHitBarycentrics, readHitNormal,
|
|
57
58
|
readHitMaterialIndex, readHitTriangleIndex,
|
|
58
59
|
writeRayOriginMeta, writeRayDirFlags, writeRayThroughputPdf, writeRayRadiance,
|
|
@@ -88,6 +89,7 @@ export function buildShadeKernel( params ) {
|
|
|
88
89
|
pointLightsBuffer, numPointLights,
|
|
89
90
|
spotLightsBuffer, numSpotLights,
|
|
90
91
|
maxBounceCount, maxSubsurfaceSteps,
|
|
92
|
+
maxTransparentBounces, // guard on alpha-skip depth; counter in ORIGIN_META.w
|
|
91
93
|
currentBounce, // loop iteration = path length (advances on free bounces); drives RR/firefly/giScale
|
|
92
94
|
transparentBackground, backgroundIntensity, backgroundColor, backgroundBlurriness, backgroundBlurSamples, showBackground,
|
|
93
95
|
globalIlluminationIntensity,
|
|
@@ -204,6 +206,7 @@ export function buildShadeKernel( params ) {
|
|
|
204
206
|
// path length = loop iteration (advances every bounce incl. transmissive/SSS); drives RR/firefly/giScale/MIS. Megakernel: loop counter i.
|
|
205
207
|
const bounceIndex = int( currentBounce ).toVar();
|
|
206
208
|
const sssSteps = readSssSteps( rayBufferRW, rayID ).toVar();
|
|
209
|
+
const transparentCount = readTransparentCount( rayBufferRW, rayID ).toVar();
|
|
207
210
|
|
|
208
211
|
// ── Analytic ground-plane shadow catcher (primary ray only, no geometry) ──
|
|
209
212
|
// A horizontal plane at y = groundCatcherHeight. For a bounce-0 ray that crosses it
|
|
@@ -546,7 +549,7 @@ export function buildShadeKernel( params ) {
|
|
|
546
549
|
// free-bounce continuation: ray stays in the same medium, so medium stack + coeffs persist
|
|
547
550
|
// SSS scatter changes direction → no longer the direct backdrop view.
|
|
548
551
|
flags.assign( flags.bitOr( uint( RAY_FLAG.REDIRECTED ) ) );
|
|
549
|
-
writeRayOriginMeta( rayBufferRW, rayID, scatterPoint, cameraDepth, sssSteps );
|
|
552
|
+
writeRayOriginMeta( rayBufferRW, rayID, scatterPoint, cameraDepth, sssSteps, transparentCount );
|
|
550
553
|
writeRayDirFlags( rayBufferRW, rayID, newDir, flags );
|
|
551
554
|
// Free bounce: preserve prevBouncePdf (megakernel leaves it untouched across SSS scatter,
|
|
552
555
|
// PathTracerCore.js:1272 sets it only after an opaque scatter). Writing 1.0 here spuriously
|
|
@@ -666,6 +669,29 @@ export function buildShadeKernel( params ) {
|
|
|
666
669
|
).greaterThanEqual( float( 0.25 ) ).toVar();
|
|
667
670
|
const featPrefix = featCarry.toVar();
|
|
668
671
|
|
|
672
|
+
// DDFA terminal fallback: a ray dying while still deferring (e.g. a mirror maze) commits its last
|
|
673
|
+
// surface instead of leaving a black guide OIDN would demod-amplify.
|
|
674
|
+
// Plain JS inliner, not an Fn — it closes over albedo/featPrefix/flags .toVar()s.
|
|
675
|
+
const commitDeferredAux = ( normal ) => {
|
|
676
|
+
|
|
677
|
+
If( auxOn.and( flags.bitAnd( uint( RAY_FLAG.AUX_LOCKED ) ).equal( uint( 0 ) ) ), () => {
|
|
678
|
+
|
|
679
|
+
const primaryDepth = gbDecodeNormalDepth( readGBuffer( gBufferRW, pixelIndex ) ).w;
|
|
680
|
+
writeGBuffer( gBufferRW, pixelIndex, normal, primaryDepth, clamp( albedo.mul( featPrefix ), vec3( 0.0 ), vec3( 1.0 ) ) );
|
|
681
|
+
|
|
682
|
+
} );
|
|
683
|
+
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// Deactivate the ray, keeping the radiance already gathered at this vertex.
|
|
687
|
+
const terminatePath = () => {
|
|
688
|
+
|
|
689
|
+
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
690
|
+
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
691
|
+
rngBufferRW.element( rayID ).assign( rngState );
|
|
692
|
+
|
|
693
|
+
};
|
|
694
|
+
|
|
669
695
|
// first-hit MRT data (bounce 0 only): write the primary DEPTH now with the default normal/albedo.
|
|
670
696
|
// The real normal/albedo are committed by the DDFA decision blocks below (which re-pack this depth);
|
|
671
697
|
// they may defer through smooth glass/mirror and commit at the first diffuse-enough surface or the env.
|
|
@@ -874,8 +900,21 @@ export function buildShadeKernel( params ) {
|
|
|
874
900
|
|
|
875
901
|
flags.assign( flags.bitOr( uint( RAY_FLAG.REDIRECTED ) ) );
|
|
876
902
|
|
|
903
|
+
} ).Else( () => {
|
|
904
|
+
|
|
905
|
+
// Alpha passthrough: charge the guard. N is faceforwarded for the aux commit (a ray
|
|
906
|
+
// exiting a back-facing skip would otherwise write an inverted normal).
|
|
907
|
+
transparentCount.addAssign( 1 );
|
|
908
|
+
If( transparentCount.greaterThan( maxTransparentBounces ), () => {
|
|
909
|
+
|
|
910
|
+
commitDeferredAux( select( dot( N, direction.negate() ).lessThan( 0.0 ), N.negate(), N ) );
|
|
911
|
+
terminatePath();
|
|
912
|
+
Return();
|
|
913
|
+
|
|
914
|
+
} );
|
|
915
|
+
|
|
877
916
|
} );
|
|
878
|
-
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth, sssSteps );
|
|
917
|
+
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth, sssSteps, transparentCount );
|
|
879
918
|
writeRayDirFlags( rayBufferRW, rayID, interaction.direction, flags );
|
|
880
919
|
// Free bounce: preserve prevBouncePdf (megakernel keeps the last opaque-scatter pdf across
|
|
881
920
|
// transmission/alpha-skip/SSS-boundary). Writing 1.0 corrupts the next bounce's env/emissive MIS,
|
|
@@ -1230,17 +1269,8 @@ export function buildShadeKernel( params ) {
|
|
|
1230
1269
|
).toVar();
|
|
1231
1270
|
If( rrSurvival.lessThanEqual( 0.0 ), () => {
|
|
1232
1271
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
If( auxOn.and( flags.bitAnd( uint( RAY_FLAG.AUX_LOCKED ) ).equal( uint( 0 ) ) ), () => {
|
|
1236
|
-
|
|
1237
|
-
const primaryDepth = gbDecodeNormalDepth( readGBuffer( gBufferRW, pixelIndex ) ).w;
|
|
1238
|
-
writeGBuffer( gBufferRW, pixelIndex, N, primaryDepth, clamp( albedo.mul( featPrefix ), vec3( 0.0 ), vec3( 1.0 ) ) );
|
|
1239
|
-
|
|
1240
|
-
} );
|
|
1241
|
-
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
1242
|
-
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
1243
|
-
rngBufferRW.element( rayID ).assign( rngState );
|
|
1272
|
+
commitDeferredAux( N );
|
|
1273
|
+
terminatePath();
|
|
1244
1274
|
Return();
|
|
1245
1275
|
|
|
1246
1276
|
} );
|
|
@@ -1249,16 +1279,8 @@ export function buildShadeKernel( params ) {
|
|
|
1249
1279
|
// Terminate on CAMERA depth (opaque scatter count), not path length — glass/SSS free bounces no longer burn the maxBounces budget (gap #4).
|
|
1250
1280
|
If( cameraDepth.greaterThanEqual( maxBounceCount ), () => {
|
|
1251
1281
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const primaryDepth = gbDecodeNormalDepth( readGBuffer( gBufferRW, pixelIndex ) ).w;
|
|
1256
|
-
writeGBuffer( gBufferRW, pixelIndex, N, primaryDepth, clamp( albedo.mul( featPrefix ), vec3( 0.0 ), vec3( 1.0 ) ) );
|
|
1257
|
-
|
|
1258
|
-
} );
|
|
1259
|
-
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
1260
|
-
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
1261
|
-
rngBufferRW.element( rayID ).assign( rngState );
|
|
1282
|
+
commitDeferredAux( N );
|
|
1283
|
+
terminatePath();
|
|
1262
1284
|
Return();
|
|
1263
1285
|
|
|
1264
1286
|
} );
|
|
@@ -1266,7 +1288,7 @@ export function buildShadeKernel( params ) {
|
|
|
1266
1288
|
const newOrigin = hitPoint.add( N.mul( 0.001 ) );
|
|
1267
1289
|
|
|
1268
1290
|
// Opaque scatter: the only bounce that advances camera depth.
|
|
1269
|
-
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth.add( 1 ), sssSteps );
|
|
1291
|
+
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth.add( 1 ), sssSteps, transparentCount );
|
|
1270
1292
|
writeRayDirFlags( rayBufferRW, rayID, bounceDir, flags );
|
|
1271
1293
|
writeRayThroughputPdf( rayBufferRW, rayID, throughput, bouncePdf );
|
|
1272
1294
|
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
@@ -47,10 +47,20 @@ const withBucket = ( buckets, packedIndex, fn ) => {
|
|
|
47
47
|
|
|
48
48
|
const bucket = packedIndex.div( int( _STRIDE ) ).toVar();
|
|
49
49
|
const layer = packedIndex.sub( bucket.mul( int( _STRIDE ) ) ).toVar();
|
|
50
|
-
|
|
50
|
+
// Block bodies, not concise arrows: an If() callback that yields a value makes TSL emit a
|
|
51
|
+
// `return` inside an inline Fn(), which it comments out and warns about on every arm.
|
|
52
|
+
let chain = If( bucket.equal( int( 0 ) ), () => {
|
|
53
|
+
|
|
54
|
+
fn( buckets[ 0 ], layer );
|
|
55
|
+
|
|
56
|
+
} );
|
|
51
57
|
for ( let i = 1; i < buckets.length; i ++ ) {
|
|
52
58
|
|
|
53
|
-
chain = chain.ElseIf( bucket.equal( int( i ) ), () =>
|
|
59
|
+
chain = chain.ElseIf( bucket.equal( int( i ) ), () => {
|
|
60
|
+
|
|
61
|
+
fn( buckets[ i ], layer );
|
|
62
|
+
|
|
63
|
+
} );
|
|
54
64
|
|
|
55
65
|
}
|
|
56
66
|
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,9 @@ export { EngineEvents } from './EngineEvents.js';
|
|
|
17
17
|
// Asset URL / cache namespace overrides (call before constructing PathTracerApp)
|
|
18
18
|
export { configureAssets, getAssetConfig } from './AssetConfig.js';
|
|
19
19
|
|
|
20
|
+
// Logging — leveled/namespaced console output shared with the workers
|
|
21
|
+
export { Logger, createLogger, fmt, LOG_LEVELS } from './utils/Logger.js';
|
|
22
|
+
|
|
20
23
|
// Configuration defaults and presets
|
|
21
24
|
export {
|
|
22
25
|
ENGINE_DEFAULTS,
|
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
import { EquirectHDRInfo } from '../Processor/EquirectHDRInfo.js';
|
|
14
14
|
import { ProceduralSky } from '../Processor/ProceduralSky.js';
|
|
15
15
|
import { SimpleSky } from '../Processor/SimpleSky.js';
|
|
16
|
+
import { createLogger, fmt } from '../utils/Logger.js';
|
|
17
|
+
|
|
18
|
+
const log = createLogger( 'env' );
|
|
16
19
|
import { ENGINE_DEFAULTS as DEFAULT_STATE } from '../EngineDefaults.js';
|
|
17
20
|
|
|
18
21
|
export class EnvironmentManager {
|
|
@@ -231,8 +234,6 @@ export class EnvironmentManager {
|
|
|
231
234
|
this.environmentTexture = envTex;
|
|
232
235
|
this.envTexSize.set( envTex.image.width, envTex.image.height );
|
|
233
236
|
|
|
234
|
-
console.log( `EnvironmentManager: Environment map ${envTex.image.width}x${envTex.image.height}` );
|
|
235
|
-
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
/**
|
|
@@ -317,11 +318,14 @@ export class EnvironmentManager {
|
|
|
317
318
|
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
|
|
321
|
+
log.info( fmt.list( [
|
|
322
|
+
fmt.px( this.envTexSize.x, this.envTexSize.y ),
|
|
323
|
+
`CDF ${fmt.ms( this.cdfBuildTime )}${useWorker ? '' : ' (main thread)'}`,
|
|
324
|
+
] ) );
|
|
321
325
|
|
|
322
326
|
} catch ( error ) {
|
|
323
327
|
|
|
324
|
-
|
|
328
|
+
log.error( 'CDF build failed:', error );
|
|
325
329
|
this.uniforms.set( 'useEnvMapIS', 0 );
|
|
326
330
|
this.uniforms.set( 'envTotalSum', 0.0 );
|
|
327
331
|
this.uniforms.set( 'envCompensationDelta', 0.0 );
|
|
@@ -437,7 +441,7 @@ export class EnvironmentManager {
|
|
|
437
441
|
|
|
438
442
|
} catch ( error ) {
|
|
439
443
|
|
|
440
|
-
|
|
444
|
+
log.error( 'gradient sky generation failed:', error );
|
|
441
445
|
|
|
442
446
|
}
|
|
443
447
|
|
|
@@ -467,7 +471,7 @@ export class EnvironmentManager {
|
|
|
467
471
|
|
|
468
472
|
} catch ( error ) {
|
|
469
473
|
|
|
470
|
-
|
|
474
|
+
log.error( 'solid color sky generation failed:', error );
|
|
471
475
|
|
|
472
476
|
}
|
|
473
477
|
|
|
@@ -503,11 +507,11 @@ export class EnvironmentManager {
|
|
|
503
507
|
this.uniforms.set( 'sunAngularSize', 0.0087 );
|
|
504
508
|
this.uniforms.set( 'hasSun', 1 );
|
|
505
509
|
|
|
506
|
-
|
|
510
|
+
log.debug( `sun synced · dir ${this.envParams.skySunDirection.toArray().map( v => v.toFixed( 2 ) ).join( ',' )}` );
|
|
507
511
|
|
|
508
512
|
} catch ( error ) {
|
|
509
513
|
|
|
510
|
-
|
|
514
|
+
log.error( 'procedural sky generation failed:', error );
|
|
511
515
|
|
|
512
516
|
}
|
|
513
517
|
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
import { StorageInstancedBufferAttribute } from 'three/webgpu';
|
|
11
11
|
import { storage } from 'three/tsl';
|
|
12
12
|
import { MATERIAL_DATA_LAYOUT as M, TRIANGLE_DATA_LAYOUT as T } from '../EngineDefaults.js';
|
|
13
|
+
import { createLogger, fmt } from '../utils/Logger.js';
|
|
14
|
+
|
|
15
|
+
const log = createLogger( 'material' );
|
|
13
16
|
|
|
14
17
|
const PIXELS_PER_MATERIAL = M.SLOTS_PER_MATERIAL;
|
|
15
18
|
// Per-triangle float offsets used by _patchTriangleSideForMaterial / _patchTriangleBlockerForMaterial.
|
|
@@ -84,7 +87,7 @@ export class MaterialDataManager {
|
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
this.materialCount = Math.floor( vec4Count / PIXELS_PER_MATERIAL );
|
|
87
|
-
|
|
90
|
+
log.debug( `${fmt.n( this.materialCount )} materials (storage buffer)` );
|
|
88
91
|
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -186,7 +189,7 @@ export class MaterialDataManager {
|
|
|
186
189
|
|
|
187
190
|
if ( ! this.materialStorageAttr ) {
|
|
188
191
|
|
|
189
|
-
|
|
192
|
+
log.warn( 'material storage buffer not available' );
|
|
190
193
|
return;
|
|
191
194
|
|
|
192
195
|
}
|
|
@@ -364,7 +367,7 @@ export class MaterialDataManager {
|
|
|
364
367
|
|
|
365
368
|
break;
|
|
366
369
|
default:
|
|
367
|
-
|
|
370
|
+
log.warn( `unknown material property: ${property}` );
|
|
368
371
|
return;
|
|
369
372
|
|
|
370
373
|
}
|
|
@@ -403,7 +406,7 @@ export class MaterialDataManager {
|
|
|
403
406
|
|
|
404
407
|
if ( ! this.materialStorageAttr ) {
|
|
405
408
|
|
|
406
|
-
|
|
409
|
+
log.warn( 'material storage buffer not available' );
|
|
407
410
|
return;
|
|
408
411
|
|
|
409
412
|
}
|
|
@@ -630,7 +633,7 @@ export class MaterialDataManager {
|
|
|
630
633
|
|
|
631
634
|
if ( ! this.materialStorageAttr ) {
|
|
632
635
|
|
|
633
|
-
|
|
636
|
+
log.warn( 'material storage buffer not available' );
|
|
634
637
|
return;
|
|
635
638
|
|
|
636
639
|
}
|
|
@@ -651,7 +654,7 @@ export class MaterialDataManager {
|
|
|
651
654
|
const offset = transformOffsets[ textureName ];
|
|
652
655
|
if ( offset === undefined ) {
|
|
653
656
|
|
|
654
|
-
|
|
657
|
+
log.warn( `unknown texture name for transform update: ${textureName}` );
|
|
655
658
|
return;
|
|
656
659
|
|
|
657
660
|
}
|
|
@@ -683,7 +686,7 @@ export class MaterialDataManager {
|
|
|
683
686
|
|
|
684
687
|
if ( ! this.materialStorageAttr?.array ) {
|
|
685
688
|
|
|
686
|
-
|
|
689
|
+
log.warn( 'material storage buffer not available for feature scanning' );
|
|
687
690
|
return false;
|
|
688
691
|
|
|
689
692
|
}
|
|
@@ -763,7 +766,7 @@ export class MaterialDataManager {
|
|
|
763
766
|
|
|
764
767
|
if ( ! features ) {
|
|
765
768
|
|
|
766
|
-
|
|
769
|
+
log.warn( 'no sceneFeatures detected, skipping define injection' );
|
|
767
770
|
return;
|
|
768
771
|
|
|
769
772
|
}
|
|
@@ -780,7 +783,7 @@ export class MaterialDataManager {
|
|
|
780
783
|
// For TSL, we can't inject defines into the shader at runtime
|
|
781
784
|
// Instead, we would need to conditionally generate the shader
|
|
782
785
|
// For now, log the features for debugging
|
|
783
|
-
|
|
786
|
+
log.debug( 'material features:', features );
|
|
784
787
|
|
|
785
788
|
this.compiledFeatures = featuresJSON;
|
|
786
789
|
|
|
@@ -164,13 +164,13 @@ export class UniformManager {
|
|
|
164
164
|
u( 'maxSamples', DEFAULT_STATE.maxSamples, 'int' );
|
|
165
165
|
u( 'transmissiveBounces', DEFAULT_STATE.transmissiveBounces, 'int' );
|
|
166
166
|
u( 'maxSubsurfaceSteps', DEFAULT_STATE.maxSubsurfaceSteps, 'int' );
|
|
167
|
+
u( 'maxTransparentBounces', DEFAULT_STATE.maxTransparentBounces, 'int' );
|
|
167
168
|
u( 'visMode', DEFAULT_STATE.debugMode, 'int' );
|
|
168
169
|
u( 'debugVisScale', DEFAULT_STATE.debugVisScale, 'float' );
|
|
169
170
|
|
|
170
171
|
// Tier-1 convergence early-stop (FinalWrite reads these; live-toggled, no shader rebuild)
|
|
171
172
|
ub( 'useAdaptiveSampling', DEFAULT_STATE.useAdaptiveSampling );
|
|
172
173
|
u( 'noiseThreshold', DEFAULT_STATE.noiseThreshold, 'float' );
|
|
173
|
-
u( 'darkNoiseFloor', DEFAULT_STATE.darkNoiseFloor, 'float' );
|
|
174
174
|
u( 'adaptiveMinSamples', DEFAULT_STATE.adaptiveMinSamples, 'int' );
|
|
175
175
|
// CPU-only (read in PathTracer._isConvergedComplete, not bound to any kernel); registered here for
|
|
176
176
|
// the settings/configureForMode plumbing + the _defineUniformGetters accessor.
|