rayzee 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rayzee.es.js +1175 -1107
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +46 -46
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/PathTracerApp.js +1 -0
- package/src/Processor/AssetLoader.js +31 -0
- package/src/Processor/GeometryExtractor.js +22 -67
- package/src/Processor/TextureCreator.js +128 -7
package/package.json
CHANGED
package/src/PathTracerApp.js
CHANGED
|
@@ -1014,6 +1014,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1014
1014
|
|
|
1015
1015
|
this._sdf = new SceneProcessor();
|
|
1016
1016
|
this.assetLoader = new AssetLoader( this.meshScene, this.cameraManager.camera, this.cameraManager.controls );
|
|
1017
|
+
this.assetLoader.setRenderer( this.renderer );
|
|
1017
1018
|
this.assetLoader.createFloorPlane();
|
|
1018
1019
|
|
|
1019
1020
|
this.cameraManager.controls.addEventListener( 'change', () => {
|
|
@@ -4,6 +4,7 @@ import { Box3, Vector3, RectAreaLight, Color, FloatType, LinearFilter, Equirecta
|
|
|
4
4
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
5
5
|
import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
|
|
6
6
|
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
|
|
7
|
+
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
|
|
7
8
|
import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';
|
|
8
9
|
import { createMeshesFromMultiMaterialMesh } from 'three/addons/utils/SceneUtils.js';
|
|
9
10
|
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
|
|
@@ -41,6 +42,13 @@ export class AssetLoader extends EventDispatcher {
|
|
|
41
42
|
this.loaderCache = {};
|
|
42
43
|
this.uploadedFileInfo = null;
|
|
43
44
|
this.animations = [];
|
|
45
|
+
this.renderer = null;
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setRenderer( renderer ) {
|
|
50
|
+
|
|
51
|
+
this.renderer = renderer;
|
|
44
52
|
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -698,8 +706,31 @@ export class AssetLoader extends EventDispatcher {
|
|
|
698
706
|
dracoLoader.setDecoderConfig( { type: 'js' } );
|
|
699
707
|
dracoLoader.setDecoderPath( 'https://www.gstatic.com/draco/v1/decoders/' );
|
|
700
708
|
|
|
709
|
+
const ktx2Loader = new KTX2Loader();
|
|
710
|
+
ktx2Loader.setTranscoderPath( 'https://cdn.jsdelivr.net/npm/three@0.183.2/examples/jsm/libs/basis/' );
|
|
711
|
+
|
|
712
|
+
if ( this.renderer ) {
|
|
713
|
+
|
|
714
|
+
ktx2Loader.detectSupport( this.renderer );
|
|
715
|
+
|
|
716
|
+
// Force RGBA output for Basis Universal textures. GPU-compressed
|
|
717
|
+
// texture arrays (CompressedArrayTexture) are blocked by a Three.js
|
|
718
|
+
// TSL limitation: the node compiler maintains global state that
|
|
719
|
+
// survives dispose(), so swapping texture array formats between
|
|
720
|
+
// DataArrayTexture and CompressedArrayTexture at runtime causes
|
|
721
|
+
// WGSL compilation failures (unresolved uniform bindings).
|
|
722
|
+
ktx2Loader.workerConfig = {
|
|
723
|
+
astcSupported: false, etc1Supported: false, etc2Supported: false,
|
|
724
|
+
dxtSupported: false, bptcSupported: false, pvrtcSupported: false,
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
this.loaderCache.ktx2 = ktx2Loader;
|
|
730
|
+
|
|
701
731
|
const loader = new GLTFLoader();
|
|
702
732
|
loader.setDRACOLoader( dracoLoader );
|
|
733
|
+
loader.setKTX2Loader( ktx2Loader );
|
|
703
734
|
loader.setMeshoptDecoder( MeshoptDecoder );
|
|
704
735
|
|
|
705
736
|
this.loaderCache.gltf = loader;
|
|
@@ -542,55 +542,29 @@ export class GeometryExtractor {
|
|
|
542
542
|
for ( let i = 0; i < triangleCount; i ++ ) {
|
|
543
543
|
|
|
544
544
|
const i3 = i * 3;
|
|
545
|
+
const idxA = indices ? indices[ i3 + 0 ] : i3 + 0;
|
|
546
|
+
const idxB = indices ? indices[ i3 + 1 ] : i3 + 1;
|
|
547
|
+
const idxC = indices ? indices[ i3 + 2 ] : i3 + 2;
|
|
545
548
|
|
|
546
|
-
|
|
547
|
-
|
|
549
|
+
this.getVertex( positions, idxA, posA );
|
|
550
|
+
this.getVertex( positions, idxB, posB );
|
|
551
|
+
this.getVertex( positions, idxC, posC );
|
|
548
552
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
553
|
+
this.getVertex( normals, idxA, normalA );
|
|
554
|
+
this.getVertex( normals, idxB, normalB );
|
|
555
|
+
this.getVertex( normals, idxC, normalC );
|
|
552
556
|
|
|
553
|
-
|
|
554
|
-
this.getVertexFromIndices( normals, indices[ i3 + 1 ], normalB );
|
|
555
|
-
this.getVertexFromIndices( normals, indices[ i3 + 2 ], normalC );
|
|
557
|
+
if ( uvs ) {
|
|
556
558
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
this.getVertexFromIndices( uvs, indices[ i3 + 1 ], uvB );
|
|
561
|
-
this.getVertexFromIndices( uvs, indices[ i3 + 2 ], uvC );
|
|
562
|
-
|
|
563
|
-
} else {
|
|
564
|
-
|
|
565
|
-
uvA.set( 0, 0 );
|
|
566
|
-
uvB.set( 0, 0 );
|
|
567
|
-
uvC.set( 0, 0 );
|
|
568
|
-
|
|
569
|
-
}
|
|
559
|
+
this.getVertex( uvs, idxA, uvA );
|
|
560
|
+
this.getVertex( uvs, idxB, uvB );
|
|
561
|
+
this.getVertex( uvs, idxC, uvC );
|
|
570
562
|
|
|
571
563
|
} else {
|
|
572
564
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
this.getVertex( normals, i3 + 0, normalA );
|
|
578
|
-
this.getVertex( normals, i3 + 1, normalB );
|
|
579
|
-
this.getVertex( normals, i3 + 2, normalC );
|
|
580
|
-
|
|
581
|
-
if ( uvs ) {
|
|
582
|
-
|
|
583
|
-
this.getVertex( uvs, i3 + 0, uvA );
|
|
584
|
-
this.getVertex( uvs, i3 + 1, uvB );
|
|
585
|
-
this.getVertex( uvs, i3 + 2, uvC );
|
|
586
|
-
|
|
587
|
-
} else {
|
|
588
|
-
|
|
589
|
-
uvA.set( 0, 0 );
|
|
590
|
-
uvB.set( 0, 0 );
|
|
591
|
-
uvC.set( 0, 0 );
|
|
592
|
-
|
|
593
|
-
}
|
|
565
|
+
uvA.set( 0, 0 );
|
|
566
|
+
uvB.set( 0, 0 );
|
|
567
|
+
uvC.set( 0, 0 );
|
|
594
568
|
|
|
595
569
|
}
|
|
596
570
|
|
|
@@ -689,37 +663,18 @@ export class GeometryExtractor {
|
|
|
689
663
|
}
|
|
690
664
|
|
|
691
665
|
// Optimized attribute access methods
|
|
692
|
-
getVertexFromIndices( attribute, index, target ) {
|
|
693
|
-
|
|
694
|
-
if ( attribute.itemSize === 2 ) {
|
|
695
|
-
|
|
696
|
-
target.x = attribute.array[ index * 2 ];
|
|
697
|
-
target.y = attribute.array[ index * 2 + 1 ];
|
|
698
|
-
|
|
699
|
-
} else if ( attribute.itemSize === 3 ) {
|
|
700
|
-
|
|
701
|
-
target.x = attribute.array[ index * 3 ];
|
|
702
|
-
target.y = attribute.array[ index * 3 + 1 ];
|
|
703
|
-
target.z = attribute.array[ index * 3 + 2 ];
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
return target;
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
|
|
711
666
|
getVertex( attribute, index, target ) {
|
|
712
667
|
|
|
713
668
|
if ( attribute.itemSize === 2 ) {
|
|
714
669
|
|
|
715
|
-
target.x = attribute.
|
|
716
|
-
target.y = attribute.
|
|
670
|
+
target.x = attribute.getX( index );
|
|
671
|
+
target.y = attribute.getY( index );
|
|
717
672
|
|
|
718
|
-
} else if ( attribute.itemSize
|
|
673
|
+
} else if ( attribute.itemSize >= 3 ) {
|
|
719
674
|
|
|
720
|
-
target.x = attribute.
|
|
721
|
-
target.y = attribute.
|
|
722
|
-
target.z = attribute.
|
|
675
|
+
target.x = attribute.getX( index );
|
|
676
|
+
target.y = attribute.getY( index );
|
|
677
|
+
target.z = attribute.getZ( index );
|
|
723
678
|
|
|
724
679
|
}
|
|
725
680
|
|
|
@@ -496,8 +496,11 @@ export class TextureCreator {
|
|
|
496
496
|
const cached = this.textureCache.get( cacheKey );
|
|
497
497
|
if ( cached ) return cached;
|
|
498
498
|
|
|
499
|
+
// Normalize non-drawable images (KTX2 CompressedTexture RGBA, DataTexture)
|
|
500
|
+
const { normalized, bitmapsToClose } = await this._normalizeTexturesForProcessing( textures );
|
|
501
|
+
|
|
499
502
|
// Select optimal processing strategy
|
|
500
|
-
const strategy = this.selectProcessingStrategy(
|
|
503
|
+
const strategy = this.selectProcessingStrategy( normalized );
|
|
501
504
|
let result;
|
|
502
505
|
|
|
503
506
|
try {
|
|
@@ -505,19 +508,19 @@ export class TextureCreator {
|
|
|
505
508
|
switch ( strategy.method ) {
|
|
506
509
|
|
|
507
510
|
case 'worker-direct':
|
|
508
|
-
result = await this.processWithWorkerDirect(
|
|
511
|
+
result = await this.processWithWorkerDirect( normalized );
|
|
509
512
|
break;
|
|
510
513
|
case 'worker-chunked':
|
|
511
|
-
result = await this.processWithWorkerChunked(
|
|
514
|
+
result = await this.processWithWorkerChunked( normalized, strategy.chunkSize );
|
|
512
515
|
break;
|
|
513
516
|
case 'main-batch':
|
|
514
|
-
result = await this.processOnMainThreadBatch(
|
|
517
|
+
result = await this.processOnMainThreadBatch( normalized, strategy.batchSize );
|
|
515
518
|
break;
|
|
516
519
|
case 'main-streaming':
|
|
517
|
-
result = await this.processOnMainThreadStreaming(
|
|
520
|
+
result = await this.processOnMainThreadStreaming( normalized );
|
|
518
521
|
break;
|
|
519
522
|
default:
|
|
520
|
-
result = await this.processOnMainThreadSync(
|
|
523
|
+
result = await this.processOnMainThreadSync( normalized );
|
|
521
524
|
|
|
522
525
|
}
|
|
523
526
|
|
|
@@ -533,7 +536,11 @@ export class TextureCreator {
|
|
|
533
536
|
} catch ( error ) {
|
|
534
537
|
|
|
535
538
|
console.warn( 'Texture processing failed, trying fallback:', error );
|
|
536
|
-
return await this.processOnMainThreadSync(
|
|
539
|
+
return await this.processOnMainThreadSync( normalized );
|
|
540
|
+
|
|
541
|
+
} finally {
|
|
542
|
+
|
|
543
|
+
for ( const bmp of bitmapsToClose ) bmp.close();
|
|
537
544
|
|
|
538
545
|
}
|
|
539
546
|
|
|
@@ -1258,6 +1265,109 @@ export class TextureCreator {
|
|
|
1258
1265
|
|
|
1259
1266
|
}
|
|
1260
1267
|
|
|
1268
|
+
// ── KTX2 / DataTexture normalization ────────────────────────────────
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Normalize textures so every entry has a drawable `.image`.
|
|
1272
|
+
* - RGBA CompressedTexture (KTX2 Basis → RGBA): pixel data from mipmaps[0]
|
|
1273
|
+
* - GPU-compressed texture (BC7/ASTC/ETC2): warning (should be pre-decompressed)
|
|
1274
|
+
* - DataTexture (raw RGBA pixels): pixel data from image.data
|
|
1275
|
+
* - Regular texture: passed through as-is
|
|
1276
|
+
*
|
|
1277
|
+
* Bitmap creation is parallelized via Promise.all.
|
|
1278
|
+
*/
|
|
1279
|
+
async _normalizeTexturesForProcessing( textures ) {
|
|
1280
|
+
|
|
1281
|
+
const normalized = [];
|
|
1282
|
+
const bitmapsToClose = [];
|
|
1283
|
+
const bitmapJobs = []; // { index, promise }
|
|
1284
|
+
|
|
1285
|
+
for ( const tex of textures ) {
|
|
1286
|
+
|
|
1287
|
+
if ( ! tex?.image ) continue;
|
|
1288
|
+
|
|
1289
|
+
// RGBA CompressedTexture (KTX2 Basis transcode wraps output as CompressedTexture)
|
|
1290
|
+
if ( tex.isCompressedTexture && tex.format === RGBAFormat && tex.mipmaps?.[ 0 ]?.data ) {
|
|
1291
|
+
|
|
1292
|
+
const mip = tex.mipmaps[ 0 ];
|
|
1293
|
+
const idx = normalized.length;
|
|
1294
|
+
normalized.push( null ); // placeholder — filled after Promise.all
|
|
1295
|
+
bitmapJobs.push( { index: idx, promise: _rawPixelsToBitmap( mip.data, mip.width, mip.height ) } );
|
|
1296
|
+
continue;
|
|
1297
|
+
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// True GPU-compressed texture in a mixed group — can't extract pixels on CPU.
|
|
1301
|
+
// All-compressed groups are handled by the CompressedArrayTexture path upstream.
|
|
1302
|
+
if ( tex.isCompressedTexture ) {
|
|
1303
|
+
|
|
1304
|
+
console.warn( '[TextureCreator] GPU-compressed texture in mixed group — using placeholder' );
|
|
1305
|
+
normalized.push( null );
|
|
1306
|
+
continue;
|
|
1307
|
+
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// DataTexture with raw pixel array
|
|
1311
|
+
if ( tex.image.data && ! ( tex.image instanceof HTMLImageElement ) &&
|
|
1312
|
+
! ( tex.image instanceof HTMLCanvasElement ) &&
|
|
1313
|
+
! ( typeof ImageBitmap !== 'undefined' && tex.image instanceof ImageBitmap ) ) {
|
|
1314
|
+
|
|
1315
|
+
const idx = normalized.length;
|
|
1316
|
+
normalized.push( null );
|
|
1317
|
+
bitmapJobs.push( { index: idx, promise: _rawPixelsToBitmap( tex.image.data, tex.image.width, tex.image.height ) } );
|
|
1318
|
+
continue;
|
|
1319
|
+
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
normalized.push( tex );
|
|
1323
|
+
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// Resolve all bitmap conversions in parallel
|
|
1327
|
+
if ( bitmapJobs.length > 0 ) {
|
|
1328
|
+
|
|
1329
|
+
const results = await Promise.allSettled( bitmapJobs.map( j => j.promise ) );
|
|
1330
|
+
|
|
1331
|
+
for ( let i = 0; i < bitmapJobs.length; i ++ ) {
|
|
1332
|
+
|
|
1333
|
+
const { index } = bitmapJobs[ i ];
|
|
1334
|
+
const result = results[ i ];
|
|
1335
|
+
|
|
1336
|
+
if ( result.status === 'fulfilled' ) {
|
|
1337
|
+
|
|
1338
|
+
const bitmap = result.value;
|
|
1339
|
+
bitmapsToClose.push( bitmap );
|
|
1340
|
+
normalized[ index ] = { image: bitmap };
|
|
1341
|
+
|
|
1342
|
+
} else {
|
|
1343
|
+
|
|
1344
|
+
console.warn( '[TextureCreator] Failed to create ImageBitmap:', result.reason );
|
|
1345
|
+
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Replace any remaining nulls (failed conversions) with a 1x1 white placeholder
|
|
1353
|
+
// to preserve array indexing alignment with material texture indices.
|
|
1354
|
+
for ( let i = 0; i < normalized.length; i ++ ) {
|
|
1355
|
+
|
|
1356
|
+
if ( normalized[ i ] === null ) {
|
|
1357
|
+
|
|
1358
|
+
const placeholder = new Uint8ClampedArray( [ 255, 255, 255, 255 ] );
|
|
1359
|
+
const bitmap = await createImageBitmap( new ImageData( placeholder, 1, 1 ) );
|
|
1360
|
+
bitmapsToClose.push( bitmap );
|
|
1361
|
+
normalized[ i ] = { image: bitmap };
|
|
1362
|
+
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
return { normalized, bitmapsToClose };
|
|
1368
|
+
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1261
1371
|
createFallbackTexture() {
|
|
1262
1372
|
|
|
1263
1373
|
const data = new Uint8Array( [ 255, 255, 255, 255 ] );
|
|
@@ -1291,3 +1401,14 @@ export class TextureCreator {
|
|
|
1291
1401
|
}
|
|
1292
1402
|
|
|
1293
1403
|
}
|
|
1404
|
+
|
|
1405
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
1406
|
+
|
|
1407
|
+
/** Convert raw RGBA pixel data to an ImageBitmap (zero-copy Uint8ClampedArray view). */
|
|
1408
|
+
function _rawPixelsToBitmap( data, width, height ) {
|
|
1409
|
+
|
|
1410
|
+
const clamped = new Uint8ClampedArray( data.buffer, data.byteOffset, data.byteLength );
|
|
1411
|
+
return createImageBitmap( new ImageData( clamped, width, height ) );
|
|
1412
|
+
|
|
1413
|
+
}
|
|
1414
|
+
|