rayzee 7.5.1 → 7.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rayzee",
3
- "version": "7.5.1",
3
+ "version": "7.7.0",
4
4
  "type": "module",
5
5
  "description": "Real-time WebGPU path tracing engine built on Three.js",
6
6
  "main": "dist/rayzee.umd.js",
@@ -10,6 +10,11 @@ export const ENGINE_DEFAULTS = {
10
10
  canvasWidth: 512,
11
11
  canvasHeight: 512,
12
12
 
13
+ // Max material-texture dimension (longest edge) used when processing a scene's
14
+ // textures into GPU arrays. Larger = sharper textures but ~quadratic VRAM. Clamped
15
+ // to TEXTURE_CONSTANTS.MAX_TEXTURE_SIZE (hardware ceiling). Applied at scene load.
16
+ maxTextureSize: 4096,
17
+
13
18
  toneMapping: 4,
14
19
  exposure: 1,
15
20
  saturation: 1.2,
@@ -483,7 +488,11 @@ export const TEXTURE_CONSTANTS = {
483
488
  BUFFER_POOL_SIZE: 20,
484
489
  CANVAS_POOL_SIZE: 12,
485
490
  CACHE_SIZE_LIMIT: 50,
486
- MAX_TEXTURE_SIZE: 8192
491
+ // Hardware ceiling for a single texture-array dimension (WebGPU maxTextureDimension2D
492
+ // guaranteed minimum). The configurable maxTextureSize setting is clamped to this.
493
+ MAX_TEXTURE_SIZE: 8192,
494
+ // Default cap applied when no maxTextureSize is supplied (engine standalone use).
495
+ DEFAULT_MAX_TEXTURE_SIZE: 4096
487
496
  };
488
497
 
489
498
  // Default texture matrix for materials
@@ -103,6 +103,8 @@ export class PathTracerApp extends EventDispatcher {
103
103
  this.assetLoader = null;
104
104
  this._sdf = null;
105
105
  this._animRefitInFlight = false;
106
+ // Max material-texture dimension (longest edge); applied on each scene build.
107
+ this._maxTextureSize = DEFAULT_STATE.maxTextureSize;
106
108
 
107
109
  // ── Pipeline & stages ──
108
110
  this.pipeline = null;
@@ -667,6 +669,47 @@ export class PathTracerApp extends EventDispatcher {
667
669
 
668
670
  }
669
671
 
672
+ /**
673
+ * Set the max material-texture dimension (longest edge) used when processing a
674
+ * scene's textures into GPU arrays. Clamped to the hardware ceiling. Larger =
675
+ * sharper textures, ~quadratic VRAM. By default reprocesses the current scene so
676
+ * the change is visible without a manual reload.
677
+ * @param {number} size
678
+ * @param {Object} [opts]
679
+ * @param {boolean} [opts.reprocess=true] - Rebuild the current scene now.
680
+ * @returns {Promise<void>}
681
+ */
682
+ async setMaxTextureSize( size, { reprocess = true } = {} ) {
683
+
684
+ const prev = this._maxTextureSize;
685
+ const clamped = this._sdf?.setMaxTextureSize( size );
686
+ this._maxTextureSize = clamped ?? size;
687
+ if ( typeof this.stages?.pathTracer?.sdfs?.setMaxTextureSize === 'function' ) {
688
+
689
+ this.stages.pathTracer.sdfs.setMaxTextureSize( this._maxTextureSize );
690
+
691
+ }
692
+
693
+ // Reprocess the loaded scene so the new cap takes effect immediately.
694
+ if ( reprocess && this._maxTextureSize !== prev && this._sdf?.triangleData && ! this._loadingInProgress ) {
695
+
696
+ this._loadingInProgress = true;
697
+ try {
698
+
699
+ await this.loadSceneData();
700
+ this.reset();
701
+ this.dispatchEvent( { type: 'TexturesReprocessed', maxTextureSize: this._maxTextureSize } );
702
+
703
+ } finally {
704
+
705
+ this._loadingInProgress = false;
706
+
707
+ }
708
+
709
+ }
710
+
711
+ }
712
+
670
713
  /** Shared pipeline: load asset → sync controls → build BVH → reset → dispatch events */
671
714
  async _loadWithSceneRebuild( loadFn, eventPayload ) {
672
715
 
@@ -730,6 +773,7 @@ export class PathTracerApp extends EventDispatcher {
730
773
 
731
774
  // Build BVH
732
775
  timer.start( 'BVH build (SceneProcessor)' );
776
+ this._sdf.setMaxTextureSize( this._maxTextureSize );
733
777
  await this._sdf.buildBVH( this.meshScene );
734
778
  timer.end( 'BVH build (SceneProcessor)' );
735
779
 
@@ -9,7 +9,7 @@ import { GeometryExtractor } from './GeometryExtractor.js';
9
9
  import { EmissiveTriangleBuilder } from './EmissiveTriangleBuilder.js';
10
10
  import { updateLoading } from '../Processor/utils.js';
11
11
  import { BuildTimer } from './BuildTimer.js';
12
- import { TRIANGLE_DATA_LAYOUT } from '../EngineDefaults.js';
12
+ import { TRIANGLE_DATA_LAYOUT, TEXTURE_CONSTANTS } from '../EngineDefaults.js';
13
13
  import { fetchAsWorker } from './Workers/fetchAsWorker.js';
14
14
  import BVH_WORKER_URL from './Workers/BVHWorker.js?worker&url';
15
15
  import BVH_REFIT_WORKER_URL from './Workers/BVHRefitWorker.js?worker&url';
@@ -41,6 +41,7 @@ export class SceneProcessor {
41
41
  verbose: false,
42
42
  useFloat32Array: true,
43
43
  textureQuality: 'adaptive', // 'low', 'medium', 'high', 'adaptive'
44
+ maxTextureSize: TEXTURE_CONSTANTS.DEFAULT_MAX_TEXTURE_SIZE, // longest-edge cap for material textures
44
45
  enableTextureCache: true,
45
46
  maxConcurrentTextureTasks: Math.min( navigator.hardwareConcurrency || 4, 6 ),
46
47
  // Treelet optimization configuration
@@ -109,6 +110,17 @@ export class SceneProcessor {
109
110
 
110
111
  }
111
112
 
113
+ /**
114
+ * Set the max material-texture dimension applied on the next scene build.
115
+ * @param {number} size - Longest-edge cap (clamped to the hardware ceiling).
116
+ */
117
+ setMaxTextureSize( size ) {
118
+
119
+ this.config.maxTextureSize = size;
120
+ return this.textureCreator?.setMaxTextureSize( size );
121
+
122
+ }
123
+
112
124
  /**
113
125
  * Initialize processing components with configuration
114
126
  * @private
@@ -131,7 +143,7 @@ export class SceneProcessor {
131
143
  } );
132
144
 
133
145
  // Create and configure texture creator
134
- this.textureCreator = new TextureCreator();
146
+ this.textureCreator = new TextureCreator( { maxTextureSize: this.config.maxTextureSize } );
135
147
  // The optimized TextureCreator will auto-detect capabilities and select optimal methods
136
148
 
137
149
  // Create emissive triangle builder for direct lighting
@@ -18,7 +18,6 @@ export class ShaderBuilder {
18
18
 
19
19
  // Previous-frame texture nodes (sample from MRT RenderTarget)
20
20
  this.prevColorTexNode = null;
21
- this.prevNormalDepthTexNode = null;
22
21
  this.prevAlbedoTexNode = null;
23
22
 
24
23
  // Scene texture nodes cache (for in-place updates on model change)
@@ -104,7 +103,6 @@ export class ShaderBuilder {
104
103
  // Previous-frame texture nodes — initialized from readTarget textures
105
104
  const readTextures = storageTextures.getReadTextures();
106
105
  this.prevColorTexNode = texture( readTextures.color );
107
- this.prevNormalDepthTexNode = texture( readTextures.normalDepth );
108
106
  this.prevAlbedoTexNode = texture( readTextures.albedo );
109
107
 
110
108
  const createArrayPlaceholder = () => {
@@ -156,7 +154,6 @@ export class ShaderBuilder {
156
154
  dispose() {
157
155
 
158
156
  this.prevColorTexNode = null;
159
- this.prevNormalDepthTexNode = null;
160
157
  this.prevAlbedoTexNode = null;
161
158
  this._sceneTextureNodes = null;
162
159
 
@@ -446,6 +446,11 @@ export class TextureCreator {
446
446
  this.maxConcurrentWorkers = TEXTURE_CONSTANTS.MAX_CONCURRENT_WORKERS;
447
447
  this.activeWorkers = 0;
448
448
 
449
+ // Longest-edge cap for material-texture arrays. Clamped to the hardware ceiling.
450
+ this.maxTextureSize = this._clampTextureSize(
451
+ options.maxTextureSize ?? TEXTURE_CONSTANTS.DEFAULT_MAX_TEXTURE_SIZE
452
+ );
453
+
449
454
  // Initialize high-performance components
450
455
  this.canvasPool = new CanvasPool();
451
456
  this.bufferPool = new SmartBufferPool( {
@@ -460,6 +465,25 @@ export class TextureCreator {
460
465
 
461
466
  }
462
467
 
468
+ _clampTextureSize( size ) {
469
+
470
+ const n = Math.floor( Number( size ) || TEXTURE_CONSTANTS.DEFAULT_MAX_TEXTURE_SIZE );
471
+ return Math.max( TEXTURE_CONSTANTS.MIN_TEXTURE_WIDTH, Math.min( n, TEXTURE_CONSTANTS.MAX_TEXTURE_SIZE ) );
472
+
473
+ }
474
+
475
+ setMaxTextureSize( size ) {
476
+
477
+ const clamped = this._clampTextureSize( size );
478
+ if ( clamped === this.maxTextureSize ) return clamped; // unchanged — keep cache
479
+ this.maxTextureSize = clamped;
480
+ // Cache keys don't encode size — drop cached arrays so a new cap takes effect.
481
+ this.textureCache?.dispose();
482
+ this.textureCache = new TextureCache();
483
+ return this.maxTextureSize;
484
+
485
+ }
486
+
463
487
  detectCapabilities() {
464
488
 
465
489
  return {
@@ -656,7 +680,7 @@ export class TextureCreator {
656
680
 
657
681
  worker.postMessage( {
658
682
  textures: texturesData,
659
- maxTextureSize: TEXTURE_CONSTANTS.MAX_TEXTURE_SIZE,
683
+ maxTextureSize: this.maxTextureSize,
660
684
  method: 'direct-transfer'
661
685
  }, transferables );
662
686
 
@@ -1256,7 +1280,8 @@ export class TextureCreator {
1256
1280
  maxWidth = Math.pow( 2, Math.ceil( Math.log2( maxWidth ) ) );
1257
1281
  maxHeight = Math.pow( 2, Math.ceil( Math.log2( maxHeight ) ) );
1258
1282
 
1259
- while ( maxWidth >= TEXTURE_CONSTANTS.MAX_TEXTURE_SIZE / 2 || maxHeight >= TEXTURE_CONSTANTS.MAX_TEXTURE_SIZE / 2 ) {
1283
+ // Halve only while a dimension exceeds the cap (preserves native res up to the cap).
1284
+ while ( maxWidth > this.maxTextureSize || maxHeight > this.maxTextureSize ) {
1260
1285
 
1261
1286
  maxWidth = Math.max( 1, Math.floor( maxWidth / 2 ) );
1262
1287
  maxHeight = Math.max( 1, Math.floor( maxHeight / 2 ) );
@@ -3,7 +3,7 @@ let canvas, ctx;
3
3
  // Memory limits and chunking configuration
4
4
  const MEMORY_LIMITS = {
5
5
  MAX_BYTES_PER_TEXTURE: 256 * 1024 * 1024, // 256MB per texture array
6
- MAX_TEXTURE_DIMENSION: 4096, // Maximum dimension for a single texture
6
+ MAX_TEXTURE_DIMENSION: 8192, // Hardware ceiling (WebGPU maxTextureDimension2D guaranteed min); the per-scene maxTextureSize setting is the actual knob
7
7
  CHUNK_SIZE: 8, // Optimized: Process textures in chunks of 8 for better memory locality
8
8
  ADAPTIVE_CHUNK_SIZE: true, // Enable adaptive chunk sizing based on texture dimensions
9
9
  MEMORY_SAFETY_FACTOR: 0.8 // Use only 80% of estimated available memory
@@ -627,8 +627,8 @@ function calculateOptimalDimensions( textures, maxTextureSize ) {
627
627
  maxWidth = Math.min( maxWidth, maxTextureSize, MEMORY_LIMITS.MAX_TEXTURE_DIMENSION );
628
628
  maxHeight = Math.min( maxHeight, maxTextureSize, MEMORY_LIMITS.MAX_TEXTURE_DIMENSION );
629
629
 
630
- // Additional safety check
631
- while ( maxWidth >= maxTextureSize / 2 || maxHeight >= maxTextureSize / 2 ) {
630
+ // Halve only while a dimension exceeds the cap (preserves native res up to the cap).
631
+ while ( maxWidth > maxTextureSize || maxHeight > maxTextureSize ) {
632
632
 
633
633
  maxWidth = Math.max( 1, Math.floor( maxWidth / 2 ) );
634
634
  maxHeight = Math.max( 1, Math.floor( maxHeight / 2 ) );
@@ -200,7 +200,6 @@ export class PathTracer extends PathTracerStage {
200
200
  if ( this.shaderBuilder.prevColorTexNode ) {
201
201
 
202
202
  this.shaderBuilder.prevColorTexNode.value = readTextures.color;
203
- this.shaderBuilder.prevNormalDepthTexNode.value = readTextures.normalDepth;
204
203
  this.shaderBuilder.prevAlbedoTexNode.value = readTextures.albedo;
205
204
 
206
205
  }
@@ -570,7 +569,6 @@ export class PathTracer extends PathTracerStage {
570
569
  this._wfMaxRayCount.value = maxRays;
571
570
 
572
571
  const prevColor = this.shaderBuilder.prevColorTexNode;
573
- const prevND = this.shaderBuilder.prevNormalDepthTexNode;
574
572
  const prevAlbedo = this.shaderBuilder.prevAlbedoTexNode;
575
573
  const writeTex = this.storageTextures.getWriteTextures();
576
574
 
@@ -885,7 +883,6 @@ export class PathTracer extends PathTracerStage {
885
883
  cameraIsMoving: this.cameraIsMoving,
886
884
  transparentBackground: this.transparentBackground,
887
885
  prevAccumTexture: prevColor,
888
- prevNormalDepthTexture: prevND,
889
886
  prevAlbedoTexture: prevAlbedo,
890
887
  renderWidth: this._wfRenderWidth,
891
888
  renderHeight: this._wfRenderHeight,
@@ -1,4 +1,4 @@
1
- import { Fn, float, vec2, int, If, Loop, abs, normalize, dot, max } from 'three/tsl';
1
+ import { Fn, float, vec2, int, If, Loop, abs, normalize, dot, max, textureSize } from 'three/tsl';
2
2
 
3
3
  import { struct } from './patches.js';
4
4
  import { getDatafromStorageBuffer } from './Common.js';
@@ -8,7 +8,6 @@ import { sampleDisplacementMap } from './TextureSampling.js';
8
8
  const MAX_MARCH_STEPS = 32;
9
9
  const MIN_MARCH_STEPS = 16;
10
10
  const BINARY_STEPS = 5;
11
- const NORMAL_TEXEL_SIZE = 1.0 / 1024.0;
12
11
  const TRI_STRIDE = 8;
13
12
 
14
13
  export const DisplacementResult = struct( {
@@ -194,14 +193,15 @@ export const refineDisplacedIntersection = Fn( ( [
194
193
  );
195
194
  const displacedHeight = finalHeight.sub( 0.5 ).mul( scale );
196
195
 
197
- // Compute displaced normal from height-field gradients using UV tangent vectors
198
- const h = float( NORMAL_TEXEL_SIZE );
196
+ // Compute displaced normal from height-field gradients using UV tangent vectors.
197
+ // Finite-difference step = one texel of the actual displacement-array dimensions.
198
+ const texel = vec2( 1.0 ).div( vec2( textureSize( displacementMaps ) ) ).toVar();
199
199
  const hC = finalHeight;
200
200
  const hU = sampleDisplacementMap(
201
- displacementMaps, material.displacementMapIndex, finalUV.add( vec2( h, 0.0 ) ), material.displacementTransform,
201
+ displacementMaps, material.displacementMapIndex, finalUV.add( vec2( texel.x, 0.0 ) ), material.displacementTransform,
202
202
  );
203
203
  const hV = sampleDisplacementMap(
204
- displacementMaps, material.displacementMapIndex, finalUV.add( vec2( 0.0, h ) ), material.displacementTransform,
204
+ displacementMaps, material.displacementMapIndex, finalUV.add( vec2( 0.0, texel.y ) ), material.displacementTransform,
205
205
  );
206
206
 
207
207
  // Perturb normal using actual tangent/bitangent from UV parameterization
@@ -32,7 +32,7 @@ export function buildFinalWriteKernel( params ) {
32
32
  resolution, frame,
33
33
  enableAccumulation, hasPreviousAccumulated, accumulationAlpha, cameraIsMoving,
34
34
  transparentBackground,
35
- prevAccumTexture, prevNormalDepthTexture, prevAlbedoTexture,
35
+ prevAccumTexture, prevAlbedoTexture,
36
36
  renderWidth, renderHeight,
37
37
  visMode,
38
38
  // Aux MRT (normalDepth + albedo) feeds only the denoiser/OIDN. Gated by a live uniform (1 = denoiser
@@ -80,7 +80,10 @@ export function buildFinalWriteKernel( params ) {
80
80
  finalColor.assign( mix( prevAccumSample.xyz, sampleColor.xyz, accumulationAlpha ) );
81
81
  If( auxOn, () => {
82
82
 
83
- finalNormalDepth.assign( mix( texture( prevNormalDepthTexture, prevUV, 0 ), finalNormalDepth, accumulationAlpha ) );
83
+ // Albedo averages cleanly (it's a colour). The NORMAL must NOT: averaging jittered
84
+ // unit normals collapses toward the flat geometric mean (worse at distance), which made
85
+ // OIDN smooth bump detail away. Keep this frame's point-sampled normal — it varies with
86
+ // the bump, which is exactly what OIDN's edge-stop needs to preserve it.
84
87
  finalAlbedo.assign( mix( texture( prevAlbedoTexture, prevUV, 0 ).xyz, finalAlbedo, accumulationAlpha ) );
85
88
 
86
89
  } );
@@ -1,4 +1,4 @@
1
- import { Fn, wgslFn, float, vec2, vec3, vec4, int, If, normalize, cross, abs, mix, clamp, texture } from 'three/tsl';
1
+ import { Fn, wgslFn, float, vec2, vec3, vec4, int, If, normalize, cross, abs, mix, clamp, texture, textureSize } from 'three/tsl';
2
2
 
3
3
  import {
4
4
  UVCache,
@@ -283,8 +283,8 @@ export const processBump = Fn( ( [ bumpMaps, currentNormal, material, uvCache ]
283
283
 
284
284
  If( material.bumpMapIndex.greaterThanEqual( int( 0 ) ).and( material.bumpScale.greaterThan( 0.0 ) ), () => {
285
285
 
286
- // Approximate texel size
287
- const texelSize = vec2( 1.0 / 1024.0 ).toVar();
286
+ // Texel size from the actual bump-array dimensions (finite-difference step).
287
+ const texelSize = vec2( 1.0 ).div( vec2( textureSize( bumpMaps ) ) ).toVar();
288
288
 
289
289
  const h_c = texture( bumpMaps, uvCache.bumpUV ).depth( int( material.bumpMapIndex ) ).r;
290
290
  const h_u = texture( bumpMaps, vec2( uvCache.bumpUV.x.add( texelSize.x ), uvCache.bumpUV.y ) ).depth( int( material.bumpMapIndex ) ).r;
@@ -1 +0,0 @@
1
- {"version":3,"file":"TexturesWorker-DBqGmVdR.js","names":[],"sources":["../../src/Processor/Workers/TexturesWorker.js"],"sourcesContent":["let canvas, ctx;\n\n// Memory limits and chunking configuration\nconst MEMORY_LIMITS = {\n\tMAX_BYTES_PER_TEXTURE: 256 * 1024 * 1024, // 256MB per texture array\n\tMAX_TEXTURE_DIMENSION: 4096, // Maximum dimension for a single texture\n\tCHUNK_SIZE: 8, // Optimized: Process textures in chunks of 8 for better memory locality\n\tADAPTIVE_CHUNK_SIZE: true, // Enable adaptive chunk sizing based on texture dimensions\n\tMEMORY_SAFETY_FACTOR: 0.8 // Use only 80% of estimated available memory\n};\n\nself.onmessage = async function ( e ) {\n\n\tconst { textures, maxTextureSize, method = 'direct-transfer' } = e.data;\n\n\ttry {\n\n\t\t// Initialize on first use\n\t\tif ( ! canvas ) {\n\n\t\t\tinitializeWorker( maxTextureSize );\n\n\t\t}\n\n\t\tconst result = await processTextures( textures, maxTextureSize, method );\n\n\t\t// Transfer ownership for zero-copy\n\t\tself.postMessage( result, [ result.data ] );\n\n\t} catch ( error ) {\n\n\t\tconsole.error( 'Worker processing failed:', error );\n\t\tself.postMessage( { error: error.message } );\n\n\t}\n\n};\n\nfunction initializeWorker( maxTextureSize ) {\n\n\t// Initialize OffscreenCanvas with optimal settings\n\tconst size = Math.min( maxTextureSize, MEMORY_LIMITS.MAX_TEXTURE_DIMENSION );\n\tcanvas = new OffscreenCanvas( size, size );\n\tctx = canvas.getContext( '2d', {\n\t\twillReadFrequently: true,\n\t\talpha: true,\n\t\tdesynchronized: true\n\t} );\n\n}\n\nasync function processTextures( textures, maxTextureSize, method ) {\n\n\t// Check if we need to use chunked processing\n\tconst dimensions = calculateOptimalDimensions( textures, maxTextureSize );\n\tconst estimatedBytes = dimensions.maxWidth * dimensions.maxHeight * textures.length * 4;\n\n\tif ( estimatedBytes > MEMORY_LIMITS.MAX_BYTES_PER_TEXTURE ) {\n\n\t\tconsole.log( `Large texture array detected (${( estimatedBytes / 1024 / 1024 ).toFixed( 2 )}MB), using chunked processing` );\n\t\treturn await processTexturesInChunks( textures, maxTextureSize, method );\n\n\t}\n\n\tswitch ( method ) {\n\n\t\tcase 'direct-transfer':\n\t\t\treturn await processWithDirectTransfer( textures, maxTextureSize );\n\t\tcase 'offscreen-optimized':\n\t\t\treturn await processWithOffscreenOptimized( textures, maxTextureSize );\n\t\tcase 'imageBitmap-batch':\n\t\t\treturn await processWithImageBitmapBatch( textures, maxTextureSize );\n\t\tdefault:\n\t\t\treturn await processWithDirectTransfer( textures, maxTextureSize );\n\n\t}\n\n}\n\nasync function processTexturesInChunks( textures, maxTextureSize, method ) {\n\n\tconst dimensions = calculateOptimalDimensions( textures, maxTextureSize );\n\tconst { maxWidth, maxHeight } = dimensions;\n\tconst depth = textures.length;\n\n\t// Optimize chunk size based on texture dimensions and memory constraints\n\tconst chunkSize = calculateOptimalChunkSize( maxWidth, maxHeight, depth );\n\tconst numChunks = Math.ceil( depth / chunkSize );\n\n\tconsole.log( `Processing ${depth} textures in ${numChunks} chunks of up to ${chunkSize} textures each` );\n\tconsole.log( `Texture dimensions: ${maxWidth}x${maxHeight}, Est. memory per chunk: ${( maxWidth * maxHeight * chunkSize * 4 / 1024 / 1024 ).toFixed( 2 )}MB` );\n\n\t// Allocate the full output array\n\tlet data;\n\ttry {\n\n\t\tdata = new Uint8Array( maxWidth * maxHeight * depth * 4 );\n\n\t} catch {\n\n\t\t// If full allocation fails, fall back to reduced dimensions\n\t\tconsole.warn( 'Failed to allocate full texture array, reducing dimensions' );\n\t\tconst reducedDimensions = calculateReducedDimensions( textures, maxTextureSize );\n\t\treturn await processWithReducedDimensions( textures, reducedDimensions, method );\n\n\t}\n\n\t// Pre-allocate chunk buffer for reuse\n\tconst chunkBufferSize = maxWidth * maxHeight * chunkSize * 4;\n\tlet chunkBuffer;\n\n\ttry {\n\n\t\tchunkBuffer = new Uint8Array( chunkBufferSize );\n\n\t} catch {\n\n\t\tconsole.warn( 'Failed to allocate chunk buffer, reducing dimensions' );\n\t\tconst reducedDimensions = calculateReducedDimensions( textures, maxTextureSize );\n\t\treturn await processWithReducedDimensions( textures, reducedDimensions, method );\n\n\t}\n\n\t// Process each chunk with optimized memory reuse\n\tfor ( let chunkIndex = 0; chunkIndex < numChunks; chunkIndex ++ ) {\n\n\t\tconst startIdx = chunkIndex * chunkSize;\n\t\tconst endIdx = Math.min( startIdx + chunkSize, depth );\n\t\tconst actualChunkSize = endIdx - startIdx;\n\t\tconst chunkTextures = textures.slice( startIdx, endIdx );\n\n\t\tconst chunkResult = await processTextureChunkOptimized(\n\t\t\tchunkTextures,\n\t\t\tmaxWidth,\n\t\t\tmaxHeight,\n\t\t\tchunkBuffer.subarray( 0, maxWidth * maxHeight * actualChunkSize * 4 )\n\t\t);\n\n\t\t// Copy chunk data to main array\n\t\tconst offset = startIdx * maxWidth * maxHeight * 4;\n\t\tconst copySize = actualChunkSize * maxWidth * maxHeight * 4;\n\t\tdata.set( new Uint8Array( chunkResult.data.slice( 0, copySize ) ), offset );\n\n\t\t// Micro-yield to prevent blocking the thread\n\n\t\tif ( chunkIndex % 2 === 1 ) { // Yield every 2 chunks instead of every chunk\n\n\t\t\tawait new Promise( resolve => setTimeout( resolve, 0 ) );\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tdata: data.buffer,\n\t\twidth: maxWidth,\n\t\theight: maxHeight,\n\t\tdepth\n\t};\n\n}\n\nfunction calculateOptimalChunkSize( maxWidth, maxHeight, totalTextures ) {\n\n\tif ( ! MEMORY_LIMITS.ADAPTIVE_CHUNK_SIZE ) {\n\n\t\treturn Math.min( MEMORY_LIMITS.CHUNK_SIZE, totalTextures );\n\n\t}\n\n\t// Calculate memory per texture in MB\n\tconst bytesPerTexture = maxWidth * maxHeight * 4;\n\tconst mbPerTexture = bytesPerTexture / ( 1024 * 1024 );\n\n\t// Adaptive chunk sizing based on texture size\n\tlet optimalChunkSize;\n\n\tif ( mbPerTexture <= 1 ) { // Small textures (<=1MB)\n\n\t\toptimalChunkSize = 16; // Process more at once\n\n\t} else if ( mbPerTexture <= 4 ) { // Medium textures (1-4MB)\n\n\t\toptimalChunkSize = 8; // Balanced approach\n\n\t} else if ( mbPerTexture <= 16 ) { // Large textures (4-16MB)\n\n\t\toptimalChunkSize = 4; // Conservative\n\n\t} else { // Very large textures (>16MB)\n\n\t\toptimalChunkSize = 2; // Very conservative\n\n\t}\n\n\t// Don't exceed total texture count or configured limits\n\treturn Math.min( optimalChunkSize, totalTextures, MEMORY_LIMITS.CHUNK_SIZE * 2 );\n\n}\n\nasync function processTextureChunkOptimized( textures, maxWidth, maxHeight, outputBuffer ) {\n\n\t// Resize canvas for this chunk if needed\n\tif ( canvas.width !== maxWidth || canvas.height !== maxHeight ) {\n\n\t\tcanvas.width = maxWidth;\n\t\tcanvas.height = maxHeight;\n\n\t}\n\n\t// Use provided buffer to avoid allocation\n\tconst bytesPerTexture = maxWidth * maxHeight * 4;\n\n\t// Optimize context settings once per chunk\n\tctx.imageSmoothingEnabled = true;\n\tctx.imageSmoothingQuality = 'high';\n\n\t// Process textures with optimized single texture processing\n\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\tconst textureData = textures[ i ];\n\n\t\ttry {\n\n\t\t\tconst offset = i * bytesPerTexture;\n\t\t\tawait processSingleTextureOptimized( textureData, outputBuffer, offset, maxWidth, maxHeight );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.warn( `Failed to process texture ${i}:`, error );\n\t\t\t// Fill with transparent pixels as fallback\n\t\t\tconst offset = i * bytesPerTexture;\n\t\t\toutputBuffer.fill( 0, offset, offset + bytesPerTexture );\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tdata: outputBuffer.buffer,\n\t\twidth: maxWidth,\n\t\theight: maxHeight,\n\t\tdepth: textures.length\n\t};\n\n}\n\nasync function processSingleTextureOptimized( textureData, outputData, offset, maxWidth, maxHeight ) {\n\n\tlet imageBitmap;\n\n\tif ( textureData.isDirect && textureData.bitmap ) {\n\n\t\t// Direct ImageBitmap transfer - no conversion needed!\n\t\timageBitmap = textureData.bitmap;\n\n\t} else if ( textureData.isImageData && textureData.data ) {\n\n\t\t// Direct ImageData transfer - minimal conversion\n\t\tconst imageData = new ImageData(\n\t\t\tnew Uint8ClampedArray( textureData.data ),\n\t\t\ttextureData.width,\n\t\t\ttextureData.height\n\t\t);\n\n\t\timageBitmap = await createImageBitmap( imageData, {\n\t\t\tresizeWidth: maxWidth,\n\t\t\tresizeHeight: maxHeight,\n\t\t\tresizeQuality: 'high'\n\t\t} );\n\n\t} else if ( textureData.isBlob ) {\n\n\t\t// Legacy blob processing (fallback)\n\t\tconst blob = new Blob( [ textureData.data ] );\n\t\timageBitmap = await createImageBitmap( blob, {\n\t\t\tresizeWidth: maxWidth,\n\t\t\tresizeHeight: maxHeight,\n\t\t\tresizeQuality: 'high'\n\t\t} );\n\n\t} else {\n\n\t\tthrow new Error( 'Unknown texture data format' );\n\n\t}\n\n\t// Clear and draw to canvas\n\tctx.clearRect( 0, 0, maxWidth, maxHeight );\n\tctx.drawImage( imageBitmap, 0, 0, maxWidth, maxHeight );\n\n\t// Get image data efficiently\n\tconst imageData = ctx.getImageData( 0, 0, maxWidth, maxHeight );\n\n\t// Copy directly to the specified offset in output buffer\n\toutputData.set( imageData.data, offset );\n\n\t// Clean up ImageBitmap if we created it\n\tif ( textureData.isImageData || textureData.isBlob ) {\n\n\t\timageBitmap.close();\n\n\t}\n\n}\n\nasync function processTextureChunk( textures, maxWidth, maxHeight ) {\n\n\tlet data;\n\ttry {\n\n\t\tdata = new Uint8Array( maxWidth * maxHeight * textures.length * 4 );\n\n\t} catch ( error ) {\n\n\t\tconsole.warn( 'Failed to allocate texture array in processTextureChunk, reducing dimensions' );\n\t\tconst nextWidth = Math.max( 1, Math.floor( maxWidth / 2 ) );\n\t\tconst nextHeight = Math.max( 1, Math.floor( maxHeight / 2 ) );\n\n\t\tif ( nextWidth === maxWidth && nextHeight === maxHeight ) {\n\n\t\t\tthrow error;\n\n\t\t}\n\n\t\treturn await processTextureChunk( textures, nextWidth, nextHeight );\n\n\t}\n\n\treturn await processTextureChunkOptimized( textures, maxWidth, maxHeight, data );\n\n}\n\nasync function processSingleTexture( textureData, index, outputData, maxWidth, maxHeight ) {\n\n\tconst offset = maxWidth * maxHeight * 4 * index;\n\tawait processSingleTextureOptimized( textureData, outputData, offset, maxWidth, maxHeight );\n\n}\n\nasync function processWithDirectTransfer( textures, maxTextureSize ) {\n\n\tconst dimensions = calculateOptimalDimensions( textures, maxTextureSize );\n\tconst { maxWidth, maxHeight } = dimensions;\n\n\t// Resize canvas if needed\n\tif ( canvas.width !== maxWidth || canvas.height !== maxHeight ) {\n\n\t\tcanvas.width = maxWidth;\n\t\tcanvas.height = maxHeight;\n\n\t}\n\n\tconst depth = textures.length;\n\n\t// Try to allocate memory with fallback\n\tlet data;\n\ttry {\n\n\t\tdata = new Uint8Array( maxWidth * maxHeight * depth * 4 );\n\n\t} catch ( error ) {\n\n\t\tconsole.error( 'Failed to allocate texture array:', error );\n\t\t// Fall back to chunked processing\n\t\treturn await processTexturesInChunks( textures, maxTextureSize, 'direct-transfer' );\n\n\t}\n\n\t// Optimize context settings for batch processing\n\tctx.imageSmoothingEnabled = true;\n\tctx.imageSmoothingQuality = 'high';\n\n\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\tconst textureData = textures[ i ];\n\n\t\ttry {\n\n\t\t\tawait processSingleTexture( textureData, i, data, maxWidth, maxHeight );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.warn( `Failed to process texture ${i}:`, error );\n\t\t\t// Fill with transparent pixels as fallback\n\t\t\tconst offset = maxWidth * maxHeight * 4 * i;\n\t\t\tdata.fill( 0, offset, offset + maxWidth * maxHeight * 4 );\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tdata: data.buffer,\n\t\twidth: maxWidth,\n\t\theight: maxHeight,\n\t\tdepth\n\t};\n\n}\n\nasync function processWithReducedDimensions( textures, dimensions, method ) {\n\n\tconst { maxWidth, maxHeight } = dimensions;\n\tconsole.log( `Using reduced dimensions: ${maxWidth}x${maxHeight}` );\n\n\t// Process with reduced dimensions\n\treturn await processTextureChunk( textures, maxWidth, maxHeight, method );\n\n}\n\nasync function processWithOffscreenOptimized( textures, maxTextureSize ) {\n\n\tconst dimensions = calculateOptimalDimensions( textures, maxTextureSize );\n\tconst { maxWidth, maxHeight } = dimensions;\n\n\t// Resize canvas if needed\n\tif ( canvas.width !== maxWidth || canvas.height !== maxHeight ) {\n\n\t\tcanvas.width = maxWidth;\n\t\tcanvas.height = maxHeight;\n\n\t}\n\n\tconst depth = textures.length;\n\n\t// Try to allocate memory with fallback\n\tlet data;\n\ttry {\n\n\t\tdata = new Uint8Array( maxWidth * maxHeight * depth * 4 );\n\n\t} catch ( error ) {\n\n\t\tconsole.error( 'Failed to allocate texture array:', error );\n\t\t// Fall back to chunked processing\n\t\treturn await processTexturesInChunks( textures, maxTextureSize, 'offscreen-optimized' );\n\n\t}\n\n\t// Optimize context settings for batch processing\n\tctx.imageSmoothingEnabled = true;\n\tctx.imageSmoothingQuality = 'high';\n\n\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\tconst textureData = textures[ i ];\n\n\t\ttry {\n\n\t\t\tlet imageBitmap;\n\n\t\t\tif ( textureData.isBlob ) {\n\n\t\t\t\t// Create ImageBitmap from blob data\n\t\t\t\tconst blob = new Blob( [ textureData.data ] );\n\t\t\t\timageBitmap = await createImageBitmap( blob, {\n\t\t\t\t\tresizeWidth: maxWidth,\n\t\t\t\t\tresizeHeight: maxHeight,\n\t\t\t\t\tresizeQuality: 'high'\n\t\t\t\t} );\n\n\t\t\t} else {\n\n\t\t\t\t// Handle direct image data\n\t\t\t\tconst imageData = new ImageData(\n\t\t\t\t\tnew Uint8ClampedArray( textureData.data ),\n\t\t\t\t\ttextureData.width,\n\t\t\t\t\ttextureData.height\n\t\t\t\t);\n\t\t\t\timageBitmap = await createImageBitmap( imageData, {\n\t\t\t\t\tresizeWidth: maxWidth,\n\t\t\t\t\tresizeHeight: maxHeight,\n\t\t\t\t\tresizeQuality: 'high'\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\t// Clear and draw to canvas\n\t\t\tctx.clearRect( 0, 0, maxWidth, maxHeight );\n\t\t\tctx.drawImage( imageBitmap, 0, 0 );\n\n\t\t\t// Get image data efficiently\n\t\t\tconst imageData = ctx.getImageData( 0, 0, maxWidth, maxHeight );\n\n\t\t\t// Copy to output array\n\t\t\tconst offset = maxWidth * maxHeight * 4 * i;\n\t\t\tdata.set( imageData.data, offset );\n\n\t\t\t// Clean up ImageBitmap\n\t\t\timageBitmap.close();\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.warn( `Failed to process texture ${i}:`, error );\n\t\t\t// Fill with transparent pixels as fallback\n\t\t\tconst offset = maxWidth * maxHeight * 4 * i;\n\t\t\tdata.fill( 0, offset, offset + maxWidth * maxHeight * 4 );\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tdata: data.buffer,\n\t\twidth: maxWidth,\n\t\theight: maxHeight,\n\t\tdepth\n\t};\n\n}\n\nasync function processWithImageBitmapBatch( textures, maxTextureSize ) {\n\n\tconst dimensions = calculateOptimalDimensions( textures, maxTextureSize );\n\tconst { maxWidth, maxHeight } = dimensions;\n\n\tconst depth = textures.length;\n\n\t// Try to allocate memory with fallback\n\tlet data;\n\ttry {\n\n\t\tdata = new Uint8Array( maxWidth * maxHeight * depth * 4 );\n\n\t} catch ( error ) {\n\n\t\tconsole.error( 'Failed to allocate texture array:', error );\n\t\t// Fall back to chunked processing\n\t\treturn await processTexturesInChunks( textures, maxTextureSize, 'imageBitmap-batch' );\n\n\t}\n\n\t// Process in batches for memory efficiency - optimized batch size\n\tconst batchSize = Math.min( calculateOptimalChunkSize( maxWidth, maxHeight, textures.length ), textures.length );\n\n\tfor ( let batchStart = 0; batchStart < textures.length; batchStart += batchSize ) {\n\n\t\tconst batchEnd = Math.min( batchStart + batchSize, textures.length );\n\t\tconst batchPromises = [];\n\n\t\t// Create all ImageBitmaps for this batch in parallel\n\t\tfor ( let i = batchStart; i < batchEnd; i ++ ) {\n\n\t\t\tconst textureData = textures[ i ];\n\n\t\t\tlet bitmapPromise;\n\t\t\tif ( textureData.isBlob ) {\n\n\t\t\t\tconst blob = new Blob( [ textureData.data ] );\n\t\t\t\tbitmapPromise = createImageBitmap( blob, {\n\t\t\t\t\tresizeWidth: maxWidth,\n\t\t\t\t\tresizeHeight: maxHeight,\n\t\t\t\t\tresizeQuality: 'high'\n\t\t\t\t} );\n\n\t\t\t} else {\n\n\t\t\t\tconst imageData = new ImageData(\n\t\t\t\t\tnew Uint8ClampedArray( textureData.data ),\n\t\t\t\t\ttextureData.width,\n\t\t\t\t\ttextureData.height\n\t\t\t\t);\n\t\t\t\tbitmapPromise = createImageBitmap( imageData, {\n\t\t\t\t\tresizeWidth: maxWidth,\n\t\t\t\t\tresizeHeight: maxHeight,\n\t\t\t\t\tresizeQuality: 'high'\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tbatchPromises.push(\n\t\t\t\tbitmapPromise.then( bitmap => ( { bitmap, index: i } ) )\n\t\t\t);\n\n\t\t}\n\n\t\t// Wait for all bitmaps in this batch\n\t\tconst bitmaps = await Promise.all( batchPromises );\n\n\t\t// Process each bitmap\n\t\tcanvas.width = maxWidth;\n\t\tcanvas.height = maxHeight;\n\t\tctx.imageSmoothingEnabled = false; // Fast processing for batches\n\n\t\tfor ( const { bitmap, index } of bitmaps ) {\n\n\t\t\tctx.clearRect( 0, 0, maxWidth, maxHeight );\n\t\t\tctx.drawImage( bitmap, 0, 0 );\n\n\t\t\tconst imageData = ctx.getImageData( 0, 0, maxWidth, maxHeight );\n\t\t\tconst offset = maxWidth * maxHeight * 4 * index;\n\t\t\tdata.set( imageData.data, offset );\n\n\t\t\tbitmap.close();\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tdata: data.buffer,\n\t\twidth: maxWidth,\n\t\theight: maxHeight,\n\t\tdepth\n\t};\n\n}\n\nfunction calculateOptimalDimensions( textures, maxTextureSize ) {\n\n\tlet maxWidth = 0;\n\tlet maxHeight = 0;\n\n\tfor ( let texture of textures ) {\n\n\t\tmaxWidth = Math.max( maxWidth, texture.width || 0 );\n\t\tmaxHeight = Math.max( maxHeight, texture.height || 0 );\n\n\t}\n\n\t// Round to power of 2 for optimal GPU performance\n\tmaxWidth = Math.pow( 2, Math.ceil( Math.log2( maxWidth ) ) );\n\tmaxHeight = Math.pow( 2, Math.ceil( Math.log2( maxHeight ) ) );\n\n\t// Respect texture size limits\n\tmaxWidth = Math.min( maxWidth, maxTextureSize, MEMORY_LIMITS.MAX_TEXTURE_DIMENSION );\n\tmaxHeight = Math.min( maxHeight, maxTextureSize, MEMORY_LIMITS.MAX_TEXTURE_DIMENSION );\n\n\t// Additional safety check\n\twhile ( maxWidth >= maxTextureSize / 2 || maxHeight >= maxTextureSize / 2 ) {\n\n\t\tmaxWidth = Math.max( 1, Math.floor( maxWidth / 2 ) );\n\t\tmaxHeight = Math.max( 1, Math.floor( maxHeight / 2 ) );\n\n\t}\n\n\treturn { maxWidth, maxHeight };\n\n}\n\nfunction calculateReducedDimensions( textures, maxTextureSize ) {\n\n\t// Calculate dimensions but reduce by factor of 2 for memory safety\n\tconst original = calculateOptimalDimensions( textures, maxTextureSize );\n\n\treturn {\n\t\tmaxWidth: Math.max( 1, Math.floor( original.maxWidth / 2 ) ),\n\t\tmaxHeight: Math.max( 1, Math.floor( original.maxHeight / 2 ) )\n\t};\n\n}\n\n"],"mappings":"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"}