@vizij/render 0.1.0 → 0.1.2
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 +12 -8
- package/dist/index.d.mts +42 -2
- package/dist/index.d.ts +42 -2
- package/dist/index.js +663 -131
- package/dist/index.mjs +654 -121
- package/package.json +18 -17
- package/LICENSE +0 -201
package/dist/index.mjs
CHANGED
|
@@ -974,6 +974,48 @@ function InnerRenderedShape({
|
|
|
974
974
|
);
|
|
975
975
|
}
|
|
976
976
|
},
|
|
977
|
+
roughness: (value) => {
|
|
978
|
+
const standard = material.current;
|
|
979
|
+
if (standard?.roughness !== void 0 && instanceOfRawNumber4(value)) {
|
|
980
|
+
standard.roughness = value;
|
|
981
|
+
standard.needsUpdate = true;
|
|
982
|
+
}
|
|
983
|
+
},
|
|
984
|
+
metalness: (value) => {
|
|
985
|
+
const standard = material.current;
|
|
986
|
+
if (standard?.metalness !== void 0 && instanceOfRawNumber4(value)) {
|
|
987
|
+
standard.metalness = value;
|
|
988
|
+
standard.needsUpdate = true;
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
shininess: (value) => {
|
|
992
|
+
const phong = material.current;
|
|
993
|
+
if (phong?.shininess !== void 0 && instanceOfRawNumber4(value)) {
|
|
994
|
+
phong.shininess = value;
|
|
995
|
+
phong.needsUpdate = true;
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
emissive: (value) => {
|
|
999
|
+
const standard = material.current;
|
|
1000
|
+
if (standard?.emissive && instanceOfRawRGB3(value)) {
|
|
1001
|
+
standard.emissive.setRGB(value.r, value.g, value.b);
|
|
1002
|
+
standard.needsUpdate = true;
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
emissiveIntensity: (value) => {
|
|
1006
|
+
const standard = material.current;
|
|
1007
|
+
if (standard?.emissiveIntensity !== void 0 && instanceOfRawNumber4(value)) {
|
|
1008
|
+
standard.emissiveIntensity = value;
|
|
1009
|
+
standard.needsUpdate = true;
|
|
1010
|
+
}
|
|
1011
|
+
},
|
|
1012
|
+
specular: (value) => {
|
|
1013
|
+
const phong = material.current;
|
|
1014
|
+
if (phong?.specular && instanceOfRawRGB3(value)) {
|
|
1015
|
+
phong.specular.setRGB(value.r, value.g, value.b);
|
|
1016
|
+
phong.needsUpdate = true;
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
977
1019
|
...morphTargetSettings[2]
|
|
978
1020
|
},
|
|
979
1021
|
shape
|
|
@@ -1094,7 +1136,10 @@ var MATERIAL_FEATURE_KEYS = [
|
|
|
1094
1136
|
"opacity",
|
|
1095
1137
|
"roughness",
|
|
1096
1138
|
"metalness",
|
|
1097
|
-
"shininess"
|
|
1139
|
+
"shininess",
|
|
1140
|
+
"emissive",
|
|
1141
|
+
"emissiveIntensity",
|
|
1142
|
+
"specular"
|
|
1098
1143
|
];
|
|
1099
1144
|
var MATERIAL_NAME_SUFFIXES = [
|
|
1100
1145
|
" color",
|
|
@@ -1103,7 +1148,10 @@ var MATERIAL_NAME_SUFFIXES = [
|
|
|
1103
1148
|
" opacity",
|
|
1104
1149
|
" roughness",
|
|
1105
1150
|
" metalness",
|
|
1106
|
-
" shininess"
|
|
1151
|
+
" shininess",
|
|
1152
|
+
" emissive intensity",
|
|
1153
|
+
" emissive",
|
|
1154
|
+
" specular"
|
|
1107
1155
|
];
|
|
1108
1156
|
function deriveMaterialName(shape, values) {
|
|
1109
1157
|
for (const key of MATERIAL_FEATURE_KEYS) {
|
|
@@ -1217,12 +1265,13 @@ import { createRef } from "react";
|
|
|
1217
1265
|
import { mapValues as mapValues2 } from "lodash";
|
|
1218
1266
|
|
|
1219
1267
|
// src/functions/create-world-element.ts
|
|
1268
|
+
import { createBrowserSafeId } from "@vizij/utils";
|
|
1220
1269
|
function createDefaultGroup(partialBody) {
|
|
1221
1270
|
const translation = partialBody.features?.translation || { animated: false, value: { x: 0, y: 0 } };
|
|
1222
1271
|
const rotation = partialBody.features?.rotation || { animated: false, value: { x: 0, y: 0, z: 0 } };
|
|
1223
1272
|
const scale = partialBody.features?.scale || { animated: false, value: { x: 1, y: 1, z: 1 } };
|
|
1224
1273
|
return {
|
|
1225
|
-
id: partialBody.id ||
|
|
1274
|
+
id: partialBody.id || createBrowserSafeId(),
|
|
1226
1275
|
name: partialBody.name || "new-body",
|
|
1227
1276
|
type: partialBody.type || "group",
|
|
1228
1277
|
tags: partialBody.tags || [],
|
|
@@ -1283,7 +1332,32 @@ function removeFromTree(state, nodesToRemove) {
|
|
|
1283
1332
|
});
|
|
1284
1333
|
}
|
|
1285
1334
|
|
|
1335
|
+
// src/memoryInvestigation.ts
|
|
1336
|
+
function getGlobalMemoryInvestigation() {
|
|
1337
|
+
return globalThis;
|
|
1338
|
+
}
|
|
1339
|
+
function updateRenderState(updater) {
|
|
1340
|
+
const globalObj = getGlobalMemoryInvestigation();
|
|
1341
|
+
if (!globalObj.__VIZIJ_MEMORY_INVESTIGATION__?.enabled) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
if (!globalObj.__vizijMemoryDebugState) {
|
|
1345
|
+
globalObj.__vizijMemoryDebugState = {};
|
|
1346
|
+
}
|
|
1347
|
+
if (!globalObj.__vizijMemoryDebugState.render) {
|
|
1348
|
+
globalObj.__vizijMemoryDebugState.render = {};
|
|
1349
|
+
}
|
|
1350
|
+
updater(globalObj.__vizijMemoryDebugState.render);
|
|
1351
|
+
}
|
|
1352
|
+
function recordRenderCounter(key, delta = 1) {
|
|
1353
|
+
updateRenderState((renderState) => {
|
|
1354
|
+
const current = typeof renderState[key] === "number" ? Number(renderState[key]) : 0;
|
|
1355
|
+
renderState[key] = current + delta;
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1286
1359
|
// src/functions/create-animatable.ts
|
|
1360
|
+
import { createBrowserSafeId as createBrowserSafeId2 } from "@vizij/utils";
|
|
1287
1361
|
function createAnimatable(value) {
|
|
1288
1362
|
if (!value.type) {
|
|
1289
1363
|
return null;
|
|
@@ -1293,7 +1367,7 @@ function createAnimatable(value) {
|
|
|
1293
1367
|
}
|
|
1294
1368
|
if (value.type === "euler") {
|
|
1295
1369
|
const newAnimatable = {
|
|
1296
|
-
id: value.id ??
|
|
1370
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1297
1371
|
name: `${value.name} Rotation`,
|
|
1298
1372
|
type: value.type,
|
|
1299
1373
|
default: value.default ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1310,7 +1384,7 @@ function createAnimatable(value) {
|
|
|
1310
1384
|
return newAnimatable;
|
|
1311
1385
|
} else if (value.type === "vector3") {
|
|
1312
1386
|
const newAnimatable = {
|
|
1313
|
-
id: value.id ??
|
|
1387
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1314
1388
|
name: `${value.name} Vector3`,
|
|
1315
1389
|
type: value.type,
|
|
1316
1390
|
default: value.default ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1327,7 +1401,7 @@ function createAnimatable(value) {
|
|
|
1327
1401
|
return newAnimatable;
|
|
1328
1402
|
} else if (value.type === "string") {
|
|
1329
1403
|
const newAnimatable = {
|
|
1330
|
-
id: value.id ??
|
|
1404
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1331
1405
|
name: value.name,
|
|
1332
1406
|
type: value.type,
|
|
1333
1407
|
default: value.default ?? "Hello World",
|
|
@@ -1340,7 +1414,7 @@ function createAnimatable(value) {
|
|
|
1340
1414
|
return newAnimatable;
|
|
1341
1415
|
} else if (value.type === "number") {
|
|
1342
1416
|
const newAnimatable = {
|
|
1343
|
-
id: value.id ??
|
|
1417
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1344
1418
|
name: value.name,
|
|
1345
1419
|
type: value.type,
|
|
1346
1420
|
default: value.default ?? 0,
|
|
@@ -1353,7 +1427,7 @@ function createAnimatable(value) {
|
|
|
1353
1427
|
return newAnimatable;
|
|
1354
1428
|
} else if (value.type === "boolean") {
|
|
1355
1429
|
const newAnimatable = {
|
|
1356
|
-
id: value.id ??
|
|
1430
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1357
1431
|
name: value.name,
|
|
1358
1432
|
type: value.type,
|
|
1359
1433
|
default: value.default ?? false,
|
|
@@ -1366,7 +1440,7 @@ function createAnimatable(value) {
|
|
|
1366
1440
|
return newAnimatable;
|
|
1367
1441
|
} else if (value.type === "rgb") {
|
|
1368
1442
|
const newAnimatable = {
|
|
1369
|
-
id: value.id ??
|
|
1443
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1370
1444
|
name: value.name,
|
|
1371
1445
|
type: value.type,
|
|
1372
1446
|
default: value.default ?? { r: 0, g: 0, b: 0 },
|
|
@@ -1383,7 +1457,7 @@ function createAnimatable(value) {
|
|
|
1383
1457
|
return newAnimatable;
|
|
1384
1458
|
} else if (value.type === "hsl") {
|
|
1385
1459
|
const newAnimatable = {
|
|
1386
|
-
id: value.id ??
|
|
1460
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1387
1461
|
name: value.name,
|
|
1388
1462
|
type: value.type,
|
|
1389
1463
|
default: value.default ?? { h: 0, s: 0, l: 0 },
|
|
@@ -1403,6 +1477,35 @@ function createAnimatable(value) {
|
|
|
1403
1477
|
}
|
|
1404
1478
|
createAnimatable({ type: "euler", name: "Rotation" });
|
|
1405
1479
|
|
|
1480
|
+
// src/functions/exportable-bodies.ts
|
|
1481
|
+
function asGroupEntries(world) {
|
|
1482
|
+
return Object.values(world).filter((entry) => entry.type === "group");
|
|
1483
|
+
}
|
|
1484
|
+
function selectExportableGroupEntries(world, filterIds) {
|
|
1485
|
+
const groupEntries = asGroupEntries(world);
|
|
1486
|
+
const filterSet = Array.isArray(filterIds) && filterIds.length > 0 ? new Set(filterIds) : null;
|
|
1487
|
+
if (filterSet) {
|
|
1488
|
+
return groupEntries.filter((entry) => filterSet.has(entry.id));
|
|
1489
|
+
}
|
|
1490
|
+
const rootBoundsGroups = groupEntries.filter(
|
|
1491
|
+
(entry) => Boolean(entry.rootBounds)
|
|
1492
|
+
);
|
|
1493
|
+
if (rootBoundsGroups.length > 0) {
|
|
1494
|
+
return rootBoundsGroups;
|
|
1495
|
+
}
|
|
1496
|
+
const explicitRootGroups = groupEntries.filter(
|
|
1497
|
+
(entry) => entry.root === true
|
|
1498
|
+
);
|
|
1499
|
+
if (explicitRootGroups.length > 0) {
|
|
1500
|
+
return explicitRootGroups;
|
|
1501
|
+
}
|
|
1502
|
+
const topLevelGroups = groupEntries.filter((entry) => !entry.parent);
|
|
1503
|
+
if (topLevelGroups.length > 0) {
|
|
1504
|
+
return topLevelGroups;
|
|
1505
|
+
}
|
|
1506
|
+
return groupEntries;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1406
1509
|
// src/store.ts
|
|
1407
1510
|
THREE3.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
1408
1511
|
enableMapSet();
|
|
@@ -1478,23 +1581,17 @@ var VizijSlice = (set, get) => ({
|
|
|
1478
1581
|
},
|
|
1479
1582
|
getExportableBodies: (filterIds) => {
|
|
1480
1583
|
const worldData = get().world;
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
const firstNs = Object.keys(entry.refs)[0];
|
|
1493
|
-
const refGroup = entry.refs[firstNs].current;
|
|
1494
|
-
return refGroup;
|
|
1495
|
-
});
|
|
1496
|
-
return bodies;
|
|
1497
|
-
}
|
|
1584
|
+
const candidateGroups = selectExportableGroupEntries(
|
|
1585
|
+
worldData,
|
|
1586
|
+
filterIds
|
|
1587
|
+
);
|
|
1588
|
+
return candidateGroups.flatMap((entry) => {
|
|
1589
|
+
const refs = Object.values(
|
|
1590
|
+
entry.refs ?? {}
|
|
1591
|
+
);
|
|
1592
|
+
const resolved = refs.find((ref) => ref?.current)?.current ?? null;
|
|
1593
|
+
return resolved ? [resolved] : [];
|
|
1594
|
+
});
|
|
1498
1595
|
},
|
|
1499
1596
|
setGeometry: (id, geometry) => {
|
|
1500
1597
|
set(
|
|
@@ -1692,6 +1789,7 @@ var VizijSlice = (set, get) => ({
|
|
|
1692
1789
|
);
|
|
1693
1790
|
},
|
|
1694
1791
|
setVizij: (scene, animatables) => {
|
|
1792
|
+
recordRenderCounter("rootReplacementCount");
|
|
1695
1793
|
set({
|
|
1696
1794
|
world: scene,
|
|
1697
1795
|
animatables
|
|
@@ -1699,6 +1797,7 @@ var VizijSlice = (set, get) => ({
|
|
|
1699
1797
|
},
|
|
1700
1798
|
addWorldElements(world, animatables, replace) {
|
|
1701
1799
|
if (replace) {
|
|
1800
|
+
recordRenderCounter("rootReplacementCount");
|
|
1702
1801
|
set({ world, animatables });
|
|
1703
1802
|
} else {
|
|
1704
1803
|
set((state) => ({
|
|
@@ -1751,7 +1850,7 @@ import {
|
|
|
1751
1850
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1752
1851
|
function SelectionGlowEffect({
|
|
1753
1852
|
enabled = false,
|
|
1754
|
-
color = "#
|
|
1853
|
+
color = "#ff1010",
|
|
1755
1854
|
opacity = 0.9,
|
|
1756
1855
|
thresholdAngle = 2
|
|
1757
1856
|
}) {
|
|
@@ -1857,6 +1956,13 @@ function Vizij({
|
|
|
1857
1956
|
onPointerMissed
|
|
1858
1957
|
}) {
|
|
1859
1958
|
const ctx = useContext3(VizijContext);
|
|
1959
|
+
useEffect7(() => {
|
|
1960
|
+
recordRenderCounter("canvasMountCount");
|
|
1961
|
+
recordRenderCounter("mountedCanvasCount");
|
|
1962
|
+
return () => {
|
|
1963
|
+
recordRenderCounter("mountedCanvasCount", -1);
|
|
1964
|
+
};
|
|
1965
|
+
}, []);
|
|
1860
1966
|
if (ctx) {
|
|
1861
1967
|
return /* @__PURE__ */ jsx7(
|
|
1862
1968
|
Canvas,
|
|
@@ -1925,7 +2031,7 @@ function InnerVizij({
|
|
|
1925
2031
|
makeDefault: true,
|
|
1926
2032
|
position: [0, 0, 100],
|
|
1927
2033
|
near: 0.1,
|
|
1928
|
-
far:
|
|
2034
|
+
far: 1e3
|
|
1929
2035
|
}
|
|
1930
2036
|
),
|
|
1931
2037
|
/* @__PURE__ */ jsx7(Suspense, { fallback: null, children: /* @__PURE__ */ jsx7(
|
|
@@ -2103,6 +2209,7 @@ import { Object3D as Object3D7 } from "three";
|
|
|
2103
2209
|
|
|
2104
2210
|
// src/functions/gltf-loading/import-group.ts
|
|
2105
2211
|
import { Object3D as Object3D6 } from "three";
|
|
2212
|
+
import { createBrowserSafeId as createBrowserSafeId5 } from "@vizij/utils";
|
|
2106
2213
|
|
|
2107
2214
|
// src/functions/util.ts
|
|
2108
2215
|
import { createRef as createRef2 } from "react";
|
|
@@ -2112,8 +2219,12 @@ function namespaceArrayToRefs(namespaces) {
|
|
|
2112
2219
|
|
|
2113
2220
|
// src/functions/gltf-loading/import-mesh.ts
|
|
2114
2221
|
import { Object3D as Object3D5 } from "three";
|
|
2222
|
+
import { createBrowserSafeId as createBrowserSafeId4 } from "@vizij/utils";
|
|
2115
2223
|
|
|
2116
2224
|
// src/functions/gltf-loading/import-geometry.ts
|
|
2225
|
+
import {
|
|
2226
|
+
createBrowserSafeId as createBrowserSafeId3
|
|
2227
|
+
} from "@vizij/utils";
|
|
2117
2228
|
function sanitizeMorphKey(name, fallbackIndex, used) {
|
|
2118
2229
|
const baseName = name && name.trim().length > 0 ? name.trim() : `morph_${fallbackIndex + 1}`;
|
|
2119
2230
|
const slug = baseName.toLowerCase().replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "");
|
|
@@ -2137,7 +2248,7 @@ function importGeometry(geometry, mesh) {
|
|
|
2137
2248
|
const usedKeys = /* @__PURE__ */ new Set();
|
|
2138
2249
|
Object.entries(mesh.morphTargetDictionary ?? {}).forEach(
|
|
2139
2250
|
([name, index]) => {
|
|
2140
|
-
const morphId =
|
|
2251
|
+
const morphId = createBrowserSafeId3();
|
|
2141
2252
|
const featureKey = sanitizeMorphKey(name, index, usedKeys);
|
|
2142
2253
|
morphIds.push(featureKey);
|
|
2143
2254
|
features[featureKey] = {
|
|
@@ -2173,7 +2284,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2173
2284
|
let animatables = {};
|
|
2174
2285
|
let newColorLookup = {};
|
|
2175
2286
|
const translationAnimatable = {
|
|
2176
|
-
id:
|
|
2287
|
+
id: createBrowserSafeId4(),
|
|
2177
2288
|
name: `${mesh.name ?? "Mesh"} translation`,
|
|
2178
2289
|
type: "vector3",
|
|
2179
2290
|
default: { x: mesh.position.x, y: mesh.position.y, z: mesh.position.z },
|
|
@@ -2189,7 +2300,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2189
2300
|
[translationAnimatable.id]: translationAnimatable
|
|
2190
2301
|
};
|
|
2191
2302
|
const rotationAnimatable = {
|
|
2192
|
-
id:
|
|
2303
|
+
id: createBrowserSafeId4(),
|
|
2193
2304
|
name: `${mesh.name ?? "Mesh"} rotation`,
|
|
2194
2305
|
type: "euler",
|
|
2195
2306
|
default: { x: mesh.rotation.x, y: mesh.rotation.y, z: mesh.rotation.z },
|
|
@@ -2202,7 +2313,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2202
2313
|
};
|
|
2203
2314
|
animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
|
|
2204
2315
|
const scaleAnimatable = {
|
|
2205
|
-
id:
|
|
2316
|
+
id: createBrowserSafeId4(),
|
|
2206
2317
|
name: `${mesh.name ?? "Mesh"} scale`,
|
|
2207
2318
|
type: "vector3",
|
|
2208
2319
|
default: { x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z },
|
|
@@ -2213,56 +2324,120 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2213
2324
|
}
|
|
2214
2325
|
};
|
|
2215
2326
|
animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
|
|
2216
|
-
const
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
type: "rgb",
|
|
2227
|
-
default: { r: color.r, g: color.g, b: color.b },
|
|
2228
|
-
constraints: {
|
|
2229
|
-
min: [0, 0, 0],
|
|
2230
|
-
max: [1, 1, 1]
|
|
2231
|
-
},
|
|
2327
|
+
const material = mesh.material;
|
|
2328
|
+
const color = material.color;
|
|
2329
|
+
const colorName = material.name;
|
|
2330
|
+
const label = (suffix) => colorName ? `${colorName} ${suffix}` : `${mesh.name ?? "Mesh"} ${suffix}`;
|
|
2331
|
+
const makeNumberAnimatable = (suffix, value, constraints) => ({
|
|
2332
|
+
id: createBrowserSafeId4(),
|
|
2333
|
+
name: label(suffix),
|
|
2334
|
+
type: "number",
|
|
2335
|
+
default: value,
|
|
2336
|
+
constraints,
|
|
2232
2337
|
pub: {
|
|
2233
2338
|
public: true,
|
|
2234
|
-
output:
|
|
2339
|
+
output: label(suffix)
|
|
2235
2340
|
}
|
|
2236
|
-
};
|
|
2237
|
-
const
|
|
2238
|
-
id:
|
|
2239
|
-
name:
|
|
2240
|
-
type: "
|
|
2241
|
-
default:
|
|
2341
|
+
});
|
|
2342
|
+
const makeColorAnimatable = (suffix, value) => ({
|
|
2343
|
+
id: createBrowserSafeId4(),
|
|
2344
|
+
name: label(suffix),
|
|
2345
|
+
type: "rgb",
|
|
2346
|
+
default: { r: value.r, g: value.g, b: value.b },
|
|
2242
2347
|
constraints: {
|
|
2243
|
-
min: 0,
|
|
2244
|
-
max: 1
|
|
2348
|
+
min: [0, 0, 0],
|
|
2349
|
+
max: [1, 1, 1]
|
|
2245
2350
|
},
|
|
2246
2351
|
pub: {
|
|
2247
2352
|
public: true,
|
|
2248
|
-
output:
|
|
2353
|
+
output: label(suffix)
|
|
2249
2354
|
}
|
|
2355
|
+
});
|
|
2356
|
+
const colorAnimatable = {
|
|
2357
|
+
...makeColorAnimatable("color", color),
|
|
2358
|
+
name: material.name ?? `${mesh.name ?? "Mesh"} color`
|
|
2250
2359
|
};
|
|
2251
|
-
|
|
2252
|
-
|
|
2360
|
+
const opacityAnimatable = makeNumberAnimatable("opacity", material.opacity, {
|
|
2361
|
+
min: 0,
|
|
2362
|
+
max: 1
|
|
2363
|
+
});
|
|
2364
|
+
const materialAnimatables = [
|
|
2365
|
+
colorAnimatable,
|
|
2366
|
+
opacityAnimatable
|
|
2367
|
+
];
|
|
2368
|
+
let roughnessAnimatable;
|
|
2369
|
+
let metalnessAnimatable;
|
|
2370
|
+
let emissiveAnimatable;
|
|
2371
|
+
let emissiveIntensityAnimatable;
|
|
2372
|
+
let shininessAnimatable;
|
|
2373
|
+
let specularAnimatable;
|
|
2374
|
+
if (material.isMeshStandardMaterial) {
|
|
2375
|
+
roughnessAnimatable = makeNumberAnimatable(
|
|
2376
|
+
"roughness",
|
|
2377
|
+
material.roughness,
|
|
2378
|
+
{
|
|
2379
|
+
min: 0,
|
|
2380
|
+
max: 1
|
|
2381
|
+
}
|
|
2382
|
+
);
|
|
2383
|
+
metalnessAnimatable = makeNumberAnimatable(
|
|
2384
|
+
"metalness",
|
|
2385
|
+
material.metalness,
|
|
2386
|
+
{
|
|
2387
|
+
min: 0,
|
|
2388
|
+
max: 1
|
|
2389
|
+
}
|
|
2390
|
+
);
|
|
2391
|
+
emissiveAnimatable = makeColorAnimatable("emissive", material.emissive);
|
|
2392
|
+
emissiveIntensityAnimatable = makeNumberAnimatable(
|
|
2393
|
+
"emissive intensity",
|
|
2394
|
+
material.emissiveIntensity,
|
|
2395
|
+
{ min: 0 }
|
|
2396
|
+
);
|
|
2397
|
+
materialAnimatables.push(
|
|
2398
|
+
roughnessAnimatable,
|
|
2399
|
+
metalnessAnimatable,
|
|
2400
|
+
emissiveAnimatable,
|
|
2401
|
+
emissiveIntensityAnimatable
|
|
2402
|
+
);
|
|
2403
|
+
} else if (mesh.material.isMeshPhongMaterial) {
|
|
2404
|
+
const phong = mesh.material;
|
|
2405
|
+
shininessAnimatable = makeNumberAnimatable("shininess", phong.shininess, {
|
|
2406
|
+
min: 0
|
|
2407
|
+
});
|
|
2408
|
+
emissiveAnimatable = makeColorAnimatable("emissive", phong.emissive);
|
|
2409
|
+
emissiveIntensityAnimatable = makeNumberAnimatable(
|
|
2410
|
+
"emissive intensity",
|
|
2411
|
+
phong.emissiveIntensity,
|
|
2412
|
+
{ min: 0 }
|
|
2413
|
+
);
|
|
2414
|
+
specularAnimatable = makeColorAnimatable("specular", phong.specular);
|
|
2415
|
+
materialAnimatables.push(
|
|
2416
|
+
shininessAnimatable,
|
|
2417
|
+
emissiveAnimatable,
|
|
2418
|
+
emissiveIntensityAnimatable,
|
|
2419
|
+
specularAnimatable
|
|
2420
|
+
);
|
|
2421
|
+
}
|
|
2422
|
+
let materialIds;
|
|
2253
2423
|
if (colorName && colorLookup[colorName]) {
|
|
2254
|
-
|
|
2255
|
-
opacityId = colorLookup[colorName][1];
|
|
2256
|
-
useEmissive = colorLookup[colorName][2];
|
|
2424
|
+
materialIds = colorLookup[colorName];
|
|
2257
2425
|
} else {
|
|
2258
|
-
|
|
2259
|
-
|
|
2426
|
+
materialIds = {
|
|
2427
|
+
color: colorAnimatable.id,
|
|
2428
|
+
opacity: opacityAnimatable.id,
|
|
2429
|
+
roughness: roughnessAnimatable?.id,
|
|
2430
|
+
metalness: metalnessAnimatable?.id,
|
|
2431
|
+
emissive: emissiveAnimatable?.id,
|
|
2432
|
+
emissiveIntensity: emissiveIntensityAnimatable?.id,
|
|
2433
|
+
shininess: shininessAnimatable?.id,
|
|
2434
|
+
specular: specularAnimatable?.id
|
|
2435
|
+
};
|
|
2436
|
+
materialAnimatables.forEach((animatable) => {
|
|
2437
|
+
animatables = { ...animatables, [animatable.id]: animatable };
|
|
2438
|
+
});
|
|
2260
2439
|
if (colorName) {
|
|
2261
|
-
newColorLookup[colorName] =
|
|
2262
|
-
colorAnimatable.id,
|
|
2263
|
-
opacityAnimatable.id,
|
|
2264
|
-
useEmissive
|
|
2265
|
-
];
|
|
2440
|
+
newColorLookup[colorName] = materialIds;
|
|
2266
2441
|
}
|
|
2267
2442
|
}
|
|
2268
2443
|
const [geometryFeatures, geometryAnimatables, morphTargets] = importGeometry(
|
|
@@ -2281,13 +2456,22 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2281
2456
|
world = { ...world, ...newWorldItems };
|
|
2282
2457
|
animatables = { ...animatables, ...newAnimatables };
|
|
2283
2458
|
children.push(childId);
|
|
2459
|
+
} else if (shouldImportAsGroupChild(child)) {
|
|
2460
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
|
|
2461
|
+
...colorLookup,
|
|
2462
|
+
...newColorLookup
|
|
2463
|
+
});
|
|
2464
|
+
newColorLookup = { ...newColorLookup, ...newMeshColors };
|
|
2465
|
+
world = { ...world, ...newWorldItems };
|
|
2466
|
+
animatables = { ...animatables, ...newAnimatables };
|
|
2467
|
+
children.push(childId);
|
|
2284
2468
|
}
|
|
2285
2469
|
});
|
|
2286
2470
|
const newShape = {
|
|
2287
2471
|
id: mesh.uuid,
|
|
2288
2472
|
name: mesh.name,
|
|
2289
2473
|
geometry: mesh.geometry,
|
|
2290
|
-
material: getShapeMaterial(mesh
|
|
2474
|
+
material: getShapeMaterial(mesh),
|
|
2291
2475
|
type: "shape",
|
|
2292
2476
|
tags: [],
|
|
2293
2477
|
morphTargets,
|
|
@@ -2295,8 +2479,19 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2295
2479
|
translation: { animated: true, value: translationAnimatable.id },
|
|
2296
2480
|
rotation: { animated: true, value: rotationAnimatable.id },
|
|
2297
2481
|
scale: { animated: true, value: scaleAnimatable.id },
|
|
2298
|
-
color: { animated: true, value:
|
|
2299
|
-
opacity: { animated: true, value:
|
|
2482
|
+
color: { animated: true, value: materialIds.color },
|
|
2483
|
+
opacity: { animated: true, value: materialIds.opacity },
|
|
2484
|
+
...materialIds.roughness ? { roughness: { animated: true, value: materialIds.roughness } } : {},
|
|
2485
|
+
...materialIds.metalness ? { metalness: { animated: true, value: materialIds.metalness } } : {},
|
|
2486
|
+
...materialIds.emissive ? { emissive: { animated: true, value: materialIds.emissive } } : {},
|
|
2487
|
+
...materialIds.emissiveIntensity ? {
|
|
2488
|
+
emissiveIntensity: {
|
|
2489
|
+
animated: true,
|
|
2490
|
+
value: materialIds.emissiveIntensity
|
|
2491
|
+
}
|
|
2492
|
+
} : {},
|
|
2493
|
+
...materialIds.shininess ? { shininess: { animated: true, value: materialIds.shininess } } : {},
|
|
2494
|
+
...materialIds.specular ? { specular: { animated: true, value: materialIds.specular } } : {},
|
|
2300
2495
|
...geometryFeatures
|
|
2301
2496
|
},
|
|
2302
2497
|
children: children.length > 0 ? children : void 0,
|
|
@@ -2305,11 +2500,8 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2305
2500
|
world = { ...world, [newShape.id]: newShape };
|
|
2306
2501
|
return [world, animatables, newShape.id, newColorLookup];
|
|
2307
2502
|
}
|
|
2308
|
-
function getShapeMaterial(mesh
|
|
2503
|
+
function getShapeMaterial(mesh) {
|
|
2309
2504
|
const material = mesh.material;
|
|
2310
|
-
if (useEmissive) {
|
|
2311
|
-
return "basic" /* Basic */;
|
|
2312
|
-
}
|
|
2313
2505
|
if (material.isMeshStandardMaterial) {
|
|
2314
2506
|
return "standard" /* Standard */;
|
|
2315
2507
|
} else if (material.isMeshPhongMaterial) {
|
|
@@ -2324,6 +2516,24 @@ function getShapeMaterial(mesh, useEmissive) {
|
|
|
2324
2516
|
return "standard" /* Standard */;
|
|
2325
2517
|
}
|
|
2326
2518
|
}
|
|
2519
|
+
function shouldImportAsGroupChild(child) {
|
|
2520
|
+
if (!child.isObject3D) {
|
|
2521
|
+
return false;
|
|
2522
|
+
}
|
|
2523
|
+
if (child.isMesh) {
|
|
2524
|
+
return false;
|
|
2525
|
+
}
|
|
2526
|
+
if (child.isCamera) {
|
|
2527
|
+
return false;
|
|
2528
|
+
}
|
|
2529
|
+
if (child.isLight) {
|
|
2530
|
+
return false;
|
|
2531
|
+
}
|
|
2532
|
+
if (child.isBone) {
|
|
2533
|
+
return false;
|
|
2534
|
+
}
|
|
2535
|
+
return true;
|
|
2536
|
+
}
|
|
2327
2537
|
|
|
2328
2538
|
// src/functions/gltf-loading/import-group.ts
|
|
2329
2539
|
Object3D6.DEFAULT_UP.set(0, 0, 1);
|
|
@@ -2333,7 +2543,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2333
2543
|
let newColorLookup = {};
|
|
2334
2544
|
const children = [];
|
|
2335
2545
|
const translationAnimatable = {
|
|
2336
|
-
id:
|
|
2546
|
+
id: createBrowserSafeId5(),
|
|
2337
2547
|
name: `${group.name ?? "Group"} translation`,
|
|
2338
2548
|
type: "vector3",
|
|
2339
2549
|
default: { x: group.position.x, y: group.position.y, z: group.position.z },
|
|
@@ -2349,7 +2559,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2349
2559
|
[translationAnimatable.id]: translationAnimatable
|
|
2350
2560
|
};
|
|
2351
2561
|
const rotationAnimatable = {
|
|
2352
|
-
id:
|
|
2562
|
+
id: createBrowserSafeId5(),
|
|
2353
2563
|
name: `${group.name ?? "Group"} rotation`,
|
|
2354
2564
|
type: "euler",
|
|
2355
2565
|
default: { x: group.rotation.x, y: group.rotation.y, z: group.rotation.z },
|
|
@@ -2362,7 +2572,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2362
2572
|
};
|
|
2363
2573
|
animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
|
|
2364
2574
|
const scaleAnimatable = {
|
|
2365
|
-
id:
|
|
2575
|
+
id: createBrowserSafeId5(),
|
|
2366
2576
|
name: `${group.name ?? "Group"} scale`,
|
|
2367
2577
|
type: "vector3",
|
|
2368
2578
|
default: { x: group.scale.x, y: group.scale.y, z: group.scale.z },
|
|
@@ -2383,7 +2593,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2383
2593
|
world = { ...world, ...newWorldItems };
|
|
2384
2594
|
animatables = { ...animatables, ...newAnimatables };
|
|
2385
2595
|
children.push(childId);
|
|
2386
|
-
} else if (child
|
|
2596
|
+
} else if (shouldImportAsGroupChild2(child)) {
|
|
2387
2597
|
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
|
|
2388
2598
|
...colorLookup,
|
|
2389
2599
|
...newColorLookup
|
|
@@ -2412,6 +2622,24 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2412
2622
|
world = { ...world, [newGroup.id]: newGroup };
|
|
2413
2623
|
return [world, animatables, newGroup.id, newColorLookup];
|
|
2414
2624
|
}
|
|
2625
|
+
function shouldImportAsGroupChild2(child) {
|
|
2626
|
+
if (!child.isObject3D) {
|
|
2627
|
+
return false;
|
|
2628
|
+
}
|
|
2629
|
+
if (child.isMesh) {
|
|
2630
|
+
return false;
|
|
2631
|
+
}
|
|
2632
|
+
if (child.isCamera) {
|
|
2633
|
+
return false;
|
|
2634
|
+
}
|
|
2635
|
+
if (child.isLight) {
|
|
2636
|
+
return false;
|
|
2637
|
+
}
|
|
2638
|
+
if (child.isBone) {
|
|
2639
|
+
return false;
|
|
2640
|
+
}
|
|
2641
|
+
return true;
|
|
2642
|
+
}
|
|
2415
2643
|
|
|
2416
2644
|
// src/functions/gltf-loading/import-scene.ts
|
|
2417
2645
|
Object3D7.DEFAULT_UP.set(0, 0, 1);
|
|
@@ -2537,7 +2765,10 @@ var MATERIAL_NAME_FEATURE_KEYS = [
|
|
|
2537
2765
|
"opacity",
|
|
2538
2766
|
"roughness",
|
|
2539
2767
|
"metalness",
|
|
2540
|
-
"shininess"
|
|
2768
|
+
"shininess",
|
|
2769
|
+
"emissive",
|
|
2770
|
+
"emissiveIntensity",
|
|
2771
|
+
"specular"
|
|
2541
2772
|
];
|
|
2542
2773
|
var MATERIAL_NAME_SUFFIXES2 = [
|
|
2543
2774
|
" color",
|
|
@@ -2546,7 +2777,10 @@ var MATERIAL_NAME_SUFFIXES2 = [
|
|
|
2546
2777
|
" opacity",
|
|
2547
2778
|
" roughness",
|
|
2548
2779
|
" metalness",
|
|
2549
|
-
" shininess"
|
|
2780
|
+
" shininess",
|
|
2781
|
+
" emissive intensity",
|
|
2782
|
+
" emissive",
|
|
2783
|
+
" specular"
|
|
2550
2784
|
];
|
|
2551
2785
|
function applyStoredRenderableNames(object, data) {
|
|
2552
2786
|
if (typeof data.name === "string" && data.name.length > 0) {
|
|
@@ -2722,6 +2956,13 @@ function searchParserJsonForBundle(parserJson) {
|
|
|
2722
2956
|
if (!parserJson || typeof parserJson !== "object") {
|
|
2723
2957
|
return null;
|
|
2724
2958
|
}
|
|
2959
|
+
const rootExtensions = parserJson && typeof parserJson === "object" ? parserJson.extensions : null;
|
|
2960
|
+
if (rootExtensions && typeof rootExtensions === "object") {
|
|
2961
|
+
const match = readExtensionValue(rootExtensions);
|
|
2962
|
+
if (match) {
|
|
2963
|
+
return cloneBundle(match.value);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2725
2966
|
const nodes = Array.isArray(parserJson.nodes) ? parserJson.nodes : [];
|
|
2726
2967
|
for (const node of nodes) {
|
|
2727
2968
|
const extensions = node && typeof node === "object" ? node.extensions : null;
|
|
@@ -2759,12 +3000,29 @@ function applyVizijBundle(object, bundle) {
|
|
|
2759
3000
|
const userData = object.userData && typeof object.userData === "object" ? object.userData : {};
|
|
2760
3001
|
const originalExtensions = userData.gltfExtensions;
|
|
2761
3002
|
let applied = false;
|
|
3003
|
+
const staleCarriers = [];
|
|
2762
3004
|
if (bundle) {
|
|
2763
3005
|
userData.gltfExtensions = {
|
|
2764
3006
|
...originalExtensions ?? {},
|
|
2765
3007
|
VIZIJ_bundle: bundle
|
|
2766
3008
|
};
|
|
2767
3009
|
object.userData = userData;
|
|
3010
|
+
object.traverse((node) => {
|
|
3011
|
+
if (node === object) {
|
|
3012
|
+
return;
|
|
3013
|
+
}
|
|
3014
|
+
const extensions = node.userData?.gltfExtensions;
|
|
3015
|
+
if (!extensions || !(BUNDLE_KEYS[0] in extensions)) {
|
|
3016
|
+
return;
|
|
3017
|
+
}
|
|
3018
|
+
staleCarriers.push({ node, extensions });
|
|
3019
|
+
const { [BUNDLE_KEYS[0]]: _stale, ...rest } = extensions;
|
|
3020
|
+
if (Object.keys(rest).length > 0) {
|
|
3021
|
+
node.userData.gltfExtensions = rest;
|
|
3022
|
+
} else {
|
|
3023
|
+
delete node.userData.gltfExtensions;
|
|
3024
|
+
}
|
|
3025
|
+
});
|
|
2768
3026
|
applied = true;
|
|
2769
3027
|
}
|
|
2770
3028
|
return () => {
|
|
@@ -2781,6 +3039,10 @@ function applyVizijBundle(object, bundle) {
|
|
|
2781
3039
|
delete object.userData;
|
|
2782
3040
|
}
|
|
2783
3041
|
}
|
|
3042
|
+
for (const { node, extensions } of staleCarriers) {
|
|
3043
|
+
node.userData.gltfExtensions = extensions;
|
|
3044
|
+
}
|
|
3045
|
+
staleCarriers.length = 0;
|
|
2784
3046
|
applied = false;
|
|
2785
3047
|
};
|
|
2786
3048
|
}
|
|
@@ -3157,24 +3419,87 @@ function extractVizijAnimations(parserJson, clips) {
|
|
|
3157
3419
|
|
|
3158
3420
|
// src/functions/load-gltf.ts
|
|
3159
3421
|
THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
3422
|
+
var GLB_MAGIC = 1179937895;
|
|
3423
|
+
var GLB_VERSION = 2;
|
|
3424
|
+
var GLB_HEADER_BYTES = 12;
|
|
3425
|
+
var GLB_CHUNK_HEADER_BYTES = 8;
|
|
3426
|
+
var GLB_JSON_CHUNK_TYPE = 1313821514;
|
|
3160
3427
|
var EmptyModelError = class extends Error {
|
|
3161
3428
|
constructor(message) {
|
|
3162
3429
|
super(message);
|
|
3163
3430
|
this.name = "EmptyModelError";
|
|
3164
3431
|
}
|
|
3165
3432
|
};
|
|
3433
|
+
function parseGlbJsonChunk(buffer) {
|
|
3434
|
+
if (buffer.byteLength < GLB_HEADER_BYTES + GLB_CHUNK_HEADER_BYTES) {
|
|
3435
|
+
return void 0;
|
|
3436
|
+
}
|
|
3437
|
+
const view = new DataView(buffer);
|
|
3438
|
+
const magic = view.getUint32(0, true);
|
|
3439
|
+
const version = view.getUint32(4, true);
|
|
3440
|
+
if (magic !== GLB_MAGIC || version !== GLB_VERSION) {
|
|
3441
|
+
return void 0;
|
|
3442
|
+
}
|
|
3443
|
+
const chunkLength = view.getUint32(GLB_HEADER_BYTES, true);
|
|
3444
|
+
const chunkType = view.getUint32(GLB_HEADER_BYTES + 4, true);
|
|
3445
|
+
if (chunkType !== GLB_JSON_CHUNK_TYPE) {
|
|
3446
|
+
return void 0;
|
|
3447
|
+
}
|
|
3448
|
+
const chunkStart = GLB_HEADER_BYTES + GLB_CHUNK_HEADER_BYTES;
|
|
3449
|
+
const chunkEnd = chunkStart + chunkLength;
|
|
3450
|
+
if (chunkEnd > buffer.byteLength) {
|
|
3451
|
+
return void 0;
|
|
3452
|
+
}
|
|
3453
|
+
try {
|
|
3454
|
+
const chunkBytes = new Uint8Array(buffer, chunkStart, chunkLength);
|
|
3455
|
+
const jsonText = new TextDecoder().decode(chunkBytes);
|
|
3456
|
+
return JSON.parse(jsonText);
|
|
3457
|
+
} catch {
|
|
3458
|
+
return void 0;
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
async function resolveParserJson(parserJson, fallback) {
|
|
3462
|
+
if (parserJson && typeof parserJson === "object") {
|
|
3463
|
+
return parserJson;
|
|
3464
|
+
}
|
|
3465
|
+
if (fallback.arrayBuffer) {
|
|
3466
|
+
const fromArrayBuffer = parseGlbJsonChunk(fallback.arrayBuffer);
|
|
3467
|
+
if (fromArrayBuffer && typeof fromArrayBuffer === "object") {
|
|
3468
|
+
return fromArrayBuffer;
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
if (fallback.blob) {
|
|
3472
|
+
try {
|
|
3473
|
+
const blobBuffer = typeof fallback.blob.arrayBuffer === "function" ? await fallback.blob.arrayBuffer() : await new Response(fallback.blob).arrayBuffer();
|
|
3474
|
+
const fromBlob = parseGlbJsonChunk(blobBuffer);
|
|
3475
|
+
if (fromBlob && typeof fromBlob === "object") {
|
|
3476
|
+
return fromBlob;
|
|
3477
|
+
}
|
|
3478
|
+
} catch {
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
if (fallback.url && typeof fetch === "function") {
|
|
3482
|
+
try {
|
|
3483
|
+
const response = await fetch(fallback.url);
|
|
3484
|
+
if (response.ok) {
|
|
3485
|
+
const binary = await response.arrayBuffer();
|
|
3486
|
+
const fromUrl = parseGlbJsonChunk(binary);
|
|
3487
|
+
if (fromUrl && typeof fromUrl === "object") {
|
|
3488
|
+
return fromUrl;
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
} catch {
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
return parserJson;
|
|
3495
|
+
}
|
|
3166
3496
|
async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
3167
|
-
const
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3171
|
-
const asset = parseScene(
|
|
3172
|
-
modelData.scene,
|
|
3173
|
-
actualizedNamespaces,
|
|
3497
|
+
const asset = await loadGLTFWithBundleInternal(
|
|
3498
|
+
url,
|
|
3499
|
+
namespaces,
|
|
3174
3500
|
aggressiveImport,
|
|
3175
3501
|
rootBounds,
|
|
3176
|
-
|
|
3177
|
-
modelData.animations
|
|
3502
|
+
"url"
|
|
3178
3503
|
);
|
|
3179
3504
|
return [asset.world, asset.animatables, asset.animations];
|
|
3180
3505
|
}
|
|
@@ -3183,11 +3508,13 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
3183
3508
|
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
3184
3509
|
const objectUrl = URL.createObjectURL(blob);
|
|
3185
3510
|
try {
|
|
3186
|
-
const asset = await
|
|
3511
|
+
const asset = await loadGLTFWithBundleInternal(
|
|
3187
3512
|
objectUrl,
|
|
3188
3513
|
actualizedNamespaces,
|
|
3189
3514
|
aggressiveImport,
|
|
3190
|
-
rootBounds
|
|
3515
|
+
rootBounds,
|
|
3516
|
+
"blob",
|
|
3517
|
+
{ blob }
|
|
3191
3518
|
);
|
|
3192
3519
|
return [asset.world, asset.animatables, asset.animations];
|
|
3193
3520
|
} finally {
|
|
@@ -3196,19 +3523,22 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
3196
3523
|
}
|
|
3197
3524
|
const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
|
|
3198
3525
|
return new Promise((resolve, reject) => {
|
|
3199
|
-
const loader =
|
|
3200
|
-
loader.setDRACOLoader(new DRACOLoader());
|
|
3526
|
+
const loader = createTrackedGLTFLoader();
|
|
3201
3527
|
loader.parse(
|
|
3202
3528
|
arrayBuffer,
|
|
3203
3529
|
"",
|
|
3204
|
-
(gltf) => {
|
|
3530
|
+
async (gltf) => {
|
|
3205
3531
|
try {
|
|
3532
|
+
const parserJson = await resolveParserJson(
|
|
3533
|
+
gltf?.parser?.json,
|
|
3534
|
+
{ arrayBuffer }
|
|
3535
|
+
);
|
|
3206
3536
|
const asset = parseScene(
|
|
3207
3537
|
gltf.scene,
|
|
3208
3538
|
actualizedNamespaces,
|
|
3209
3539
|
aggressiveImport,
|
|
3210
3540
|
rootBounds,
|
|
3211
|
-
|
|
3541
|
+
parserJson,
|
|
3212
3542
|
gltf.animations
|
|
3213
3543
|
);
|
|
3214
3544
|
resolve([asset.world, asset.animatables, asset.animations]);
|
|
@@ -3235,32 +3565,59 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson,
|
|
|
3235
3565
|
);
|
|
3236
3566
|
const bundle = extractVizijBundle(scene, parserJson);
|
|
3237
3567
|
const animations = extractVizijAnimations(parserJson, clips);
|
|
3238
|
-
return { world, animatables, bundle, animations };
|
|
3568
|
+
return { world, animatables, bundle, animations, scene };
|
|
3239
3569
|
}
|
|
3240
|
-
|
|
3570
|
+
function createTrackedGLTFLoader() {
|
|
3571
|
+
recordRenderCounter("gltfLoadCount");
|
|
3572
|
+
recordRenderCounter("dracoLoaderCreationCount");
|
|
3241
3573
|
const modelLoader = new GLTFLoader();
|
|
3242
3574
|
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
3575
|
+
return modelLoader;
|
|
3576
|
+
}
|
|
3577
|
+
async function loadGLTFWithBundleInternal(url, namespaces, aggressiveImport = false, rootBounds, sourceKind = "url", parserJsonFallback) {
|
|
3578
|
+
if (sourceKind === "url") {
|
|
3579
|
+
recordRenderCounter("gltfUrlLoadCount");
|
|
3580
|
+
} else {
|
|
3581
|
+
recordRenderCounter("gltfBlobLoadCount");
|
|
3582
|
+
}
|
|
3583
|
+
const modelLoader = createTrackedGLTFLoader();
|
|
3243
3584
|
const modelData = await modelLoader.loadAsync(url);
|
|
3585
|
+
const parserJson = await resolveParserJson(modelData?.parser?.json, {
|
|
3586
|
+
url,
|
|
3587
|
+
...parserJsonFallback
|
|
3588
|
+
});
|
|
3244
3589
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3245
3590
|
return parseScene(
|
|
3246
3591
|
modelData.scene,
|
|
3247
3592
|
actualizedNamespaces,
|
|
3248
3593
|
aggressiveImport,
|
|
3249
3594
|
rootBounds,
|
|
3250
|
-
|
|
3595
|
+
parserJson,
|
|
3251
3596
|
modelData.animations
|
|
3252
3597
|
);
|
|
3253
3598
|
}
|
|
3599
|
+
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds, parserJsonFallback) {
|
|
3600
|
+
return loadGLTFWithBundleInternal(
|
|
3601
|
+
url,
|
|
3602
|
+
namespaces,
|
|
3603
|
+
aggressiveImport,
|
|
3604
|
+
rootBounds,
|
|
3605
|
+
"url",
|
|
3606
|
+
parserJsonFallback
|
|
3607
|
+
);
|
|
3608
|
+
}
|
|
3254
3609
|
async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
3255
3610
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3256
3611
|
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
3257
3612
|
const objectUrl = URL.createObjectURL(blob);
|
|
3258
3613
|
try {
|
|
3259
|
-
return await
|
|
3614
|
+
return await loadGLTFWithBundleInternal(
|
|
3260
3615
|
objectUrl,
|
|
3261
3616
|
actualizedNamespaces,
|
|
3262
3617
|
aggressiveImport,
|
|
3263
|
-
rootBounds
|
|
3618
|
+
rootBounds,
|
|
3619
|
+
"blob",
|
|
3620
|
+
{ blob }
|
|
3264
3621
|
);
|
|
3265
3622
|
} finally {
|
|
3266
3623
|
URL.revokeObjectURL(objectUrl);
|
|
@@ -3268,19 +3625,22 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
3268
3625
|
}
|
|
3269
3626
|
const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
|
|
3270
3627
|
return new Promise((resolve, reject) => {
|
|
3271
|
-
const loader =
|
|
3272
|
-
loader.setDRACOLoader(new DRACOLoader());
|
|
3628
|
+
const loader = createTrackedGLTFLoader();
|
|
3273
3629
|
loader.parse(
|
|
3274
3630
|
arrayBuffer,
|
|
3275
3631
|
"",
|
|
3276
|
-
(gltf) => {
|
|
3632
|
+
async (gltf) => {
|
|
3277
3633
|
try {
|
|
3634
|
+
const parserJson = await resolveParserJson(
|
|
3635
|
+
gltf?.parser?.json,
|
|
3636
|
+
{ arrayBuffer }
|
|
3637
|
+
);
|
|
3278
3638
|
const asset = parseScene(
|
|
3279
3639
|
gltf.scene,
|
|
3280
3640
|
actualizedNamespaces,
|
|
3281
3641
|
aggressiveImport,
|
|
3282
3642
|
rootBounds,
|
|
3283
|
-
|
|
3643
|
+
parserJson,
|
|
3284
3644
|
gltf.animations
|
|
3285
3645
|
);
|
|
3286
3646
|
resolve(asset);
|
|
@@ -3302,6 +3662,9 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
3302
3662
|
// src/functions/load-gltf-blob.ts
|
|
3303
3663
|
import { DRACOLoader as DRACOLoader2, GLTFLoader as GLTFLoader2 } from "three-stdlib";
|
|
3304
3664
|
var loadGltfFromBlob = (blob, namespaces) => {
|
|
3665
|
+
recordRenderCounter("gltfLoadCount");
|
|
3666
|
+
recordRenderCounter("gltfBlobLoadCount");
|
|
3667
|
+
recordRenderCounter("dracoLoaderCreationCount");
|
|
3305
3668
|
return new Promise((resolve, reject) => {
|
|
3306
3669
|
const loader = new GLTFLoader2();
|
|
3307
3670
|
loader.setDRACOLoader(new DRACOLoader2());
|
|
@@ -3332,6 +3695,160 @@ var loadGltfFromBlob = (blob, namespaces) => {
|
|
|
3332
3695
|
import { GLTFExporter } from "three-stdlib";
|
|
3333
3696
|
import * as THREE6 from "three";
|
|
3334
3697
|
THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
3698
|
+
function normalizeExportError(error) {
|
|
3699
|
+
if (error instanceof Error) {
|
|
3700
|
+
return error;
|
|
3701
|
+
}
|
|
3702
|
+
if (typeof error === "string") {
|
|
3703
|
+
return new Error(error);
|
|
3704
|
+
}
|
|
3705
|
+
return new Error("Failed to export scene.");
|
|
3706
|
+
}
|
|
3707
|
+
function triggerBlobDownload(blob, filename) {
|
|
3708
|
+
const url = URL.createObjectURL(blob);
|
|
3709
|
+
const link = document.createElement("a");
|
|
3710
|
+
link.href = url;
|
|
3711
|
+
link.download = filename;
|
|
3712
|
+
link.style.display = "none";
|
|
3713
|
+
document.body.appendChild(link);
|
|
3714
|
+
link.click();
|
|
3715
|
+
document.body.removeChild(link);
|
|
3716
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
3717
|
+
}
|
|
3718
|
+
var GLB_MAGIC2 = 1179937895;
|
|
3719
|
+
var GLB_VERSION2 = 2;
|
|
3720
|
+
var GLB_JSON_CHUNK_TYPE2 = 1313821514;
|
|
3721
|
+
var GLB_HEADER_BYTES2 = 12;
|
|
3722
|
+
var GLB_CHUNK_HEADER_BYTES2 = 8;
|
|
3723
|
+
var GLB_JSON_PADDING_BYTE = 32;
|
|
3724
|
+
function isNearlyEqual(a, b, epsilon = 1e-6) {
|
|
3725
|
+
return Math.abs(a - b) <= epsilon;
|
|
3726
|
+
}
|
|
3727
|
+
function isIdentityTransformNode(node) {
|
|
3728
|
+
const translation = node.translation;
|
|
3729
|
+
if (Array.isArray(translation) && (translation.length !== 3 || !isNearlyEqual(Number(translation[0]), 0) || !isNearlyEqual(Number(translation[1]), 0) || !isNearlyEqual(Number(translation[2]), 0))) {
|
|
3730
|
+
return false;
|
|
3731
|
+
}
|
|
3732
|
+
const rotation = node.rotation;
|
|
3733
|
+
if (Array.isArray(rotation) && (rotation.length !== 4 || !isNearlyEqual(Number(rotation[0]), 0) || !isNearlyEqual(Number(rotation[1]), 0) || !isNearlyEqual(Number(rotation[2]), 0) || !isNearlyEqual(Number(rotation[3]), 1))) {
|
|
3734
|
+
return false;
|
|
3735
|
+
}
|
|
3736
|
+
const scale = node.scale;
|
|
3737
|
+
if (Array.isArray(scale) && (scale.length !== 3 || !isNearlyEqual(Number(scale[0]), 1) || !isNearlyEqual(Number(scale[1]), 1) || !isNearlyEqual(Number(scale[2]), 1))) {
|
|
3738
|
+
return false;
|
|
3739
|
+
}
|
|
3740
|
+
return true;
|
|
3741
|
+
}
|
|
3742
|
+
function isPassThroughWrapperNode(node) {
|
|
3743
|
+
if (!node || typeof node !== "object") {
|
|
3744
|
+
return false;
|
|
3745
|
+
}
|
|
3746
|
+
if (!Array.isArray(node.children) || node.children.length === 0) {
|
|
3747
|
+
return false;
|
|
3748
|
+
}
|
|
3749
|
+
const hasOnlyNumericChildren = node.children.every(
|
|
3750
|
+
(index) => Number.isInteger(index)
|
|
3751
|
+
);
|
|
3752
|
+
if (!hasOnlyNumericChildren) {
|
|
3753
|
+
return false;
|
|
3754
|
+
}
|
|
3755
|
+
if (node.mesh !== void 0 || node.camera !== void 0 || node.skin !== void 0) {
|
|
3756
|
+
return false;
|
|
3757
|
+
}
|
|
3758
|
+
if (node.extensions && typeof node.extensions === "object" && Object.keys(node.extensions).length > 0) {
|
|
3759
|
+
return false;
|
|
3760
|
+
}
|
|
3761
|
+
return isIdentityTransformNode(node);
|
|
3762
|
+
}
|
|
3763
|
+
function normalizeExportedSceneJson(json, fallbackSceneName) {
|
|
3764
|
+
if (!json || typeof json !== "object") {
|
|
3765
|
+
return false;
|
|
3766
|
+
}
|
|
3767
|
+
if (!Array.isArray(json.scenes) || !Array.isArray(json.nodes)) {
|
|
3768
|
+
return false;
|
|
3769
|
+
}
|
|
3770
|
+
const sceneIndexRaw = json.scene;
|
|
3771
|
+
const sceneIndex = typeof sceneIndexRaw === "number" && Number.isInteger(sceneIndexRaw) ? sceneIndexRaw : 0;
|
|
3772
|
+
const sceneDef = json.scenes[sceneIndex];
|
|
3773
|
+
if (!sceneDef || typeof sceneDef !== "object") {
|
|
3774
|
+
return false;
|
|
3775
|
+
}
|
|
3776
|
+
let changed = false;
|
|
3777
|
+
let wrapperNodeName;
|
|
3778
|
+
if (Array.isArray(sceneDef.nodes) && sceneDef.nodes.length === 1) {
|
|
3779
|
+
const wrapperIndex = sceneDef.nodes[0];
|
|
3780
|
+
if (Number.isInteger(wrapperIndex)) {
|
|
3781
|
+
const wrapperNode = json.nodes[wrapperIndex];
|
|
3782
|
+
if (isPassThroughWrapperNode(wrapperNode)) {
|
|
3783
|
+
sceneDef.nodes = [...wrapperNode.children];
|
|
3784
|
+
wrapperNodeName = typeof wrapperNode.name === "string" ? wrapperNode.name : void 0;
|
|
3785
|
+
changed = true;
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
const currentSceneName = typeof sceneDef.name === "string" ? sceneDef.name.trim() : "";
|
|
3790
|
+
if (currentSceneName === "AuxScene") {
|
|
3791
|
+
const nextSceneName = (wrapperNodeName?.trim() || fallbackSceneName?.trim() || "Scene").trim();
|
|
3792
|
+
if (nextSceneName.length > 0 && nextSceneName !== currentSceneName) {
|
|
3793
|
+
sceneDef.name = nextSceneName;
|
|
3794
|
+
changed = true;
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
return changed;
|
|
3798
|
+
}
|
|
3799
|
+
function sanitizeExportedGlb(buffer, fallbackSceneName) {
|
|
3800
|
+
if (buffer.byteLength < GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2) {
|
|
3801
|
+
return buffer;
|
|
3802
|
+
}
|
|
3803
|
+
const originalBytes = new Uint8Array(buffer);
|
|
3804
|
+
const view = new DataView(buffer);
|
|
3805
|
+
const magic = view.getUint32(0, true);
|
|
3806
|
+
const version = view.getUint32(4, true);
|
|
3807
|
+
if (magic !== GLB_MAGIC2 || version !== GLB_VERSION2) {
|
|
3808
|
+
return buffer;
|
|
3809
|
+
}
|
|
3810
|
+
const jsonChunkLength = view.getUint32(GLB_HEADER_BYTES2, true);
|
|
3811
|
+
const jsonChunkType = view.getUint32(GLB_HEADER_BYTES2 + 4, true);
|
|
3812
|
+
if (jsonChunkType !== GLB_JSON_CHUNK_TYPE2) {
|
|
3813
|
+
return buffer;
|
|
3814
|
+
}
|
|
3815
|
+
const jsonChunkStart = GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2;
|
|
3816
|
+
const jsonChunkEnd = jsonChunkStart + jsonChunkLength;
|
|
3817
|
+
if (jsonChunkEnd > originalBytes.length) {
|
|
3818
|
+
return buffer;
|
|
3819
|
+
}
|
|
3820
|
+
let jsonPayload;
|
|
3821
|
+
try {
|
|
3822
|
+
const jsonText = new TextDecoder().decode(
|
|
3823
|
+
originalBytes.slice(jsonChunkStart, jsonChunkEnd)
|
|
3824
|
+
);
|
|
3825
|
+
jsonPayload = JSON.parse(jsonText);
|
|
3826
|
+
} catch {
|
|
3827
|
+
return buffer;
|
|
3828
|
+
}
|
|
3829
|
+
const changed = normalizeExportedSceneJson(jsonPayload, fallbackSceneName);
|
|
3830
|
+
if (!changed) {
|
|
3831
|
+
return buffer;
|
|
3832
|
+
}
|
|
3833
|
+
const encodedJson = new TextEncoder().encode(JSON.stringify(jsonPayload));
|
|
3834
|
+
const paddedJsonLength = encodedJson.length + 3 & ~3;
|
|
3835
|
+
const paddedJson = new Uint8Array(paddedJsonLength);
|
|
3836
|
+
paddedJson.fill(GLB_JSON_PADDING_BYTE);
|
|
3837
|
+
paddedJson.set(encodedJson);
|
|
3838
|
+
const remainingChunks = originalBytes.slice(jsonChunkEnd);
|
|
3839
|
+
const totalLength = GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2 + paddedJsonLength + remainingChunks.length;
|
|
3840
|
+
const sanitized = new ArrayBuffer(totalLength);
|
|
3841
|
+
const sanitizedBytes = new Uint8Array(sanitized);
|
|
3842
|
+
const sanitizedView = new DataView(sanitized);
|
|
3843
|
+
sanitizedView.setUint32(0, GLB_MAGIC2, true);
|
|
3844
|
+
sanitizedView.setUint32(4, GLB_VERSION2, true);
|
|
3845
|
+
sanitizedView.setUint32(8, totalLength, true);
|
|
3846
|
+
sanitizedView.setUint32(GLB_HEADER_BYTES2, paddedJsonLength, true);
|
|
3847
|
+
sanitizedView.setUint32(GLB_HEADER_BYTES2 + 4, GLB_JSON_CHUNK_TYPE2, true);
|
|
3848
|
+
sanitizedBytes.set(paddedJson, jsonChunkStart);
|
|
3849
|
+
sanitizedBytes.set(remainingChunks, jsonChunkStart + paddedJsonLength);
|
|
3850
|
+
return sanitized;
|
|
3851
|
+
}
|
|
3335
3852
|
function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
3336
3853
|
const options = typeof fileNameOrOptions === "string" ? { fileName: fileNameOrOptions } : fileNameOrOptions ?? {};
|
|
3337
3854
|
const fileName = options.fileName ?? "scene.glb";
|
|
@@ -3346,7 +3863,15 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
|
3346
3863
|
}
|
|
3347
3864
|
}
|
|
3348
3865
|
}));
|
|
3349
|
-
const
|
|
3866
|
+
const sourceRoot = data;
|
|
3867
|
+
const exportRoot = sourceRoot instanceof THREE6.Scene ? sourceRoot : sourceRoot.clone(true);
|
|
3868
|
+
const exportTarget = exportRoot instanceof THREE6.Scene ? exportRoot : (() => {
|
|
3869
|
+
const scene = new THREE6.Scene();
|
|
3870
|
+
scene.name = data.name?.trim() || "Scene";
|
|
3871
|
+
scene.add(exportRoot);
|
|
3872
|
+
return scene;
|
|
3873
|
+
})();
|
|
3874
|
+
const detachBundle = shouldAttachBundle && options.bundle ? applyVizijBundle(exportRoot, options.bundle) : () => {
|
|
3350
3875
|
};
|
|
3351
3876
|
const binary = options.binary ?? true;
|
|
3352
3877
|
const exporterOptions = {
|
|
@@ -3360,33 +3885,40 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
|
3360
3885
|
}
|
|
3361
3886
|
try {
|
|
3362
3887
|
exporter.parse(
|
|
3363
|
-
|
|
3888
|
+
exportTarget,
|
|
3364
3889
|
(gltf) => {
|
|
3365
3890
|
detachBundle();
|
|
3366
3891
|
if (!(gltf instanceof ArrayBuffer)) {
|
|
3367
|
-
|
|
3892
|
+
const error = new Error("Failed to export scene.");
|
|
3893
|
+
options.onError?.(error);
|
|
3894
|
+
return;
|
|
3368
3895
|
}
|
|
3369
|
-
const
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
type: "application/octet-stream"
|
|
3373
|
-
})
|
|
3896
|
+
const sanitizedGltf = sanitizeExportedGlb(
|
|
3897
|
+
gltf,
|
|
3898
|
+
data.name?.trim() || void 0
|
|
3374
3899
|
);
|
|
3375
3900
|
const trimmed = fileName.trim();
|
|
3376
3901
|
const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
|
|
3377
3902
|
const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3903
|
+
triggerBlobDownload(
|
|
3904
|
+
new Blob([sanitizedGltf], {
|
|
3905
|
+
type: "application/octet-stream"
|
|
3906
|
+
}),
|
|
3907
|
+
downloadName
|
|
3908
|
+
);
|
|
3909
|
+
options.onComplete?.();
|
|
3381
3910
|
},
|
|
3382
|
-
() => {
|
|
3911
|
+
(error) => {
|
|
3383
3912
|
detachBundle();
|
|
3913
|
+
options.onError?.(normalizeExportError(error));
|
|
3384
3914
|
},
|
|
3385
3915
|
exporterOptions
|
|
3386
3916
|
);
|
|
3387
3917
|
} catch (error) {
|
|
3388
3918
|
detachBundle();
|
|
3389
|
-
|
|
3919
|
+
const normalizedError = normalizeExportError(error);
|
|
3920
|
+
options.onError?.(normalizedError);
|
|
3921
|
+
throw normalizedError;
|
|
3390
3922
|
}
|
|
3391
3923
|
}
|
|
3392
3924
|
export {
|
|
@@ -3405,6 +3937,7 @@ export {
|
|
|
3405
3937
|
loadGLTFFromBlobWithBundle,
|
|
3406
3938
|
loadGLTFWithBundle,
|
|
3407
3939
|
loadGltfFromBlob,
|
|
3940
|
+
parseGlbJsonChunk,
|
|
3408
3941
|
useDefaultVizijStore,
|
|
3409
3942
|
useFeatures,
|
|
3410
3943
|
useVizijStore,
|