@stowkit/three-loader 0.1.27 → 0.1.29
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.
|
@@ -237,12 +237,7 @@ class MeshParser {
|
|
|
237
237
|
reject(new Error(`Failed to decode Draco geometry: ${error}`));
|
|
238
238
|
});
|
|
239
239
|
});
|
|
240
|
-
//
|
|
241
|
-
const boundsStart = performance.now();
|
|
242
|
-
geometry.computeBoundingSphere();
|
|
243
|
-
geometry.computeBoundingBox();
|
|
244
|
-
const boundsEnd = performance.now();
|
|
245
|
-
reader.PerfLogger.log(`[Perf] Bounds computation: ${(boundsEnd - boundsStart).toFixed(2)}ms`);
|
|
240
|
+
// Bounds will be computed automatically by Three.js when needed
|
|
246
241
|
const totalTime = performance.now();
|
|
247
242
|
reader.PerfLogger.log(`[Perf] Total geometry creation: ${(totalTime - startTime).toFixed(2)}ms`);
|
|
248
243
|
return geometry;
|
|
@@ -254,6 +249,11 @@ class MeshParser {
|
|
|
254
249
|
const root = new THREE__namespace.Group();
|
|
255
250
|
root.name = 'StowKitMesh';
|
|
256
251
|
const { geometries, materials, nodes, meshIndices } = parsedData;
|
|
252
|
+
// Pre-load ALL geometries in parallel for maximum speed
|
|
253
|
+
reader.PerfLogger.log(`[Perf] Starting parallel Draco decode of ${geometries.length} geometries...`);
|
|
254
|
+
const geometryPromises = geometries.map(geoInfo => this.createGeometry(geoInfo, dataBlob, dracoLoader));
|
|
255
|
+
const loadedGeometries = await Promise.all(geometryPromises);
|
|
256
|
+
reader.PerfLogger.log(`[Perf] All Draco decodes complete`);
|
|
257
257
|
// Create all Three.js objects for nodes
|
|
258
258
|
const nodeObjects = [];
|
|
259
259
|
for (const node of nodes) {
|
|
@@ -269,7 +269,7 @@ class MeshParser {
|
|
|
269
269
|
const meshIndex = meshIndices[meshIndexArrayPos];
|
|
270
270
|
if (meshIndex < geometries.length) {
|
|
271
271
|
const geoInfo = geometries[meshIndex];
|
|
272
|
-
const geometry =
|
|
272
|
+
const geometry = loadedGeometries[meshIndex];
|
|
273
273
|
// Use assigned material if valid, otherwise create default
|
|
274
274
|
let material;
|
|
275
275
|
if (geoInfo.materialIndex < materials.length) {
|
|
@@ -300,11 +300,11 @@ class MeshParser {
|
|
|
300
300
|
root.add(obj);
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
|
-
// If no nodes, create
|
|
303
|
+
// If no nodes, create meshes from all geometries
|
|
304
304
|
if (nodes.length === 0 && geometries.length > 0) {
|
|
305
305
|
for (let index = 0; index < geometries.length; index++) {
|
|
306
306
|
const geoInfo = geometries[index];
|
|
307
|
-
const geometry =
|
|
307
|
+
const geometry = loadedGeometries[index];
|
|
308
308
|
// Use assigned material if valid, otherwise create default
|
|
309
309
|
let material;
|
|
310
310
|
if (geoInfo.materialIndex < materials.length) {
|
|
@@ -696,8 +696,8 @@ class StowKitPack {
|
|
|
696
696
|
reader.PerfLogger.log(`[Perf] Parse mesh metadata: ${(performance.now() - parseStart).toFixed(2)}ms`);
|
|
697
697
|
// Load textures for materials
|
|
698
698
|
const textureStart = performance.now();
|
|
699
|
-
await this.loadMaterialTextures(parsedData.materialData, parsedData.materials);
|
|
700
|
-
reader.PerfLogger.log(`[Perf] Load textures: ${(performance.now() - textureStart).toFixed(2)}ms`);
|
|
699
|
+
const textureNames = await this.loadMaterialTextures(parsedData.materialData, parsedData.materials);
|
|
700
|
+
reader.PerfLogger.log(`[Perf] Load textures: ${(performance.now() - textureStart).toFixed(2)}ms (${textureNames.length > 0 ? textureNames.join(', ') : 'none'})`);
|
|
701
701
|
// Build Three.js scene with Draco decoder
|
|
702
702
|
const buildStart = performance.now();
|
|
703
703
|
const scene = await MeshParser.buildScene(parsedData, data, this.dracoLoader);
|
|
@@ -727,7 +727,7 @@ class StowKitPack {
|
|
|
727
727
|
throw new Error(`Failed to read texture data: ${assetPath}`);
|
|
728
728
|
}
|
|
729
729
|
// Load as KTX2
|
|
730
|
-
return await this.loadKTX2Texture(data);
|
|
730
|
+
return await this.loadKTX2Texture(data, assetPath);
|
|
731
731
|
})();
|
|
732
732
|
this.textureCache.set(assetPath, loadPromise);
|
|
733
733
|
return loadPromise;
|
|
@@ -1016,14 +1016,17 @@ class StowKitPack {
|
|
|
1016
1016
|
async loadMaterialTextures(materialData, materials) {
|
|
1017
1017
|
// Collect all texture load promises to load in parallel
|
|
1018
1018
|
const textureLoads = [];
|
|
1019
|
+
const uniqueTextures = new Set();
|
|
1019
1020
|
for (let i = 0; i < materialData.length; i++) {
|
|
1020
1021
|
const matData = materialData[i];
|
|
1021
1022
|
for (const prop of matData.properties) {
|
|
1022
1023
|
const textureId = prop.textureId?.trim();
|
|
1023
1024
|
if (textureId && textureId.length > 0) {
|
|
1025
|
+
uniqueTextures.add(textureId);
|
|
1024
1026
|
textureLoads.push({
|
|
1025
1027
|
materialIndex: i,
|
|
1026
1028
|
propertyName: prop.fieldName,
|
|
1029
|
+
textureId: textureId,
|
|
1027
1030
|
texturePromise: this.loadTexture(textureId).catch(error => {
|
|
1028
1031
|
console.error(`Failed to load texture "${textureId}":`, error);
|
|
1029
1032
|
throw error;
|
|
@@ -1043,20 +1046,21 @@ class StowKitPack {
|
|
|
1043
1046
|
this.applyTextureToMaterial(material, load.propertyName, result.value);
|
|
1044
1047
|
}
|
|
1045
1048
|
}
|
|
1049
|
+
return Array.from(uniqueTextures);
|
|
1046
1050
|
}
|
|
1047
|
-
async loadKTX2Texture(data) {
|
|
1048
|
-
|
|
1051
|
+
async loadKTX2Texture(data, textureName) {
|
|
1052
|
+
reader.PerfLogger.log(`[Perf] KTX2/Basis texture size: ${data.byteLength} bytes${textureName ? ` (${textureName})` : ''}`);
|
|
1053
|
+
// Create blob URL - KTX2Loader requires a URL, can't use ArrayBuffer directly
|
|
1049
1054
|
const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
1050
1055
|
const blob = new Blob([arrayBuffer]);
|
|
1051
1056
|
const url = URL.createObjectURL(blob);
|
|
1052
|
-
reader.PerfLogger.log(`[Perf] KTX2/Basis texture size: ${data.byteLength} bytes`);
|
|
1053
1057
|
try {
|
|
1054
1058
|
return await new Promise((resolve, reject) => {
|
|
1055
1059
|
const loadStart = performance.now();
|
|
1056
1060
|
this.ktx2Loader.load(url, (texture) => {
|
|
1057
1061
|
URL.revokeObjectURL(url);
|
|
1058
1062
|
const loadEnd = performance.now();
|
|
1059
|
-
reader.PerfLogger.log(`[Perf] Basis transcode: ${(loadEnd - loadStart).toFixed(2)}ms (resolution: ${texture.image?.width || '?'}x${texture.image?.height || '?'})`);
|
|
1063
|
+
reader.PerfLogger.log(`[Perf] Basis transcode: ${(loadEnd - loadStart).toFixed(2)}ms (${textureName || 'unknown'}, resolution: ${texture.image?.width || '?'}x${texture.image?.height || '?'})`);
|
|
1060
1064
|
texture.needsUpdate = true;
|
|
1061
1065
|
resolve(texture);
|
|
1062
1066
|
}, undefined, (error) => {
|