rayzee 7.7.0 → 7.9.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-D9GImjGj.js → BVHSubtreeWorker-sNzvxn66.js} +2 -2
- package/dist/assets/{BVHSubtreeWorker-D9GImjGj.js.map → BVHSubtreeWorker-sNzvxn66.js.map} +1 -1
- package/dist/assets/{BVHWorker-CNJ0UBQz.js → BVHWorker-CiVdFrwe.js} +2 -2
- package/dist/assets/{BVHWorker-CNJ0UBQz.js.map → BVHWorker-CiVdFrwe.js.map} +1 -1
- package/dist/rayzee.es.js +2057 -2035
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +55 -55
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +45 -1
- package/src/EngineEvents.js +1 -0
- package/src/Passes/OIDNDenoiser.js +25 -1
- package/src/PathTracerApp.js +36 -0
- package/src/Processor/AssetLoader.js +3 -0
- package/src/Processor/GeometryExtractor.js +35 -9
- package/src/Processor/PackedRayBuffer.js +15 -1
- package/src/Processor/QueueManager.js +13 -1
- package/src/Processor/SceneProcessor.js +176 -113
- package/src/Processor/ShaderBuilder.js +6 -24
- package/src/Processor/TextureCreator.js +16 -32
- package/src/Processor/Workers/BVHWorker.js +6 -1
- package/src/Stages/EdgeFilter.js +4 -3
- package/src/Stages/MotionVector.js +4 -4
- package/src/Stages/NormalDepth.js +20 -30
- package/src/Stages/PathTracer.js +20 -40
- package/src/TSL/DebugKernel.js +0 -2
- package/src/TSL/Debugger.js +1 -8
- package/src/TSL/Displacement.js +10 -10
- package/src/TSL/GenerateKernel.js +5 -1
- package/src/TSL/LightsDirect.js +8 -9
- package/src/TSL/LightsIndirect.js +15 -9
- package/src/TSL/LightsSampling.js +9 -19
- package/src/TSL/Random.js +11 -1
- package/src/TSL/ShadeKernel.js +1 -6
- package/src/TSL/TextureSampling.js +155 -34
- package/src/managers/EnvironmentManager.js +11 -0
- package/src/managers/MaterialDataManager.js +71 -39
- package/src/managers/RenderTargetManager.js +0 -522
package/src/TSL/ShadeKernel.js
CHANGED
|
@@ -74,9 +74,6 @@ export function buildShadeKernel( params ) {
|
|
|
74
74
|
rayBufferRW, rngBufferRW, hitBufferRO, gBufferRW,
|
|
75
75
|
counters,
|
|
76
76
|
activeIndicesRO,
|
|
77
|
-
albedoMaps, normalMaps, bumpMaps,
|
|
78
|
-
metalnessMaps, roughnessMaps, emissiveMaps,
|
|
79
|
-
displacementMaps,
|
|
80
77
|
envTexture, environmentIntensity, envMatrix,
|
|
81
78
|
enableEnvironmentLight, useEnvMapIS,
|
|
82
79
|
groundProjectionEnabled, groundProjectionRadius, groundProjectionHeight, groundProjectionLevel,
|
|
@@ -533,7 +530,7 @@ export function buildShadeKernel( params ) {
|
|
|
533
530
|
boxTests: int( 0 ), triTests: int( 0 ),
|
|
534
531
|
} );
|
|
535
532
|
const dispResult = DisplacementResult.wrap( refineDisplacedIntersection(
|
|
536
|
-
dispRay, dispHit, triangleBuffer,
|
|
533
|
+
dispRay, dispHit, triangleBuffer, material, bounceIndex,
|
|
537
534
|
) ).toVar();
|
|
538
535
|
samplingUV.assign( dispResult.uv );
|
|
539
536
|
displacedNormal.assign( dispResult.normal );
|
|
@@ -543,8 +540,6 @@ export function buildShadeKernel( params ) {
|
|
|
543
540
|
);
|
|
544
541
|
|
|
545
542
|
const matSamples = MaterialSamples.wrap( sampleAllMaterialTextures(
|
|
546
|
-
albedoMaps, normalMaps, bumpMaps,
|
|
547
|
-
metalnessMaps, roughnessMaps, emissiveMaps,
|
|
548
543
|
material, samplingUV, N,
|
|
549
544
|
) ).toVar();
|
|
550
545
|
|
|
@@ -1,9 +1,129 @@
|
|
|
1
1
|
import { Fn, wgslFn, float, vec2, vec3, vec4, int, If, normalize, cross, abs, mix, clamp, texture, textureSize } from 'three/tsl';
|
|
2
|
+
import { DataArrayTexture, LinearFilter } from 'three';
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
UVCache,
|
|
5
6
|
MaterialSamples,
|
|
6
7
|
} from './Struct.js';
|
|
8
|
+
import { TEXTURE_CONSTANTS } from '../EngineDefaults.js';
|
|
9
|
+
|
|
10
|
+
// ================================================================================
|
|
11
|
+
// CONSOLIDATED SIZE-BUCKETED MATERIAL TEXTURES
|
|
12
|
+
// ================================================================================
|
|
13
|
+
// Material maps are packed into two colorSpace pools (sRGB: albedo+emissive; linear:
|
|
14
|
+
// normal/bump/roughness/metalness/displacement), each split into MATERIAL_BUCKET_COUNT
|
|
15
|
+
// longest-edge size buckets so a small map no longer pays a large neighbour's footprint.
|
|
16
|
+
// A map's stored index encodes (bucket, layer) as bucket * BUCKET_LAYER_STRIDE + layer.
|
|
17
|
+
//
|
|
18
|
+
// The bucket texture nodes live at module level (same pattern as gobo/IES/shadowAlbedo):
|
|
19
|
+
// each stage sets them via setMaterialBucketTextures() right before building its graph,
|
|
20
|
+
// so each pipeline bakes in its own fresh nodes (avoiding cross-pipeline TextureNode
|
|
21
|
+
// caching, just like the per-type nodes did before).
|
|
22
|
+
|
|
23
|
+
const _STRIDE = TEXTURE_CONSTANTS.BUCKET_LAYER_STRIDE;
|
|
24
|
+
|
|
25
|
+
// Array<MATERIAL_BUCKET_COUNT> of texture nodes (never null — empty buckets get placeholders).
|
|
26
|
+
let _srgbBuckets = null;
|
|
27
|
+
let _linearBuckets = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Set the bucket texture node arrays read by the sampling functions. Call before building
|
|
31
|
+
* any graph that samples material textures (Shade / NormalDepth / Debug kernels).
|
|
32
|
+
* @param {Array} srgb sRGB pool nodes (albedo + emissive)
|
|
33
|
+
* @param {Array} linear linear pool nodes (normal/bump/roughness/metalness/displacement)
|
|
34
|
+
*/
|
|
35
|
+
export function setMaterialBucketTextures( srgb, linear ) {
|
|
36
|
+
|
|
37
|
+
_srgbBuckets = srgb;
|
|
38
|
+
_linearBuckets = linear;
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Run `fn(node, layer)` inside a runtime branch that selects the bucket node a packed
|
|
43
|
+
// index points to. Emits one If/ElseIf arm per bucket; only the matching arm executes.
|
|
44
|
+
// Caller must guard packedIndex >= 0.
|
|
45
|
+
const withBucket = ( buckets, packedIndex, fn ) => {
|
|
46
|
+
|
|
47
|
+
const bucket = packedIndex.div( int( _STRIDE ) ).toVar();
|
|
48
|
+
const layer = packedIndex.sub( bucket.mul( int( _STRIDE ) ) ).toVar();
|
|
49
|
+
let chain = If( bucket.equal( int( 0 ) ), () => fn( buckets[ 0 ], layer ) );
|
|
50
|
+
for ( let i = 1; i < buckets.length; i ++ ) {
|
|
51
|
+
|
|
52
|
+
chain = chain.ElseIf( bucket.equal( int( i ) ), () => fn( buckets[ i ], layer ) );
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return chain;
|
|
57
|
+
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Sample the bucket a packed index points to. Caller must guard packedIndex >= 0.
|
|
61
|
+
export const sampleBucket = ( buckets, packedIndex, uv ) => {
|
|
62
|
+
|
|
63
|
+
const result = vec4( 0.0 ).toVar();
|
|
64
|
+
withBucket( buckets, packedIndex, ( node, layer ) => result.assign( texture( node, uv ).depth( layer ) ) );
|
|
65
|
+
return result;
|
|
66
|
+
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Per-axis texel size (1/dims) of the bucket a packed displacement/bump index points to,
|
|
70
|
+
// for finite-difference derivative steps. Caller must guard packedIndex >= 0.
|
|
71
|
+
export const bucketTexelSize = ( buckets, packedIndex ) => {
|
|
72
|
+
|
|
73
|
+
const ts = vec2( 1.0 ).toVar();
|
|
74
|
+
withBucket( buckets, packedIndex, node => ts.assign( vec2( 1.0 ).div( vec2( textureSize( node ) ) ) ) );
|
|
75
|
+
return ts;
|
|
76
|
+
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// The linear-pool node set (displacement lives here) — for Displacement.js texel sizing.
|
|
80
|
+
export function getLinearBucketTextures() {
|
|
81
|
+
|
|
82
|
+
return _linearBuckets;
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 1×1 white placeholder array so empty-bucket branches always reference a valid node.
|
|
87
|
+
export function makeBucketPlaceholder() {
|
|
88
|
+
|
|
89
|
+
const t = new DataArrayTexture( new Uint8Array( [ 255, 255, 255, 255 ] ), 1, 1, 1 );
|
|
90
|
+
t.minFilter = LinearFilter;
|
|
91
|
+
t.magFilter = LinearFilter;
|
|
92
|
+
t.generateMipmaps = false;
|
|
93
|
+
t.needsUpdate = true;
|
|
94
|
+
return t;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build MATERIAL_BUCKET_COUNT texture nodes from a bucket array (DataArrayTexture | null per
|
|
99
|
+
// bucket). Null buckets get a fresh placeholder. Each caller builds its OWN nodes so each
|
|
100
|
+
// pipeline bakes in independent TextureNodes (no cross-pipeline caching).
|
|
101
|
+
export function buildBucketTextureNodes( bucketArrays ) {
|
|
102
|
+
|
|
103
|
+
const K = TEXTURE_CONSTANTS.MATERIAL_BUCKET_COUNT;
|
|
104
|
+
const nodes = [];
|
|
105
|
+
for ( let i = 0; i < K; i ++ ) {
|
|
106
|
+
|
|
107
|
+
const arr = bucketArrays && bucketArrays[ i ];
|
|
108
|
+
nodes.push( texture( arr || makeBucketPlaceholder() ) );
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return nodes;
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Update in-place the .value of bucket nodes from a fresh bucket array (model change).
|
|
117
|
+
export function refreshBucketTextureNodes( nodes, bucketArrays ) {
|
|
118
|
+
|
|
119
|
+
if ( ! nodes || ! bucketArrays ) return;
|
|
120
|
+
for ( let i = 0; i < nodes.length; i ++ ) {
|
|
121
|
+
|
|
122
|
+
if ( bucketArrays[ i ] && nodes[ i ] ) nodes[ i ].value = bucketArrays[ i ];
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
7
127
|
|
|
8
128
|
// ================================================================================
|
|
9
129
|
// FAST UTILITY FUNCTIONS
|
|
@@ -201,14 +321,14 @@ export const computeUVCache = Fn( ( [ baseUV, material ] ) => {
|
|
|
201
321
|
// PROCESSING FUNCTIONS
|
|
202
322
|
// ================================================================================
|
|
203
323
|
|
|
204
|
-
export const processAlbedo = Fn( ( [
|
|
324
|
+
export const processAlbedo = Fn( ( [ material, uvCache ] ) => {
|
|
205
325
|
|
|
206
326
|
const result = material.color.toVar();
|
|
207
327
|
|
|
208
328
|
If( material.albedoMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
209
329
|
|
|
210
|
-
const albedoSample =
|
|
211
|
-
// sRGB→linear handled by GPU hardware (
|
|
330
|
+
const albedoSample = sampleBucket( _srgbBuckets, material.albedoMapIndex, uvCache.albedoUV ).toVar();
|
|
331
|
+
// sRGB→linear handled by GPU hardware (sRGB bucket arrays carry SRGBColorSpace → rgba8unorm-srgb)
|
|
212
332
|
result.assign( vec4( material.color.rgb.mul( albedoSample.rgb ), material.color.a.mul( albedoSample.a ) ) );
|
|
213
333
|
|
|
214
334
|
} );
|
|
@@ -217,15 +337,15 @@ export const processAlbedo = Fn( ( [ albedoMaps, material, uvCache ] ) => {
|
|
|
217
337
|
|
|
218
338
|
} );
|
|
219
339
|
|
|
220
|
-
export const processMetalnessRoughness = Fn( ( [
|
|
340
|
+
export const processMetalnessRoughness = Fn( ( [ material, uvCache ] ) => {
|
|
221
341
|
|
|
222
342
|
const metalness = material.metalness.toVar();
|
|
223
343
|
const roughness = material.roughness.toVar();
|
|
224
344
|
|
|
225
345
|
If( material.metalnessMapIndex.greaterThanEqual( int( 0 ) ).and( material.metalnessMapIndex.equal( material.roughnessMapIndex ) ), () => {
|
|
226
346
|
|
|
227
|
-
// Same
|
|
228
|
-
const sample =
|
|
347
|
+
// Same packed index → same bucket layer (e.g. ORM) → sample once.
|
|
348
|
+
const sample = sampleBucket( _linearBuckets, material.metalnessMapIndex, uvCache.metalnessUV );
|
|
229
349
|
metalness.assign( material.metalness.mul( sample.b ) );
|
|
230
350
|
roughness.assign( material.roughness.mul( sample.g ) );
|
|
231
351
|
|
|
@@ -233,14 +353,14 @@ export const processMetalnessRoughness = Fn( ( [ metalnessMaps, roughnessMaps, m
|
|
|
233
353
|
|
|
234
354
|
If( material.metalnessMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
235
355
|
|
|
236
|
-
const metSample =
|
|
356
|
+
const metSample = sampleBucket( _linearBuckets, material.metalnessMapIndex, uvCache.metalnessUV );
|
|
237
357
|
metalness.assign( material.metalness.mul( metSample.b ) );
|
|
238
358
|
|
|
239
359
|
} );
|
|
240
360
|
|
|
241
361
|
If( material.roughnessMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
242
362
|
|
|
243
|
-
const rghSample =
|
|
363
|
+
const rghSample = sampleBucket( _linearBuckets, material.roughnessMapIndex, uvCache.roughnessUV );
|
|
244
364
|
roughness.assign( material.roughness.mul( rghSample.g ) );
|
|
245
365
|
|
|
246
366
|
} );
|
|
@@ -251,13 +371,13 @@ export const processMetalnessRoughness = Fn( ( [ metalnessMaps, roughnessMaps, m
|
|
|
251
371
|
|
|
252
372
|
} );
|
|
253
373
|
|
|
254
|
-
export const processNormal = Fn( ( [
|
|
374
|
+
export const processNormal = Fn( ( [ geometryNormal, material, uvCache ] ) => {
|
|
255
375
|
|
|
256
376
|
const result = geometryNormal.toVar();
|
|
257
377
|
|
|
258
378
|
If( material.normalMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
259
379
|
|
|
260
|
-
const normalSample =
|
|
380
|
+
const normalSample = sampleBucket( _linearBuckets, material.normalMapIndex, uvCache.normalUV );
|
|
261
381
|
const normalMap = normalSample.xyz.mul( 2.0 ).sub( 1.0 ).toVar();
|
|
262
382
|
normalMap.x.mulAssign( material.normalScale.x );
|
|
263
383
|
normalMap.y.assign( normalMap.y.negate().mul( material.normalScale.x ) );
|
|
@@ -277,21 +397,25 @@ export const processNormal = Fn( ( [ normalMaps, geometryNormal, material, uvCac
|
|
|
277
397
|
|
|
278
398
|
} );
|
|
279
399
|
|
|
280
|
-
export const processBump = Fn( ( [
|
|
400
|
+
export const processBump = Fn( ( [ currentNormal, material, uvCache ] ) => {
|
|
281
401
|
|
|
282
402
|
const result = currentNormal.toVar();
|
|
283
403
|
|
|
284
404
|
If( material.bumpMapIndex.greaterThanEqual( int( 0 ) ).and( material.bumpScale.greaterThan( 0.0 ) ), () => {
|
|
285
405
|
|
|
286
|
-
//
|
|
287
|
-
|
|
406
|
+
// Taps + texel size come from the SELECTED bucket node (its real dimensions), so the
|
|
407
|
+
// finite-difference step is correct per bucket — done inside one bucket-branch.
|
|
408
|
+
const bumpNormal = vec3( 0.0, 0.0, 1.0 ).toVar();
|
|
409
|
+
withBucket( _linearBuckets, material.bumpMapIndex, ( node, layer ) => {
|
|
288
410
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
411
|
+
const texelSize = vec2( 1.0 ).div( vec2( textureSize( node ) ) ).toVar();
|
|
412
|
+
const h_c = texture( node, uvCache.bumpUV ).depth( layer ).r;
|
|
413
|
+
const h_u = texture( node, vec2( uvCache.bumpUV.x.add( texelSize.x ), uvCache.bumpUV.y ) ).depth( layer ).r;
|
|
414
|
+
const h_v = texture( node, vec2( uvCache.bumpUV.x, uvCache.bumpUV.y.add( texelSize.y ) ) ).depth( layer ).r;
|
|
415
|
+
const gradient = vec2( h_u.sub( h_c ), h_v.sub( h_c ) ).mul( material.bumpScale );
|
|
416
|
+
bumpNormal.assign( normalize( vec3( gradient.x.negate(), gradient.y.negate(), 1.0 ) ) );
|
|
292
417
|
|
|
293
|
-
|
|
294
|
-
const bumpNormal = normalize( vec3( gradient.x.negate(), gradient.y.negate(), 1.0 ) );
|
|
418
|
+
} );
|
|
295
419
|
|
|
296
420
|
// Build TBN matrix using current normal
|
|
297
421
|
const up = abs( currentNormal.z ).lessThan( 0.999 ).select( vec3( 0.0, 0.0, 1.0 ), vec3( 1.0, 0.0, 0.0 ) );
|
|
@@ -307,14 +431,14 @@ export const processBump = Fn( ( [ bumpMaps, currentNormal, material, uvCache ]
|
|
|
307
431
|
|
|
308
432
|
} );
|
|
309
433
|
|
|
310
|
-
export const processEmissive = Fn( ( [
|
|
434
|
+
export const processEmissive = Fn( ( [ material, uvCache ] ) => {
|
|
311
435
|
|
|
312
436
|
const emissionBase = material.emissive.mul( material.emissiveIntensity ).toVar();
|
|
313
437
|
|
|
314
438
|
If( material.emissiveMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
315
439
|
|
|
316
|
-
const emissiveSample =
|
|
317
|
-
// sRGB→linear handled by GPU hardware (
|
|
440
|
+
const emissiveSample = sampleBucket( _srgbBuckets, material.emissiveMapIndex, uvCache.emissiveUV ).toVar();
|
|
441
|
+
// sRGB→linear handled by GPU hardware (sRGB bucket arrays carry SRGBColorSpace → rgba8unorm-srgb)
|
|
318
442
|
emissionBase.assign( emissionBase.mul( emissiveSample.rgb ) );
|
|
319
443
|
|
|
320
444
|
} );
|
|
@@ -327,10 +451,7 @@ export const processEmissive = Fn( ( [ emissiveMaps, material, uvCache ] ) => {
|
|
|
327
451
|
// MAIN BATCHED SAMPLING FUNCTION
|
|
328
452
|
// ================================================================================
|
|
329
453
|
|
|
330
|
-
export const sampleAllMaterialTextures = Fn( ( [
|
|
331
|
-
albedoMaps, normalMaps, bumpMaps, metalnessMaps, roughnessMaps, emissiveMaps,
|
|
332
|
-
material, uv, geometryNormal
|
|
333
|
-
] ) => {
|
|
454
|
+
export const sampleAllMaterialTextures = Fn( ( [ material, uv, geometryNormal ] ) => {
|
|
334
455
|
|
|
335
456
|
const albedo = vec4( 0.0 ).toVar();
|
|
336
457
|
const emissive = vec3( 0.0 ).toVar();
|
|
@@ -351,17 +472,17 @@ export const sampleAllMaterialTextures = Fn( ( [
|
|
|
351
472
|
// Compute optimized UV cache with redundancy detection
|
|
352
473
|
const uvCache = UVCache.wrap( computeUVCache( uv, material ) ).toVar();
|
|
353
474
|
|
|
354
|
-
// Process samples
|
|
355
|
-
albedo.assign( processAlbedo(
|
|
475
|
+
// Process samples (bucket nodes read from module-level state)
|
|
476
|
+
albedo.assign( processAlbedo( material, uvCache ) );
|
|
356
477
|
|
|
357
|
-
const metalRough = processMetalnessRoughness(
|
|
478
|
+
const metalRough = processMetalnessRoughness( material, uvCache );
|
|
358
479
|
metalness.assign( metalRough.x );
|
|
359
480
|
roughness.assign( metalRough.y );
|
|
360
481
|
|
|
361
|
-
const currentNormal = processNormal(
|
|
362
|
-
normal.assign( processBump(
|
|
482
|
+
const currentNormal = processNormal( geometryNormal, material, uvCache ).toVar();
|
|
483
|
+
normal.assign( processBump( currentNormal, material, uvCache ) );
|
|
363
484
|
|
|
364
|
-
emissive.assign( processEmissive(
|
|
485
|
+
emissive.assign( processEmissive( material, uvCache ) );
|
|
365
486
|
|
|
366
487
|
} );
|
|
367
488
|
|
|
@@ -369,15 +490,15 @@ export const sampleAllMaterialTextures = Fn( ( [
|
|
|
369
490
|
|
|
370
491
|
} );
|
|
371
492
|
|
|
372
|
-
// Sample displacement map at given UV coordinates
|
|
373
|
-
export const sampleDisplacementMap = Fn( ( [
|
|
493
|
+
// Sample displacement map (linear pool) at given UV coordinates.
|
|
494
|
+
export const sampleDisplacementMap = Fn( ( [ displacementMapIndex, uv, transform ] ) => {
|
|
374
495
|
|
|
375
496
|
const result = float( 0.0 ).toVar();
|
|
376
497
|
|
|
377
498
|
If( displacementMapIndex.greaterThanEqual( int( 0 ) ), () => {
|
|
378
499
|
|
|
379
500
|
const transformedUV = getTransformedUV( { uv, transform } );
|
|
380
|
-
result.assign(
|
|
501
|
+
result.assign( sampleBucket( _linearBuckets, displacementMapIndex, transformedUV ).r );
|
|
381
502
|
|
|
382
503
|
} );
|
|
383
504
|
|
|
@@ -360,6 +360,17 @@ export class EnvironmentManager {
|
|
|
360
360
|
*/
|
|
361
361
|
async setEnvironmentMap( envMap ) {
|
|
362
362
|
|
|
363
|
+
// Free the outgoing env texture's GPU memory before it is orphaned. Skip: the
|
|
364
|
+
// reusable placeholder, an idempotent re-set of the same texture, and the HDRI
|
|
365
|
+
// stashed by setMode() for a later sky→hdri restore. Only when actually
|
|
366
|
+
// installing a new non-null texture (the null-env branch keeps the old ref).
|
|
367
|
+
const oldTex = this.environmentTexture;
|
|
368
|
+
if ( envMap && oldTex && oldTex !== envMap && oldTex !== this._envPlaceholder && oldTex !== this._previousHDRI ) {
|
|
369
|
+
|
|
370
|
+
oldTex.dispose?.();
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
|
|
363
374
|
this.scene.environment = envMap;
|
|
364
375
|
this.setEnvironmentTexture( envMap );
|
|
365
376
|
|
|
@@ -34,14 +34,18 @@ export class MaterialDataManager {
|
|
|
34
34
|
this.materialStorageNode = null;
|
|
35
35
|
this.materialCount = 0;
|
|
36
36
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
// Consolidated size-bucketed material texture arrays (see SceneProcessor._bucketTextures):
|
|
38
|
+
// srgbBuckets[K] — albedo + emissive (SRGBColorSpace)
|
|
39
|
+
// linearBuckets[K] — normal/bump/roughness/metalness/displacement
|
|
40
|
+
// Each entry is a DataArrayTexture | null (null = empty bucket).
|
|
41
|
+
this.srgbBuckets = null;
|
|
42
|
+
this.linearBuckets = null;
|
|
43
|
+
|
|
44
|
+
// uuid → packed (bucket,layer) index maps for the current scene, handed over by the
|
|
45
|
+
// SceneProcessor that built the buckets. Let runtime material edits (updateMaterial)
|
|
46
|
+
// re-pack a texture's index against the current bucket layout.
|
|
47
|
+
this._srgbTexPacked = null;
|
|
48
|
+
this._linearTexPacked = null;
|
|
45
49
|
|
|
46
50
|
// Compiled features cache (for change detection)
|
|
47
51
|
this.compiledFeatures = null;
|
|
@@ -112,45 +116,60 @@ export class MaterialDataManager {
|
|
|
112
116
|
*/
|
|
113
117
|
setMaterialTextures( textures ) {
|
|
114
118
|
|
|
115
|
-
if ( textures.
|
|
116
|
-
if ( textures.
|
|
117
|
-
if ( textures.normalMaps ) this.normalMaps = textures.normalMaps;
|
|
118
|
-
if ( textures.bumpMaps ) this.bumpMaps = textures.bumpMaps;
|
|
119
|
-
if ( textures.roughnessMaps ) this.roughnessMaps = textures.roughnessMaps;
|
|
120
|
-
if ( textures.metalnessMaps ) this.metalnessMaps = textures.metalnessMaps;
|
|
121
|
-
if ( textures.displacementMaps ) this.displacementMaps = textures.displacementMaps;
|
|
119
|
+
if ( textures.srgbBuckets ) this.srgbBuckets = textures.srgbBuckets;
|
|
120
|
+
if ( textures.linearBuckets ) this.linearBuckets = textures.linearBuckets;
|
|
122
121
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
/**
|
|
126
|
-
*
|
|
125
|
+
* Receive the scene's uuid→packed texture-index maps (from the SceneProcessor that bucketed).
|
|
126
|
+
* @param {Map|null} srgb
|
|
127
|
+
* @param {Map|null} linear
|
|
128
|
+
*/
|
|
129
|
+
setTexturePackMaps( srgb, linear ) {
|
|
130
|
+
|
|
131
|
+
this._srgbTexPacked = srgb || null;
|
|
132
|
+
this._linearTexPacked = linear || null;
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Packed (bucket, layer) index for a Three.js texture against the current bucket layout,
|
|
138
|
+
* or -1 if it isn't bucketed (a genuinely new texture → needs rebuildMaterials).
|
|
139
|
+
* @param {import('three').Texture|null} texture
|
|
140
|
+
* @param {boolean} isSrgb - true for albedo/emissive pool, false for the linear pool
|
|
141
|
+
* @returns {number}
|
|
142
|
+
*/
|
|
143
|
+
getPackedTextureIndex( texture, isSrgb ) {
|
|
144
|
+
|
|
145
|
+
if ( ! texture ) return - 1;
|
|
146
|
+
const uuid = texture.source?.uuid ?? texture.uuid;
|
|
147
|
+
const map = isSrgb ? this._srgbTexPacked : this._linearTexPacked;
|
|
148
|
+
const packed = map?.get( uuid );
|
|
149
|
+
return packed === undefined ? - 1 : packed;
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Load consolidated bucket arrays + pack maps from the SceneProcessor.
|
|
127
155
|
*/
|
|
128
156
|
loadTexturesFromSdfs() {
|
|
129
157
|
|
|
130
|
-
this.
|
|
131
|
-
this.
|
|
132
|
-
this.
|
|
133
|
-
this.bumpMaps = this.sdfs.bumpTextures;
|
|
134
|
-
this.roughnessMaps = this.sdfs.roughnessTextures;
|
|
135
|
-
this.metalnessMaps = this.sdfs.metalnessTextures;
|
|
136
|
-
this.displacementMaps = this.sdfs.displacementTextures;
|
|
158
|
+
this.srgbBuckets = this.sdfs.srgbBucketTextures;
|
|
159
|
+
this.linearBuckets = this.sdfs.linearBucketTextures;
|
|
160
|
+
this.setTexturePackMaps( this.sdfs._srgbTexPacked, this.sdfs._linearTexPacked );
|
|
137
161
|
|
|
138
162
|
}
|
|
139
163
|
|
|
140
164
|
/**
|
|
141
|
-
* Get
|
|
142
|
-
* @returns {
|
|
165
|
+
* Get the consolidated bucket arrays.
|
|
166
|
+
* @returns {{ srgbBuckets: Array, linearBuckets: Array }}
|
|
143
167
|
*/
|
|
144
168
|
getTextureArrays() {
|
|
145
169
|
|
|
146
170
|
return {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
normalMaps: this.normalMaps,
|
|
150
|
-
bumpMaps: this.bumpMaps,
|
|
151
|
-
roughnessMaps: this.roughnessMaps,
|
|
152
|
-
metalnessMaps: this.metalnessMaps,
|
|
153
|
-
displacementMaps: this.displacementMaps,
|
|
171
|
+
srgbBuckets: this.srgbBuckets,
|
|
172
|
+
linearBuckets: this.linearBuckets,
|
|
154
173
|
};
|
|
155
174
|
|
|
156
175
|
}
|
|
@@ -550,6 +569,22 @@ export class MaterialDataManager {
|
|
|
550
569
|
updateMaterial( materialIndex, material ) {
|
|
551
570
|
|
|
552
571
|
const completeMaterialData = this.sdfs.geometryExtractor.createMaterialObject( material );
|
|
572
|
+
|
|
573
|
+
// createMaterialObject returns stale per-type indices; re-pack each map to the packed
|
|
574
|
+
// (bucket, layer) index for the CURRENT bucket layout. -1 for a texture not yet bucketed
|
|
575
|
+
// (a genuinely new map → the caller must rebuildMaterials to add it to a bucket array).
|
|
576
|
+
if ( this._srgbTexPacked || this._linearTexPacked ) {
|
|
577
|
+
|
|
578
|
+
completeMaterialData.map = this.getPackedTextureIndex( material.map, true );
|
|
579
|
+
completeMaterialData.emissiveMap = this.getPackedTextureIndex( material.emissiveMap, true );
|
|
580
|
+
completeMaterialData.normalMap = this.getPackedTextureIndex( material.normalMap, false );
|
|
581
|
+
completeMaterialData.bumpMap = this.getPackedTextureIndex( material.bumpMap, false );
|
|
582
|
+
completeMaterialData.roughnessMap = this.getPackedTextureIndex( material.roughnessMap, false );
|
|
583
|
+
completeMaterialData.metalnessMap = this.getPackedTextureIndex( material.metalnessMap, false );
|
|
584
|
+
completeMaterialData.displacementMap = this.getPackedTextureIndex( material.displacementMap, false );
|
|
585
|
+
|
|
586
|
+
}
|
|
587
|
+
|
|
553
588
|
this.updateMaterialDataFromObject( materialIndex, completeMaterialData );
|
|
554
589
|
|
|
555
590
|
}
|
|
@@ -813,13 +848,10 @@ export class MaterialDataManager {
|
|
|
813
848
|
this.materialStorageAttr = null;
|
|
814
849
|
this.materialStorageNode = null;
|
|
815
850
|
this.materialCount = 0;
|
|
816
|
-
this.
|
|
817
|
-
this.
|
|
818
|
-
this.
|
|
819
|
-
this.
|
|
820
|
-
this.roughnessMaps = null;
|
|
821
|
-
this.metalnessMaps = null;
|
|
822
|
-
this.displacementMaps = null;
|
|
851
|
+
this.srgbBuckets = null;
|
|
852
|
+
this.linearBuckets = null;
|
|
853
|
+
this._srgbTexPacked = null;
|
|
854
|
+
this._linearTexPacked = null;
|
|
823
855
|
this.compiledFeatures = null;
|
|
824
856
|
|
|
825
857
|
}
|