@vizij/render 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -11
- package/dist/index.d.mts +296 -92
- package/dist/index.d.ts +296 -92
- package/dist/index.js +894 -555
- package/dist/index.mjs +854 -512
- package/package.json +18 -19
- package/LICENSE +0 -201
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// src/vizij.tsx
|
|
2
2
|
import { Suspense, memo as memo6, useContext as useContext3, useEffect as useEffect7 } from "react";
|
|
3
3
|
import { ErrorBoundary } from "react-error-boundary";
|
|
4
|
-
import { Object3D as Object3D4, SRGBColorSpace
|
|
4
|
+
import { Object3D as Object3D4, SRGBColorSpace } from "three";
|
|
5
5
|
import { Canvas, useThree } from "@react-three/fiber";
|
|
6
6
|
import { Line as Line3, OrthographicCamera, Text } from "@react-three/drei";
|
|
7
7
|
import { useShallow as useShallow7 } from "zustand/react/shallow";
|
|
8
8
|
|
|
9
9
|
// src/renderables/renderable.tsx
|
|
10
|
-
import { memo as memo5
|
|
10
|
+
import { memo as memo5 } from "react";
|
|
11
11
|
import { useShallow as useShallow5 } from "zustand/react/shallow";
|
|
12
12
|
|
|
13
13
|
// src/hooks/use-vizij-store.ts
|
|
@@ -84,35 +84,33 @@ function useFeatures(namespace, features, callbacks, debugInfo) {
|
|
|
84
84
|
}, [features, callbacks, store, debugInfo, namespace]);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
// src/functions/create-stored-data.ts
|
|
88
|
-
import { omit } from "lodash";
|
|
89
|
-
|
|
90
87
|
// src/functions/create-stored-features.ts
|
|
91
|
-
import { mapValues } from "lodash";
|
|
92
88
|
function createStoredFeatures(objectFeatures, animatableValues) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
const stored = Object.entries(objectFeatures).map(
|
|
90
|
+
([key, feat]) => {
|
|
91
|
+
if (feat.animated) {
|
|
92
|
+
const storedFeat = {
|
|
93
|
+
animated: true,
|
|
94
|
+
value: animatableValues[feat.value],
|
|
95
|
+
...feat.label ? { label: feat.label } : {}
|
|
96
|
+
};
|
|
97
|
+
return [key, storedFeat];
|
|
98
|
+
}
|
|
102
99
|
const staticFeature = feat;
|
|
103
|
-
return staticFeature.label ? { ...staticFeature } : staticFeature;
|
|
100
|
+
return [key, staticFeature.label ? { ...staticFeature } : staticFeature];
|
|
104
101
|
}
|
|
105
|
-
|
|
102
|
+
);
|
|
103
|
+
return Object.fromEntries(stored);
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
// src/functions/create-stored-data.ts
|
|
109
107
|
function createStoredRenderable(data, animatableValues) {
|
|
110
|
-
const
|
|
108
|
+
const { geometry: _geometry, ...stored } = data;
|
|
111
109
|
const storedFeatures = createStoredFeatures(
|
|
112
110
|
data.features,
|
|
113
111
|
animatableValues
|
|
114
112
|
);
|
|
115
|
-
return { ...
|
|
113
|
+
return { ...stored, features: storedFeatures };
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
// src/renderables/group.tsx
|
|
@@ -125,7 +123,9 @@ function InnerRenderedGroup({
|
|
|
125
123
|
}) {
|
|
126
124
|
const ref = useRef(null);
|
|
127
125
|
const group = useVizijStore(useShallow((state) => state.world[id]));
|
|
128
|
-
const refIsNull =
|
|
126
|
+
const refIsNull = useVizijStore(
|
|
127
|
+
(state) => !state.refs[id]?.[namespace]?.current
|
|
128
|
+
);
|
|
129
129
|
const animatables = useVizijStore(useShallow((state) => state.animatables));
|
|
130
130
|
const setHoveredElement = useVizijStore(
|
|
131
131
|
useShallow((state) => state.setHoveredElement)
|
|
@@ -267,7 +267,9 @@ function InnerRenderedEllipse({
|
|
|
267
267
|
const ellipse = useVizijStore(
|
|
268
268
|
useShallow2((state) => state.world[id])
|
|
269
269
|
);
|
|
270
|
-
const refIsNull =
|
|
270
|
+
const refIsNull = useVizijStore(
|
|
271
|
+
(state) => !state.refs[id]?.[namespace]?.current
|
|
272
|
+
);
|
|
271
273
|
const animatables = useVizijStore(useShallow2((state) => state.animatables));
|
|
272
274
|
const animatableValues = useMemo2(() => {
|
|
273
275
|
const av = {};
|
|
@@ -561,7 +563,9 @@ function InnerRenderedRectangle({
|
|
|
561
563
|
const rectangle = useVizijStore(
|
|
562
564
|
useShallow3((state) => state.world[id])
|
|
563
565
|
);
|
|
564
|
-
const refIsNull =
|
|
566
|
+
const refIsNull = useVizijStore(
|
|
567
|
+
(state) => !state.refs[id]?.[namespace]?.current
|
|
568
|
+
);
|
|
565
569
|
const animatables = useVizijStore(useShallow3((state) => state.animatables));
|
|
566
570
|
const animatableValues = useMemo3(() => {
|
|
567
571
|
const av = {};
|
|
@@ -833,6 +837,61 @@ import {
|
|
|
833
837
|
instanceOfRawRGB as instanceOfRawRGB3,
|
|
834
838
|
instanceOfRawVector3 as instanceOfRawVector34
|
|
835
839
|
} from "@vizij/utils";
|
|
840
|
+
|
|
841
|
+
// src/functions/material-name.ts
|
|
842
|
+
var MATERIAL_FEATURE_KEYS = [
|
|
843
|
+
"color",
|
|
844
|
+
"opacity",
|
|
845
|
+
"roughness",
|
|
846
|
+
"metalness",
|
|
847
|
+
"shininess",
|
|
848
|
+
"emissive",
|
|
849
|
+
"emissiveIntensity",
|
|
850
|
+
"specular"
|
|
851
|
+
];
|
|
852
|
+
var MATERIAL_NAME_SUFFIXES = [
|
|
853
|
+
" color",
|
|
854
|
+
" colours",
|
|
855
|
+
" colour",
|
|
856
|
+
" opacity",
|
|
857
|
+
" roughness",
|
|
858
|
+
" metalness",
|
|
859
|
+
" shininess",
|
|
860
|
+
" emissive intensity",
|
|
861
|
+
" emissive",
|
|
862
|
+
" specular"
|
|
863
|
+
];
|
|
864
|
+
function deriveMaterialName(shape, values) {
|
|
865
|
+
for (const key of MATERIAL_FEATURE_KEYS) {
|
|
866
|
+
const feature = shape.features[key];
|
|
867
|
+
if (feature && feature.animated) {
|
|
868
|
+
const animatable = values[feature.value];
|
|
869
|
+
const candidate = extractMaterialName(animatable?.name);
|
|
870
|
+
if (candidate) {
|
|
871
|
+
return candidate;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return void 0;
|
|
876
|
+
}
|
|
877
|
+
function extractMaterialName(name) {
|
|
878
|
+
if (!name) {
|
|
879
|
+
return void 0;
|
|
880
|
+
}
|
|
881
|
+
const trimmed = name.trim();
|
|
882
|
+
if (!trimmed) {
|
|
883
|
+
return void 0;
|
|
884
|
+
}
|
|
885
|
+
const lowered = trimmed.toLowerCase();
|
|
886
|
+
for (const suffix of MATERIAL_NAME_SUFFIXES) {
|
|
887
|
+
if (lowered.endsWith(suffix)) {
|
|
888
|
+
return trimmed.slice(0, trimmed.length - suffix.length).trim();
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return trimmed;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// src/renderables/shape.tsx
|
|
836
895
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
837
896
|
THREE2.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
838
897
|
function InnerRenderedShape({
|
|
@@ -843,10 +902,9 @@ function InnerRenderedShape({
|
|
|
843
902
|
const refGroup = useRef4(null);
|
|
844
903
|
const ref = useRef4(null);
|
|
845
904
|
const shape = useVizijStore(useShallow4((state) => state.world[id]));
|
|
846
|
-
const
|
|
847
|
-
|
|
905
|
+
const refIsNull = useVizijStore(
|
|
906
|
+
(state) => !state.refs[id]?.[namespace]?.current
|
|
848
907
|
);
|
|
849
|
-
const refIsNull = !refs[namespace]?.current;
|
|
850
908
|
const animatables = useVizijStore(useShallow4((state) => state.animatables));
|
|
851
909
|
const animatableValues = useMemo4(() => {
|
|
852
910
|
const av = {};
|
|
@@ -974,6 +1032,48 @@ function InnerRenderedShape({
|
|
|
974
1032
|
);
|
|
975
1033
|
}
|
|
976
1034
|
},
|
|
1035
|
+
roughness: (value) => {
|
|
1036
|
+
const standard = material.current;
|
|
1037
|
+
if (standard?.roughness !== void 0 && instanceOfRawNumber4(value)) {
|
|
1038
|
+
standard.roughness = value;
|
|
1039
|
+
standard.needsUpdate = true;
|
|
1040
|
+
}
|
|
1041
|
+
},
|
|
1042
|
+
metalness: (value) => {
|
|
1043
|
+
const standard = material.current;
|
|
1044
|
+
if (standard?.metalness !== void 0 && instanceOfRawNumber4(value)) {
|
|
1045
|
+
standard.metalness = value;
|
|
1046
|
+
standard.needsUpdate = true;
|
|
1047
|
+
}
|
|
1048
|
+
},
|
|
1049
|
+
shininess: (value) => {
|
|
1050
|
+
const phong = material.current;
|
|
1051
|
+
if (phong?.shininess !== void 0 && instanceOfRawNumber4(value)) {
|
|
1052
|
+
phong.shininess = value;
|
|
1053
|
+
phong.needsUpdate = true;
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
emissive: (value) => {
|
|
1057
|
+
const standard = material.current;
|
|
1058
|
+
if (standard?.emissive && instanceOfRawRGB3(value)) {
|
|
1059
|
+
standard.emissive.setRGB(value.r, value.g, value.b);
|
|
1060
|
+
standard.needsUpdate = true;
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
emissiveIntensity: (value) => {
|
|
1064
|
+
const standard = material.current;
|
|
1065
|
+
if (standard?.emissiveIntensity !== void 0 && instanceOfRawNumber4(value)) {
|
|
1066
|
+
standard.emissiveIntensity = value;
|
|
1067
|
+
standard.needsUpdate = true;
|
|
1068
|
+
}
|
|
1069
|
+
},
|
|
1070
|
+
specular: (value) => {
|
|
1071
|
+
const phong = material.current;
|
|
1072
|
+
if (phong?.specular && instanceOfRawRGB3(value)) {
|
|
1073
|
+
phong.specular.setRGB(value.r, value.g, value.b);
|
|
1074
|
+
phong.needsUpdate = true;
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
977
1077
|
...morphTargetSettings[2]
|
|
978
1078
|
},
|
|
979
1079
|
shape
|
|
@@ -1089,119 +1189,44 @@ function InnerRenderedShape({
|
|
|
1089
1189
|
);
|
|
1090
1190
|
}
|
|
1091
1191
|
var RenderedShape = memo4(InnerRenderedShape);
|
|
1092
|
-
var MATERIAL_FEATURE_KEYS = [
|
|
1093
|
-
"color",
|
|
1094
|
-
"opacity",
|
|
1095
|
-
"roughness",
|
|
1096
|
-
"metalness",
|
|
1097
|
-
"shininess"
|
|
1098
|
-
];
|
|
1099
|
-
var MATERIAL_NAME_SUFFIXES = [
|
|
1100
|
-
" color",
|
|
1101
|
-
" colours",
|
|
1102
|
-
" colour",
|
|
1103
|
-
" opacity",
|
|
1104
|
-
" roughness",
|
|
1105
|
-
" metalness",
|
|
1106
|
-
" shininess"
|
|
1107
|
-
];
|
|
1108
|
-
function deriveMaterialName(shape, values) {
|
|
1109
|
-
for (const key of MATERIAL_FEATURE_KEYS) {
|
|
1110
|
-
const feature = shape.features[key];
|
|
1111
|
-
if (feature && feature.animated) {
|
|
1112
|
-
const animatable = values[feature.value];
|
|
1113
|
-
const candidate = extractMaterialName(animatable?.name);
|
|
1114
|
-
if (candidate) {
|
|
1115
|
-
return candidate;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
return void 0;
|
|
1120
|
-
}
|
|
1121
|
-
function extractMaterialName(name) {
|
|
1122
|
-
if (!name) {
|
|
1123
|
-
return void 0;
|
|
1124
|
-
}
|
|
1125
|
-
const trimmed = name.trim();
|
|
1126
|
-
if (!trimmed) {
|
|
1127
|
-
return void 0;
|
|
1128
|
-
}
|
|
1129
|
-
const lowered = trimmed.toLowerCase();
|
|
1130
|
-
for (const suffix of MATERIAL_NAME_SUFFIXES) {
|
|
1131
|
-
if (lowered.endsWith(suffix)) {
|
|
1132
|
-
return trimmed.slice(0, trimmed.length - suffix.length).trim();
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
return trimmed;
|
|
1136
|
-
}
|
|
1137
1192
|
|
|
1138
1193
|
// src/renderables/renderable.tsx
|
|
1139
|
-
import {
|
|
1194
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1140
1195
|
function InnerRenderable({
|
|
1141
1196
|
id,
|
|
1142
1197
|
namespace,
|
|
1143
1198
|
chain
|
|
1144
1199
|
}) {
|
|
1145
1200
|
const type = useVizijStore(useShallow5((state) => state.world[id].type));
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1201
|
+
const key = `${namespace}.${id}`;
|
|
1202
|
+
switch (type) {
|
|
1203
|
+
case "group":
|
|
1204
|
+
return /* @__PURE__ */ jsx5(RenderedGroup, { id, namespace, chain }, key);
|
|
1205
|
+
case "ellipse":
|
|
1206
|
+
return /* @__PURE__ */ jsx5(
|
|
1207
|
+
RenderedEllipse,
|
|
1208
|
+
{
|
|
1209
|
+
id,
|
|
1210
|
+
namespace,
|
|
1211
|
+
chain
|
|
1212
|
+
},
|
|
1213
|
+
key
|
|
1214
|
+
);
|
|
1215
|
+
case "rectangle":
|
|
1216
|
+
return /* @__PURE__ */ jsx5(
|
|
1217
|
+
RenderedRectangle,
|
|
1218
|
+
{
|
|
1219
|
+
id,
|
|
1220
|
+
namespace,
|
|
1221
|
+
chain
|
|
1222
|
+
},
|
|
1223
|
+
key
|
|
1224
|
+
);
|
|
1225
|
+
case "shape":
|
|
1226
|
+
return /* @__PURE__ */ jsx5(RenderedShape, { id, namespace, chain }, key);
|
|
1227
|
+
default:
|
|
1228
|
+
return null;
|
|
1158
1229
|
}
|
|
1159
|
-
return /* @__PURE__ */ jsx5(Fragment3, { children: resolvedNamespaces.map((ns) => {
|
|
1160
|
-
switch (type) {
|
|
1161
|
-
case "group":
|
|
1162
|
-
return /* @__PURE__ */ jsx5(
|
|
1163
|
-
RenderedGroup,
|
|
1164
|
-
{
|
|
1165
|
-
id,
|
|
1166
|
-
namespace: ns,
|
|
1167
|
-
chain
|
|
1168
|
-
},
|
|
1169
|
-
`${ns}.${id}`
|
|
1170
|
-
);
|
|
1171
|
-
case "ellipse":
|
|
1172
|
-
return /* @__PURE__ */ jsx5(
|
|
1173
|
-
RenderedEllipse,
|
|
1174
|
-
{
|
|
1175
|
-
id,
|
|
1176
|
-
namespace: ns,
|
|
1177
|
-
chain
|
|
1178
|
-
},
|
|
1179
|
-
`${ns}.${id}`
|
|
1180
|
-
);
|
|
1181
|
-
case "rectangle":
|
|
1182
|
-
return /* @__PURE__ */ jsx5(
|
|
1183
|
-
RenderedRectangle,
|
|
1184
|
-
{
|
|
1185
|
-
id,
|
|
1186
|
-
namespace: ns,
|
|
1187
|
-
chain
|
|
1188
|
-
},
|
|
1189
|
-
`${ns}.${id}`
|
|
1190
|
-
);
|
|
1191
|
-
case "shape":
|
|
1192
|
-
return /* @__PURE__ */ jsx5(
|
|
1193
|
-
RenderedShape,
|
|
1194
|
-
{
|
|
1195
|
-
id,
|
|
1196
|
-
namespace: ns,
|
|
1197
|
-
chain
|
|
1198
|
-
},
|
|
1199
|
-
`${ns}.${id}`
|
|
1200
|
-
);
|
|
1201
|
-
default:
|
|
1202
|
-
return null;
|
|
1203
|
-
}
|
|
1204
|
-
}) });
|
|
1205
1230
|
}
|
|
1206
1231
|
var Renderable = memo5(InnerRenderable);
|
|
1207
1232
|
|
|
@@ -1212,21 +1237,17 @@ import { produce, enableMapSet } from "immer";
|
|
|
1212
1237
|
import * as THREE3 from "three";
|
|
1213
1238
|
import { getLookup as getLookup2 } from "@vizij/utils";
|
|
1214
1239
|
|
|
1215
|
-
// src/actions/create-new-element.ts
|
|
1216
|
-
import { createRef } from "react";
|
|
1217
|
-
import { mapValues as mapValues2 } from "lodash";
|
|
1218
|
-
|
|
1219
1240
|
// src/functions/create-world-element.ts
|
|
1241
|
+
import { createBrowserSafeId } from "@vizij/utils";
|
|
1220
1242
|
function createDefaultGroup(partialBody) {
|
|
1221
1243
|
const translation = partialBody.features?.translation || { animated: false, value: { x: 0, y: 0 } };
|
|
1222
1244
|
const rotation = partialBody.features?.rotation || { animated: false, value: { x: 0, y: 0, z: 0 } };
|
|
1223
1245
|
const scale = partialBody.features?.scale || { animated: false, value: { x: 1, y: 1, z: 1 } };
|
|
1224
1246
|
return {
|
|
1225
|
-
id: partialBody.id ||
|
|
1247
|
+
id: partialBody.id || createBrowserSafeId(),
|
|
1226
1248
|
name: partialBody.name || "new-body",
|
|
1227
1249
|
type: partialBody.type || "group",
|
|
1228
1250
|
tags: partialBody.tags || [],
|
|
1229
|
-
refs: partialBody.refs || {},
|
|
1230
1251
|
features: { translation, rotation, scale },
|
|
1231
1252
|
root: partialBody.root ?? false,
|
|
1232
1253
|
children: partialBody.children || []
|
|
@@ -1243,11 +1264,9 @@ function createNewElement(state, type, root = false) {
|
|
|
1243
1264
|
});
|
|
1244
1265
|
if (Object.entries(state.world).length === 0) {
|
|
1245
1266
|
const name = `New-Root`;
|
|
1246
|
-
const refs = { default: createRef() };
|
|
1247
1267
|
const newElement = createDefaultGroup({
|
|
1248
1268
|
name,
|
|
1249
|
-
root: true
|
|
1250
|
-
refs
|
|
1269
|
+
root: true
|
|
1251
1270
|
});
|
|
1252
1271
|
state.world[newElement.id] = newElement;
|
|
1253
1272
|
state.elementSelection = [buildSelection(newElement.id)];
|
|
@@ -1259,11 +1278,7 @@ function createNewElement(state, type, root = false) {
|
|
|
1259
1278
|
return;
|
|
1260
1279
|
}
|
|
1261
1280
|
const name = `New-Body`;
|
|
1262
|
-
const
|
|
1263
|
-
worldRootEntry.refs,
|
|
1264
|
-
() => createRef()
|
|
1265
|
-
);
|
|
1266
|
-
const newChild = createDefaultGroup({ name, root, refs });
|
|
1281
|
+
const newChild = createDefaultGroup({ name, root });
|
|
1267
1282
|
worldRootEntry.children.push(newChild.id);
|
|
1268
1283
|
state.world[newChild.id] = newChild;
|
|
1269
1284
|
state.elementSelection = [buildSelection(newChild.id)];
|
|
@@ -1283,7 +1298,32 @@ function removeFromTree(state, nodesToRemove) {
|
|
|
1283
1298
|
});
|
|
1284
1299
|
}
|
|
1285
1300
|
|
|
1301
|
+
// src/memoryInvestigation.ts
|
|
1302
|
+
function getGlobalMemoryInvestigation() {
|
|
1303
|
+
return globalThis;
|
|
1304
|
+
}
|
|
1305
|
+
function updateRenderState(updater) {
|
|
1306
|
+
const globalObj = getGlobalMemoryInvestigation();
|
|
1307
|
+
if (!globalObj.__VIZIJ_MEMORY_INVESTIGATION__?.enabled) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (!globalObj.__vizijMemoryDebugState) {
|
|
1311
|
+
globalObj.__vizijMemoryDebugState = {};
|
|
1312
|
+
}
|
|
1313
|
+
if (!globalObj.__vizijMemoryDebugState.render) {
|
|
1314
|
+
globalObj.__vizijMemoryDebugState.render = {};
|
|
1315
|
+
}
|
|
1316
|
+
updater(globalObj.__vizijMemoryDebugState.render);
|
|
1317
|
+
}
|
|
1318
|
+
function recordRenderCounter(key, delta = 1) {
|
|
1319
|
+
updateRenderState((renderState) => {
|
|
1320
|
+
const current = typeof renderState[key] === "number" ? Number(renderState[key]) : 0;
|
|
1321
|
+
renderState[key] = current + delta;
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1286
1325
|
// src/functions/create-animatable.ts
|
|
1326
|
+
import { createBrowserSafeId as createBrowserSafeId2 } from "@vizij/utils";
|
|
1287
1327
|
function createAnimatable(value) {
|
|
1288
1328
|
if (!value.type) {
|
|
1289
1329
|
return null;
|
|
@@ -1293,7 +1333,7 @@ function createAnimatable(value) {
|
|
|
1293
1333
|
}
|
|
1294
1334
|
if (value.type === "euler") {
|
|
1295
1335
|
const newAnimatable = {
|
|
1296
|
-
id: value.id ??
|
|
1336
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1297
1337
|
name: `${value.name} Rotation`,
|
|
1298
1338
|
type: value.type,
|
|
1299
1339
|
default: value.default ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1310,7 +1350,7 @@ function createAnimatable(value) {
|
|
|
1310
1350
|
return newAnimatable;
|
|
1311
1351
|
} else if (value.type === "vector3") {
|
|
1312
1352
|
const newAnimatable = {
|
|
1313
|
-
id: value.id ??
|
|
1353
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1314
1354
|
name: `${value.name} Vector3`,
|
|
1315
1355
|
type: value.type,
|
|
1316
1356
|
default: value.default ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1327,7 +1367,7 @@ function createAnimatable(value) {
|
|
|
1327
1367
|
return newAnimatable;
|
|
1328
1368
|
} else if (value.type === "string") {
|
|
1329
1369
|
const newAnimatable = {
|
|
1330
|
-
id: value.id ??
|
|
1370
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1331
1371
|
name: value.name,
|
|
1332
1372
|
type: value.type,
|
|
1333
1373
|
default: value.default ?? "Hello World",
|
|
@@ -1340,7 +1380,7 @@ function createAnimatable(value) {
|
|
|
1340
1380
|
return newAnimatable;
|
|
1341
1381
|
} else if (value.type === "number") {
|
|
1342
1382
|
const newAnimatable = {
|
|
1343
|
-
id: value.id ??
|
|
1383
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1344
1384
|
name: value.name,
|
|
1345
1385
|
type: value.type,
|
|
1346
1386
|
default: value.default ?? 0,
|
|
@@ -1353,7 +1393,7 @@ function createAnimatable(value) {
|
|
|
1353
1393
|
return newAnimatable;
|
|
1354
1394
|
} else if (value.type === "boolean") {
|
|
1355
1395
|
const newAnimatable = {
|
|
1356
|
-
id: value.id ??
|
|
1396
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1357
1397
|
name: value.name,
|
|
1358
1398
|
type: value.type,
|
|
1359
1399
|
default: value.default ?? false,
|
|
@@ -1366,7 +1406,7 @@ function createAnimatable(value) {
|
|
|
1366
1406
|
return newAnimatable;
|
|
1367
1407
|
} else if (value.type === "rgb") {
|
|
1368
1408
|
const newAnimatable = {
|
|
1369
|
-
id: value.id ??
|
|
1409
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1370
1410
|
name: value.name,
|
|
1371
1411
|
type: value.type,
|
|
1372
1412
|
default: value.default ?? { r: 0, g: 0, b: 0 },
|
|
@@ -1383,7 +1423,7 @@ function createAnimatable(value) {
|
|
|
1383
1423
|
return newAnimatable;
|
|
1384
1424
|
} else if (value.type === "hsl") {
|
|
1385
1425
|
const newAnimatable = {
|
|
1386
|
-
id: value.id ??
|
|
1426
|
+
id: value.id ?? createBrowserSafeId2(),
|
|
1387
1427
|
name: value.name,
|
|
1388
1428
|
type: value.type,
|
|
1389
1429
|
default: value.default ?? { h: 0, s: 0, l: 0 },
|
|
@@ -1438,6 +1478,7 @@ enableMapSet();
|
|
|
1438
1478
|
var VizijSlice = (set, get) => ({
|
|
1439
1479
|
// worldRef: createRef<THREE.Group>(),
|
|
1440
1480
|
world: {},
|
|
1481
|
+
refs: {},
|
|
1441
1482
|
animatables: {},
|
|
1442
1483
|
values: /* @__PURE__ */ new Map(),
|
|
1443
1484
|
renderHit: false,
|
|
@@ -1511,12 +1552,10 @@ var VizijSlice = (set, get) => ({
|
|
|
1511
1552
|
worldData,
|
|
1512
1553
|
filterIds
|
|
1513
1554
|
);
|
|
1555
|
+
const refs = get().refs;
|
|
1514
1556
|
return candidateGroups.flatMap((entry) => {
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1517
|
-
);
|
|
1518
|
-
const resolved = refs.find((ref) => ref?.current)?.current ?? null;
|
|
1519
|
-
return resolved ? [resolved] : [];
|
|
1557
|
+
const mounted = Object.values(refs[entry.id] ?? {}).map((ref) => ref.current).find((object) => Boolean(object));
|
|
1558
|
+
return mounted ? [mounted] : [];
|
|
1520
1559
|
});
|
|
1521
1560
|
},
|
|
1522
1561
|
setGeometry: (id, geometry) => {
|
|
@@ -1715,6 +1754,7 @@ var VizijSlice = (set, get) => ({
|
|
|
1715
1754
|
);
|
|
1716
1755
|
},
|
|
1717
1756
|
setVizij: (scene, animatables) => {
|
|
1757
|
+
recordRenderCounter("rootReplacementCount");
|
|
1718
1758
|
set({
|
|
1719
1759
|
world: scene,
|
|
1720
1760
|
animatables
|
|
@@ -1722,6 +1762,7 @@ var VizijSlice = (set, get) => ({
|
|
|
1722
1762
|
},
|
|
1723
1763
|
addWorldElements(world, animatables, replace) {
|
|
1724
1764
|
if (replace) {
|
|
1765
|
+
recordRenderCounter("rootReplacementCount");
|
|
1725
1766
|
set({ world, animatables });
|
|
1726
1767
|
} else {
|
|
1727
1768
|
set((state) => ({
|
|
@@ -1736,14 +1777,12 @@ var VizijSlice = (set, get) => ({
|
|
|
1736
1777
|
}));
|
|
1737
1778
|
},
|
|
1738
1779
|
setReference: (id, namespace, ref) => {
|
|
1739
|
-
set(
|
|
1740
|
-
|
|
1741
|
-
state.
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
})
|
|
1746
|
-
);
|
|
1780
|
+
set((state) => ({
|
|
1781
|
+
refs: {
|
|
1782
|
+
...state.refs,
|
|
1783
|
+
[id]: { ...state.refs[id], [namespace]: ref }
|
|
1784
|
+
}
|
|
1785
|
+
}));
|
|
1747
1786
|
}
|
|
1748
1787
|
});
|
|
1749
1788
|
var useDefaultVizijStore = create()(
|
|
@@ -1758,8 +1797,57 @@ var createVizijStore = (initial) => create()(
|
|
|
1758
1797
|
}))
|
|
1759
1798
|
);
|
|
1760
1799
|
|
|
1800
|
+
// src/types/shape.ts
|
|
1801
|
+
var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
|
|
1802
|
+
ShapeMaterial2["Standard"] = "standard";
|
|
1803
|
+
ShapeMaterial2["Phong"] = "phong";
|
|
1804
|
+
ShapeMaterial2["Basic"] = "basic";
|
|
1805
|
+
ShapeMaterial2["Lambert"] = "lambert";
|
|
1806
|
+
ShapeMaterial2["Normal"] = "normal";
|
|
1807
|
+
return ShapeMaterial2;
|
|
1808
|
+
})(ShapeMaterial || {});
|
|
1809
|
+
|
|
1810
|
+
// src/types/tone-mapping.ts
|
|
1811
|
+
import {
|
|
1812
|
+
ACESFilmicToneMapping,
|
|
1813
|
+
AgXToneMapping,
|
|
1814
|
+
NeutralToneMapping,
|
|
1815
|
+
NoToneMapping
|
|
1816
|
+
} from "three";
|
|
1817
|
+
var TONE_MAPPING_MODES = [
|
|
1818
|
+
"none",
|
|
1819
|
+
"agx",
|
|
1820
|
+
"aces",
|
|
1821
|
+
"neutral"
|
|
1822
|
+
];
|
|
1823
|
+
var TONE_MAPPING_LABELS = {
|
|
1824
|
+
none: "None (web match)",
|
|
1825
|
+
agx: "AgX (Blender)",
|
|
1826
|
+
aces: "ACES Filmic",
|
|
1827
|
+
neutral: "Neutral"
|
|
1828
|
+
};
|
|
1829
|
+
var DEFAULT_TONE_MAPPING_MODE = "none";
|
|
1830
|
+
var TONE_MAPPING_CONSTANTS = {
|
|
1831
|
+
none: NoToneMapping,
|
|
1832
|
+
agx: AgXToneMapping,
|
|
1833
|
+
aces: ACESFilmicToneMapping,
|
|
1834
|
+
neutral: NeutralToneMapping
|
|
1835
|
+
};
|
|
1836
|
+
function isToneMappingMode(value) {
|
|
1837
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(TONE_MAPPING_CONSTANTS, value);
|
|
1838
|
+
}
|
|
1839
|
+
function resolveToneMapping(mode) {
|
|
1840
|
+
if (isToneMappingMode(mode)) {
|
|
1841
|
+
return TONE_MAPPING_CONSTANTS[mode];
|
|
1842
|
+
}
|
|
1843
|
+
return TONE_MAPPING_CONSTANTS[DEFAULT_TONE_MAPPING_MODE];
|
|
1844
|
+
}
|
|
1845
|
+
function normalizeToneMappingMode(value) {
|
|
1846
|
+
return isToneMappingMode(value) ? value : DEFAULT_TONE_MAPPING_MODE;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1761
1849
|
// src/effects/selection-glow-effect.tsx
|
|
1762
|
-
import { Fragment as
|
|
1850
|
+
import { Fragment as Fragment3, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef5 } from "react";
|
|
1763
1851
|
import { useFrame } from "@react-three/fiber";
|
|
1764
1852
|
import { useShallow as useShallow6 } from "zustand/react/shallow";
|
|
1765
1853
|
import {
|
|
@@ -1774,7 +1862,7 @@ import {
|
|
|
1774
1862
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1775
1863
|
function SelectionGlowEffect({
|
|
1776
1864
|
enabled = false,
|
|
1777
|
-
color = "#
|
|
1865
|
+
color = "#ff1010",
|
|
1778
1866
|
opacity = 0.9,
|
|
1779
1867
|
thresholdAngle = 2
|
|
1780
1868
|
}) {
|
|
@@ -1786,7 +1874,7 @@ function SelectionGlowEffect({
|
|
|
1786
1874
|
if (!enabled || selections.length === 0) {
|
|
1787
1875
|
return null;
|
|
1788
1876
|
}
|
|
1789
|
-
return /* @__PURE__ */ jsx6(
|
|
1877
|
+
return /* @__PURE__ */ jsx6(Fragment3, { children: selections.map((selection) => /* @__PURE__ */ jsx6(
|
|
1790
1878
|
SelectionOutline,
|
|
1791
1879
|
{
|
|
1792
1880
|
selection,
|
|
@@ -1806,19 +1894,19 @@ function SelectionOutline({
|
|
|
1806
1894
|
const target = useVizijStore(
|
|
1807
1895
|
useShallow6((state) => {
|
|
1808
1896
|
const entry = state.world[selection.id];
|
|
1809
|
-
const ref =
|
|
1897
|
+
const ref = state.refs[selection.id]?.[selection.namespace];
|
|
1810
1898
|
const geometry = entry?.geometry ?? null;
|
|
1811
1899
|
return { ref, geometry };
|
|
1812
1900
|
})
|
|
1813
1901
|
);
|
|
1814
1902
|
const sourceRef = target.ref;
|
|
1815
|
-
const edgesGeometry =
|
|
1903
|
+
const edgesGeometry = useMemo5(() => {
|
|
1816
1904
|
if (!target.geometry) return null;
|
|
1817
1905
|
const edges = new EdgesGeometry(target.geometry, thresholdAngle);
|
|
1818
1906
|
return edges;
|
|
1819
1907
|
}, [target.geometry, thresholdAngle]);
|
|
1820
1908
|
useEffect6(() => () => edgesGeometry?.dispose(), [edgesGeometry]);
|
|
1821
|
-
const material =
|
|
1909
|
+
const material = useMemo5(() => {
|
|
1822
1910
|
const mat = new LineBasicMaterial({
|
|
1823
1911
|
color: new Color(color),
|
|
1824
1912
|
transparent: true,
|
|
@@ -1868,7 +1956,7 @@ function copyWorldTransform(source, target) {
|
|
|
1868
1956
|
}
|
|
1869
1957
|
|
|
1870
1958
|
// src/vizij.tsx
|
|
1871
|
-
import { Fragment as
|
|
1959
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1872
1960
|
Object3D4.DEFAULT_UP.set(0, 0, 1);
|
|
1873
1961
|
function Vizij({
|
|
1874
1962
|
style,
|
|
@@ -1877,9 +1965,17 @@ function Vizij({
|
|
|
1877
1965
|
namespace = "default",
|
|
1878
1966
|
showSafeArea = false,
|
|
1879
1967
|
showSelectionGlow = false,
|
|
1968
|
+
toneMapping = "none",
|
|
1880
1969
|
onPointerMissed
|
|
1881
1970
|
}) {
|
|
1882
1971
|
const ctx = useContext3(VizijContext);
|
|
1972
|
+
useEffect7(() => {
|
|
1973
|
+
recordRenderCounter("canvasMountCount");
|
|
1974
|
+
recordRenderCounter("mountedCanvasCount");
|
|
1975
|
+
return () => {
|
|
1976
|
+
recordRenderCounter("mountedCanvasCount", -1);
|
|
1977
|
+
};
|
|
1978
|
+
}, []);
|
|
1883
1979
|
if (ctx) {
|
|
1884
1980
|
return /* @__PURE__ */ jsx7(
|
|
1885
1981
|
Canvas,
|
|
@@ -1890,7 +1986,6 @@ function Vizij({
|
|
|
1890
1986
|
onPointerMissed,
|
|
1891
1987
|
gl: {
|
|
1892
1988
|
outputColorSpace: SRGBColorSpace,
|
|
1893
|
-
toneMapping: NoToneMapping,
|
|
1894
1989
|
antialias: true
|
|
1895
1990
|
},
|
|
1896
1991
|
children: /* @__PURE__ */ jsx7(
|
|
@@ -1899,7 +1994,8 @@ function Vizij({
|
|
|
1899
1994
|
rootId,
|
|
1900
1995
|
namespace,
|
|
1901
1996
|
showSafeArea,
|
|
1902
|
-
showSelectionGlow
|
|
1997
|
+
showSelectionGlow,
|
|
1998
|
+
toneMapping
|
|
1903
1999
|
}
|
|
1904
2000
|
)
|
|
1905
2001
|
}
|
|
@@ -1913,7 +2009,6 @@ function Vizij({
|
|
|
1913
2009
|
onPointerMissed,
|
|
1914
2010
|
gl: {
|
|
1915
2011
|
outputColorSpace: SRGBColorSpace,
|
|
1916
|
-
toneMapping: NoToneMapping,
|
|
1917
2012
|
antialias: true
|
|
1918
2013
|
},
|
|
1919
2014
|
children: /* @__PURE__ */ jsx7(
|
|
@@ -1922,7 +2017,8 @@ function Vizij({
|
|
|
1922
2017
|
rootId,
|
|
1923
2018
|
namespace,
|
|
1924
2019
|
showSafeArea,
|
|
1925
|
-
showSelectionGlow
|
|
2020
|
+
showSelectionGlow,
|
|
2021
|
+
toneMapping
|
|
1926
2022
|
}
|
|
1927
2023
|
)
|
|
1928
2024
|
}
|
|
@@ -1934,21 +2030,23 @@ function InnerVizij({
|
|
|
1934
2030
|
namespace = "default",
|
|
1935
2031
|
container,
|
|
1936
2032
|
showSafeArea,
|
|
1937
|
-
showSelectionGlow
|
|
2033
|
+
showSelectionGlow,
|
|
2034
|
+
toneMapping = "none"
|
|
1938
2035
|
}) {
|
|
1939
2036
|
const sceneParentSizing = container ? {
|
|
1940
2037
|
width: container.width * container.resolution,
|
|
1941
2038
|
height: container.height * container.resolution
|
|
1942
2039
|
} : void 0;
|
|
1943
|
-
return /* @__PURE__ */ jsxs4(
|
|
2040
|
+
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1944
2041
|
/* @__PURE__ */ jsx7("ambientLight", { intensity: Math.PI / 2 }),
|
|
2042
|
+
/* @__PURE__ */ jsx7(ToneMappingController, { mode: toneMapping }),
|
|
1945
2043
|
/* @__PURE__ */ jsx7(
|
|
1946
2044
|
OrthographicCamera,
|
|
1947
2045
|
{
|
|
1948
2046
|
makeDefault: true,
|
|
1949
2047
|
position: [0, 0, 100],
|
|
1950
2048
|
near: 0.1,
|
|
1951
|
-
far:
|
|
2049
|
+
far: 1e3
|
|
1952
2050
|
}
|
|
1953
2051
|
),
|
|
1954
2052
|
/* @__PURE__ */ jsx7(Suspense, { fallback: null, children: /* @__PURE__ */ jsx7(
|
|
@@ -1964,6 +2062,31 @@ function InnerVizij({
|
|
|
1964
2062
|
] });
|
|
1965
2063
|
}
|
|
1966
2064
|
var MemoizedInnerVizij = memo6(InnerVizij);
|
|
2065
|
+
function ToneMappingController({ mode }) {
|
|
2066
|
+
const gl = useThree((state) => state.gl);
|
|
2067
|
+
const scene = useThree((state) => state.scene);
|
|
2068
|
+
useEffect7(() => {
|
|
2069
|
+
const resolved = resolveToneMapping(mode);
|
|
2070
|
+
if (gl.toneMapping === resolved) {
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
gl.toneMapping = resolved;
|
|
2074
|
+
scene.traverse((object) => {
|
|
2075
|
+
const material = object.material;
|
|
2076
|
+
if (!material) {
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
if (Array.isArray(material)) {
|
|
2080
|
+
material.forEach((mat) => {
|
|
2081
|
+
mat.needsUpdate = true;
|
|
2082
|
+
});
|
|
2083
|
+
} else {
|
|
2084
|
+
material.needsUpdate = true;
|
|
2085
|
+
}
|
|
2086
|
+
});
|
|
2087
|
+
}, [gl, scene, mode]);
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
1967
2090
|
function InnerWorld({
|
|
1968
2091
|
rootId,
|
|
1969
2092
|
namespace = "default",
|
|
@@ -2053,16 +2176,6 @@ var defaultRootBounds = {
|
|
|
2053
2176
|
size: { x: 5, y: 4 }
|
|
2054
2177
|
};
|
|
2055
2178
|
|
|
2056
|
-
// src/types/shape.ts
|
|
2057
|
-
var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
|
|
2058
|
-
ShapeMaterial2["Standard"] = "standard";
|
|
2059
|
-
ShapeMaterial2["Phong"] = "phong";
|
|
2060
|
-
ShapeMaterial2["Basic"] = "basic";
|
|
2061
|
-
ShapeMaterial2["Lambert"] = "lambert";
|
|
2062
|
-
ShapeMaterial2["Normal"] = "normal";
|
|
2063
|
-
return ShapeMaterial2;
|
|
2064
|
-
})(ShapeMaterial || {});
|
|
2065
|
-
|
|
2066
2179
|
// src/hooks/use-vizij-store-subscription.ts
|
|
2067
2180
|
import { useContext as useContext4, useEffect as useEffect8 } from "react";
|
|
2068
2181
|
function useVizijStoreSubscription(selector, listener) {
|
|
@@ -2096,7 +2209,6 @@ import * as THREE5 from "three";
|
|
|
2096
2209
|
import { GLTFLoader, DRACOLoader } from "three-stdlib";
|
|
2097
2210
|
|
|
2098
2211
|
// src/functions/gltf-loading/traverse-three.ts
|
|
2099
|
-
import { createRef as createRef3 } from "react";
|
|
2100
2212
|
import * as THREE4 from "three";
|
|
2101
2213
|
|
|
2102
2214
|
// src/functions/gltf-loading/map-features.ts
|
|
@@ -2126,21 +2238,25 @@ import { Object3D as Object3D7 } from "three";
|
|
|
2126
2238
|
|
|
2127
2239
|
// src/functions/gltf-loading/import-group.ts
|
|
2128
2240
|
import { Object3D as Object3D6 } from "three";
|
|
2129
|
-
|
|
2130
|
-
// src/functions/util.ts
|
|
2131
|
-
import { createRef as createRef2 } from "react";
|
|
2132
|
-
function namespaceArrayToRefs(namespaces) {
|
|
2133
|
-
return namespaces.reduce((acc, ns) => ({ ...acc, [ns]: createRef2() }), {});
|
|
2134
|
-
}
|
|
2241
|
+
import { createBrowserSafeId as createBrowserSafeId5 } from "@vizij/utils";
|
|
2135
2242
|
|
|
2136
2243
|
// src/functions/gltf-loading/import-mesh.ts
|
|
2137
2244
|
import { Object3D as Object3D5 } from "three";
|
|
2245
|
+
import { createBrowserSafeId as createBrowserSafeId4 } from "@vizij/utils";
|
|
2138
2246
|
|
|
2139
2247
|
// src/functions/gltf-loading/import-geometry.ts
|
|
2140
|
-
|
|
2248
|
+
import {
|
|
2249
|
+
createBrowserSafeId as createBrowserSafeId3
|
|
2250
|
+
} from "@vizij/utils";
|
|
2251
|
+
|
|
2252
|
+
// src/functions/gltf-loading/morph-keys.ts
|
|
2253
|
+
function slugifyMorphName(name, fallbackIndex) {
|
|
2141
2254
|
const baseName = name && name.trim().length > 0 ? name.trim() : `morph_${fallbackIndex + 1}`;
|
|
2142
2255
|
const slug = baseName.toLowerCase().replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "");
|
|
2143
|
-
|
|
2256
|
+
return slug.length > 0 ? slug : `morph_${fallbackIndex + 1}`;
|
|
2257
|
+
}
|
|
2258
|
+
function sanitizeMorphKey(name, fallbackIndex, used) {
|
|
2259
|
+
const safeBase = slugifyMorphName(name, fallbackIndex);
|
|
2144
2260
|
let candidate = safeBase;
|
|
2145
2261
|
let counter = 1;
|
|
2146
2262
|
while (used.has(candidate)) {
|
|
@@ -2149,6 +2265,12 @@ function sanitizeMorphKey(name, fallbackIndex, used) {
|
|
|
2149
2265
|
used.add(candidate);
|
|
2150
2266
|
return candidate;
|
|
2151
2267
|
}
|
|
2268
|
+
function deriveMorphFeatureKeys(names) {
|
|
2269
|
+
const used = /* @__PURE__ */ new Set();
|
|
2270
|
+
return names.map((name, index) => sanitizeMorphKey(name, index, used));
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
// src/functions/gltf-loading/import-geometry.ts
|
|
2152
2274
|
function importGeometry(geometry, mesh) {
|
|
2153
2275
|
const features = {};
|
|
2154
2276
|
const animatableValues = {};
|
|
@@ -2160,7 +2282,7 @@ function importGeometry(geometry, mesh) {
|
|
|
2160
2282
|
const usedKeys = /* @__PURE__ */ new Set();
|
|
2161
2283
|
Object.entries(mesh.morphTargetDictionary ?? {}).forEach(
|
|
2162
2284
|
([name, index]) => {
|
|
2163
|
-
const morphId =
|
|
2285
|
+
const morphId = createBrowserSafeId3();
|
|
2164
2286
|
const featureKey = sanitizeMorphKey(name, index, usedKeys);
|
|
2165
2287
|
morphIds.push(featureKey);
|
|
2166
2288
|
features[featureKey] = {
|
|
@@ -2191,12 +2313,12 @@ function importGeometry(geometry, mesh) {
|
|
|
2191
2313
|
|
|
2192
2314
|
// src/functions/gltf-loading/import-mesh.ts
|
|
2193
2315
|
Object3D5.DEFAULT_UP.set(0, 0, 1);
|
|
2194
|
-
function importMesh(mesh,
|
|
2316
|
+
function importMesh(mesh, colorLookup) {
|
|
2195
2317
|
let world = {};
|
|
2196
2318
|
let animatables = {};
|
|
2197
2319
|
let newColorLookup = {};
|
|
2198
2320
|
const translationAnimatable = {
|
|
2199
|
-
id:
|
|
2321
|
+
id: createBrowserSafeId4(),
|
|
2200
2322
|
name: `${mesh.name ?? "Mesh"} translation`,
|
|
2201
2323
|
type: "vector3",
|
|
2202
2324
|
default: { x: mesh.position.x, y: mesh.position.y, z: mesh.position.z },
|
|
@@ -2212,7 +2334,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2212
2334
|
[translationAnimatable.id]: translationAnimatable
|
|
2213
2335
|
};
|
|
2214
2336
|
const rotationAnimatable = {
|
|
2215
|
-
id:
|
|
2337
|
+
id: createBrowserSafeId4(),
|
|
2216
2338
|
name: `${mesh.name ?? "Mesh"} rotation`,
|
|
2217
2339
|
type: "euler",
|
|
2218
2340
|
default: { x: mesh.rotation.x, y: mesh.rotation.y, z: mesh.rotation.z },
|
|
@@ -2225,7 +2347,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2225
2347
|
};
|
|
2226
2348
|
animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
|
|
2227
2349
|
const scaleAnimatable = {
|
|
2228
|
-
id:
|
|
2350
|
+
id: createBrowserSafeId4(),
|
|
2229
2351
|
name: `${mesh.name ?? "Mesh"} scale`,
|
|
2230
2352
|
type: "vector3",
|
|
2231
2353
|
default: { x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z },
|
|
@@ -2236,56 +2358,120 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2236
2358
|
}
|
|
2237
2359
|
};
|
|
2238
2360
|
animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
|
|
2239
|
-
const
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
type: "rgb",
|
|
2250
|
-
default: { r: color.r, g: color.g, b: color.b },
|
|
2251
|
-
constraints: {
|
|
2252
|
-
min: [0, 0, 0],
|
|
2253
|
-
max: [1, 1, 1]
|
|
2254
|
-
},
|
|
2361
|
+
const material = mesh.material;
|
|
2362
|
+
const color = material.color;
|
|
2363
|
+
const colorName = material.name;
|
|
2364
|
+
const label = (suffix) => colorName ? `${colorName} ${suffix}` : `${mesh.name ?? "Mesh"} ${suffix}`;
|
|
2365
|
+
const makeNumberAnimatable = (suffix, value, constraints) => ({
|
|
2366
|
+
id: createBrowserSafeId4(),
|
|
2367
|
+
name: label(suffix),
|
|
2368
|
+
type: "number",
|
|
2369
|
+
default: value,
|
|
2370
|
+
constraints,
|
|
2255
2371
|
pub: {
|
|
2256
2372
|
public: true,
|
|
2257
|
-
output:
|
|
2373
|
+
output: label(suffix)
|
|
2258
2374
|
}
|
|
2259
|
-
};
|
|
2260
|
-
const
|
|
2261
|
-
id:
|
|
2262
|
-
name:
|
|
2263
|
-
type: "
|
|
2264
|
-
default:
|
|
2375
|
+
});
|
|
2376
|
+
const makeColorAnimatable = (suffix, value) => ({
|
|
2377
|
+
id: createBrowserSafeId4(),
|
|
2378
|
+
name: label(suffix),
|
|
2379
|
+
type: "rgb",
|
|
2380
|
+
default: { r: value.r, g: value.g, b: value.b },
|
|
2265
2381
|
constraints: {
|
|
2266
|
-
min: 0,
|
|
2267
|
-
max: 1
|
|
2382
|
+
min: [0, 0, 0],
|
|
2383
|
+
max: [1, 1, 1]
|
|
2268
2384
|
},
|
|
2269
2385
|
pub: {
|
|
2270
2386
|
public: true,
|
|
2271
|
-
output:
|
|
2387
|
+
output: label(suffix)
|
|
2272
2388
|
}
|
|
2389
|
+
});
|
|
2390
|
+
const colorAnimatable = {
|
|
2391
|
+
...makeColorAnimatable("color", color),
|
|
2392
|
+
name: material.name ?? `${mesh.name ?? "Mesh"} color`
|
|
2273
2393
|
};
|
|
2274
|
-
|
|
2275
|
-
|
|
2394
|
+
const opacityAnimatable = makeNumberAnimatable("opacity", material.opacity, {
|
|
2395
|
+
min: 0,
|
|
2396
|
+
max: 1
|
|
2397
|
+
});
|
|
2398
|
+
const materialAnimatables = [
|
|
2399
|
+
colorAnimatable,
|
|
2400
|
+
opacityAnimatable
|
|
2401
|
+
];
|
|
2402
|
+
let roughnessAnimatable;
|
|
2403
|
+
let metalnessAnimatable;
|
|
2404
|
+
let emissiveAnimatable;
|
|
2405
|
+
let emissiveIntensityAnimatable;
|
|
2406
|
+
let shininessAnimatable;
|
|
2407
|
+
let specularAnimatable;
|
|
2408
|
+
if (material.isMeshStandardMaterial) {
|
|
2409
|
+
roughnessAnimatable = makeNumberAnimatable(
|
|
2410
|
+
"roughness",
|
|
2411
|
+
material.roughness,
|
|
2412
|
+
{
|
|
2413
|
+
min: 0,
|
|
2414
|
+
max: 1
|
|
2415
|
+
}
|
|
2416
|
+
);
|
|
2417
|
+
metalnessAnimatable = makeNumberAnimatable(
|
|
2418
|
+
"metalness",
|
|
2419
|
+
material.metalness,
|
|
2420
|
+
{
|
|
2421
|
+
min: 0,
|
|
2422
|
+
max: 1
|
|
2423
|
+
}
|
|
2424
|
+
);
|
|
2425
|
+
emissiveAnimatable = makeColorAnimatable("emissive", material.emissive);
|
|
2426
|
+
emissiveIntensityAnimatable = makeNumberAnimatable(
|
|
2427
|
+
"emissive intensity",
|
|
2428
|
+
material.emissiveIntensity,
|
|
2429
|
+
{ min: 0 }
|
|
2430
|
+
);
|
|
2431
|
+
materialAnimatables.push(
|
|
2432
|
+
roughnessAnimatable,
|
|
2433
|
+
metalnessAnimatable,
|
|
2434
|
+
emissiveAnimatable,
|
|
2435
|
+
emissiveIntensityAnimatable
|
|
2436
|
+
);
|
|
2437
|
+
} else if (mesh.material.isMeshPhongMaterial) {
|
|
2438
|
+
const phong = mesh.material;
|
|
2439
|
+
shininessAnimatable = makeNumberAnimatable("shininess", phong.shininess, {
|
|
2440
|
+
min: 0
|
|
2441
|
+
});
|
|
2442
|
+
emissiveAnimatable = makeColorAnimatable("emissive", phong.emissive);
|
|
2443
|
+
emissiveIntensityAnimatable = makeNumberAnimatable(
|
|
2444
|
+
"emissive intensity",
|
|
2445
|
+
phong.emissiveIntensity,
|
|
2446
|
+
{ min: 0 }
|
|
2447
|
+
);
|
|
2448
|
+
specularAnimatable = makeColorAnimatable("specular", phong.specular);
|
|
2449
|
+
materialAnimatables.push(
|
|
2450
|
+
shininessAnimatable,
|
|
2451
|
+
emissiveAnimatable,
|
|
2452
|
+
emissiveIntensityAnimatable,
|
|
2453
|
+
specularAnimatable
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
let materialIds;
|
|
2276
2457
|
if (colorName && colorLookup[colorName]) {
|
|
2277
|
-
|
|
2278
|
-
opacityId = colorLookup[colorName][1];
|
|
2279
|
-
useEmissive = colorLookup[colorName][2];
|
|
2458
|
+
materialIds = colorLookup[colorName];
|
|
2280
2459
|
} else {
|
|
2281
|
-
|
|
2282
|
-
|
|
2460
|
+
materialIds = {
|
|
2461
|
+
color: colorAnimatable.id,
|
|
2462
|
+
opacity: opacityAnimatable.id,
|
|
2463
|
+
roughness: roughnessAnimatable?.id,
|
|
2464
|
+
metalness: metalnessAnimatable?.id,
|
|
2465
|
+
emissive: emissiveAnimatable?.id,
|
|
2466
|
+
emissiveIntensity: emissiveIntensityAnimatable?.id,
|
|
2467
|
+
shininess: shininessAnimatable?.id,
|
|
2468
|
+
specular: specularAnimatable?.id
|
|
2469
|
+
};
|
|
2470
|
+
materialAnimatables.forEach((animatable) => {
|
|
2471
|
+
animatables = { ...animatables, [animatable.id]: animatable };
|
|
2472
|
+
});
|
|
2283
2473
|
if (colorName) {
|
|
2284
|
-
newColorLookup[colorName] =
|
|
2285
|
-
colorAnimatable.id,
|
|
2286
|
-
opacityAnimatable.id,
|
|
2287
|
-
useEmissive
|
|
2288
|
-
];
|
|
2474
|
+
newColorLookup[colorName] = materialIds;
|
|
2289
2475
|
}
|
|
2290
2476
|
}
|
|
2291
2477
|
const [geometryFeatures, geometryAnimatables, morphTargets] = importGeometry(
|
|
@@ -2296,7 +2482,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2296
2482
|
const children = [];
|
|
2297
2483
|
mesh.children.forEach((child) => {
|
|
2298
2484
|
if (child.isMesh) {
|
|
2299
|
-
const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child,
|
|
2485
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, {
|
|
2300
2486
|
...colorLookup,
|
|
2301
2487
|
...newColorLookup
|
|
2302
2488
|
});
|
|
@@ -2305,7 +2491,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2305
2491
|
animatables = { ...animatables, ...newAnimatables };
|
|
2306
2492
|
children.push(childId);
|
|
2307
2493
|
} else if (shouldImportAsGroupChild(child)) {
|
|
2308
|
-
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child,
|
|
2494
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, {
|
|
2309
2495
|
...colorLookup,
|
|
2310
2496
|
...newColorLookup
|
|
2311
2497
|
});
|
|
@@ -2319,7 +2505,7 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2319
2505
|
id: mesh.uuid,
|
|
2320
2506
|
name: mesh.name,
|
|
2321
2507
|
geometry: mesh.geometry,
|
|
2322
|
-
material: getShapeMaterial(mesh
|
|
2508
|
+
material: getShapeMaterial(mesh),
|
|
2323
2509
|
type: "shape",
|
|
2324
2510
|
tags: [],
|
|
2325
2511
|
morphTargets,
|
|
@@ -2327,21 +2513,28 @@ function importMesh(mesh, namespaces, colorLookup) {
|
|
|
2327
2513
|
translation: { animated: true, value: translationAnimatable.id },
|
|
2328
2514
|
rotation: { animated: true, value: rotationAnimatable.id },
|
|
2329
2515
|
scale: { animated: true, value: scaleAnimatable.id },
|
|
2330
|
-
color: { animated: true, value:
|
|
2331
|
-
opacity: { animated: true, value:
|
|
2516
|
+
color: { animated: true, value: materialIds.color },
|
|
2517
|
+
opacity: { animated: true, value: materialIds.opacity },
|
|
2518
|
+
...materialIds.roughness ? { roughness: { animated: true, value: materialIds.roughness } } : {},
|
|
2519
|
+
...materialIds.metalness ? { metalness: { animated: true, value: materialIds.metalness } } : {},
|
|
2520
|
+
...materialIds.emissive ? { emissive: { animated: true, value: materialIds.emissive } } : {},
|
|
2521
|
+
...materialIds.emissiveIntensity ? {
|
|
2522
|
+
emissiveIntensity: {
|
|
2523
|
+
animated: true,
|
|
2524
|
+
value: materialIds.emissiveIntensity
|
|
2525
|
+
}
|
|
2526
|
+
} : {},
|
|
2527
|
+
...materialIds.shininess ? { shininess: { animated: true, value: materialIds.shininess } } : {},
|
|
2528
|
+
...materialIds.specular ? { specular: { animated: true, value: materialIds.specular } } : {},
|
|
2332
2529
|
...geometryFeatures
|
|
2333
2530
|
},
|
|
2334
|
-
children: children.length > 0 ? children : void 0
|
|
2335
|
-
refs: namespaceArrayToRefs(namespaces)
|
|
2531
|
+
children: children.length > 0 ? children : void 0
|
|
2336
2532
|
};
|
|
2337
2533
|
world = { ...world, [newShape.id]: newShape };
|
|
2338
2534
|
return [world, animatables, newShape.id, newColorLookup];
|
|
2339
2535
|
}
|
|
2340
|
-
function getShapeMaterial(mesh
|
|
2536
|
+
function getShapeMaterial(mesh) {
|
|
2341
2537
|
const material = mesh.material;
|
|
2342
|
-
if (useEmissive) {
|
|
2343
|
-
return "basic" /* Basic */;
|
|
2344
|
-
}
|
|
2345
2538
|
if (material.isMeshStandardMaterial) {
|
|
2346
2539
|
return "standard" /* Standard */;
|
|
2347
2540
|
} else if (material.isMeshPhongMaterial) {
|
|
@@ -2377,13 +2570,13 @@ function shouldImportAsGroupChild(child) {
|
|
|
2377
2570
|
|
|
2378
2571
|
// src/functions/gltf-loading/import-group.ts
|
|
2379
2572
|
Object3D6.DEFAULT_UP.set(0, 0, 1);
|
|
2380
|
-
function importGroup(group,
|
|
2573
|
+
function importGroup(group, colorLookup, rootBounds) {
|
|
2381
2574
|
let world = {};
|
|
2382
2575
|
let animatables = {};
|
|
2383
2576
|
let newColorLookup = {};
|
|
2384
2577
|
const children = [];
|
|
2385
2578
|
const translationAnimatable = {
|
|
2386
|
-
id:
|
|
2579
|
+
id: createBrowserSafeId5(),
|
|
2387
2580
|
name: `${group.name ?? "Group"} translation`,
|
|
2388
2581
|
type: "vector3",
|
|
2389
2582
|
default: { x: group.position.x, y: group.position.y, z: group.position.z },
|
|
@@ -2399,7 +2592,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2399
2592
|
[translationAnimatable.id]: translationAnimatable
|
|
2400
2593
|
};
|
|
2401
2594
|
const rotationAnimatable = {
|
|
2402
|
-
id:
|
|
2595
|
+
id: createBrowserSafeId5(),
|
|
2403
2596
|
name: `${group.name ?? "Group"} rotation`,
|
|
2404
2597
|
type: "euler",
|
|
2405
2598
|
default: { x: group.rotation.x, y: group.rotation.y, z: group.rotation.z },
|
|
@@ -2412,7 +2605,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2412
2605
|
};
|
|
2413
2606
|
animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
|
|
2414
2607
|
const scaleAnimatable = {
|
|
2415
|
-
id:
|
|
2608
|
+
id: createBrowserSafeId5(),
|
|
2416
2609
|
name: `${group.name ?? "Group"} scale`,
|
|
2417
2610
|
type: "vector3",
|
|
2418
2611
|
default: { x: group.scale.x, y: group.scale.y, z: group.scale.z },
|
|
@@ -2425,7 +2618,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2425
2618
|
animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
|
|
2426
2619
|
group.children.forEach((child) => {
|
|
2427
2620
|
if (child.isMesh) {
|
|
2428
|
-
const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child,
|
|
2621
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, {
|
|
2429
2622
|
...colorLookup,
|
|
2430
2623
|
...newColorLookup
|
|
2431
2624
|
});
|
|
@@ -2434,7 +2627,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2434
2627
|
animatables = { ...animatables, ...newAnimatables };
|
|
2435
2628
|
children.push(childId);
|
|
2436
2629
|
} else if (shouldImportAsGroupChild2(child)) {
|
|
2437
|
-
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child,
|
|
2630
|
+
const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, {
|
|
2438
2631
|
...colorLookup,
|
|
2439
2632
|
...newColorLookup
|
|
2440
2633
|
});
|
|
@@ -2456,8 +2649,7 @@ function importGroup(group, namespaces, colorLookup, rootBounds) {
|
|
|
2456
2649
|
},
|
|
2457
2650
|
root: Boolean(rootBounds),
|
|
2458
2651
|
rootBounds,
|
|
2459
|
-
children
|
|
2460
|
-
refs: namespaceArrayToRefs(namespaces)
|
|
2652
|
+
children
|
|
2461
2653
|
};
|
|
2462
2654
|
world = { ...world, [newGroup.id]: newGroup };
|
|
2463
2655
|
return [world, animatables, newGroup.id, newColorLookup];
|
|
@@ -2483,12 +2675,11 @@ function shouldImportAsGroupChild2(child) {
|
|
|
2483
2675
|
|
|
2484
2676
|
// src/functions/gltf-loading/import-scene.ts
|
|
2485
2677
|
Object3D7.DEFAULT_UP.set(0, 0, 1);
|
|
2486
|
-
function importScene(scene,
|
|
2678
|
+
function importScene(scene, rootBounds) {
|
|
2487
2679
|
let world = {};
|
|
2488
2680
|
let animatables = {};
|
|
2489
2681
|
const [newWorldItems, newAnimatables] = importGroup(
|
|
2490
2682
|
scene,
|
|
2491
|
-
namespaces,
|
|
2492
2683
|
{},
|
|
2493
2684
|
rootBounds
|
|
2494
2685
|
);
|
|
@@ -2499,7 +2690,7 @@ function importScene(scene, namespaces, rootBounds) {
|
|
|
2499
2690
|
|
|
2500
2691
|
// src/functions/gltf-loading/traverse-three.ts
|
|
2501
2692
|
THREE4.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
2502
|
-
function traverseThree(group,
|
|
2693
|
+
function traverseThree(group, aggressiveImport = false, rootBounds) {
|
|
2503
2694
|
const worldData = {};
|
|
2504
2695
|
const animatableData = {};
|
|
2505
2696
|
let hasRobotData = false;
|
|
@@ -2522,11 +2713,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2522
2713
|
switch (data.type) {
|
|
2523
2714
|
case "group":
|
|
2524
2715
|
loadedData = {
|
|
2525
|
-
...data
|
|
2526
|
-
refs: namespaces.reduce(
|
|
2527
|
-
(acc, ns) => ({ ...acc, [ns]: createRef3() }),
|
|
2528
|
-
{}
|
|
2529
|
-
)
|
|
2716
|
+
...data
|
|
2530
2717
|
};
|
|
2531
2718
|
[mappedFeatures, animatableValues] = mapFeatures(data.features);
|
|
2532
2719
|
isGroupFeatures(mappedFeatures);
|
|
@@ -2537,11 +2724,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2537
2724
|
case "shape":
|
|
2538
2725
|
loadedData = {
|
|
2539
2726
|
...data,
|
|
2540
|
-
geometry: child.geometry
|
|
2541
|
-
refs: namespaces.reduce(
|
|
2542
|
-
(acc, ns) => ({ ...acc, [ns]: createRef3() }),
|
|
2543
|
-
{}
|
|
2544
|
-
)
|
|
2727
|
+
geometry: child.geometry
|
|
2545
2728
|
};
|
|
2546
2729
|
[mappedFeatures, animatableValues] = mapFeatures(data.features);
|
|
2547
2730
|
isShapeFeatures(mappedFeatures);
|
|
@@ -2551,11 +2734,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2551
2734
|
break;
|
|
2552
2735
|
case "ellipse":
|
|
2553
2736
|
loadedData = {
|
|
2554
|
-
...data
|
|
2555
|
-
refs: namespaces.reduce(
|
|
2556
|
-
(acc, ns) => ({ ...acc, [ns]: createRef3() }),
|
|
2557
|
-
{}
|
|
2558
|
-
)
|
|
2737
|
+
...data
|
|
2559
2738
|
};
|
|
2560
2739
|
[mappedFeatures, animatableValues] = mapFeatures(data.features);
|
|
2561
2740
|
isEllipseFeatures(mappedFeatures);
|
|
@@ -2565,11 +2744,7 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2565
2744
|
break;
|
|
2566
2745
|
case "rectangle":
|
|
2567
2746
|
loadedData = {
|
|
2568
|
-
...data
|
|
2569
|
-
refs: namespaces.reduce(
|
|
2570
|
-
(acc, ns) => ({ ...acc, [ns]: createRef3() }),
|
|
2571
|
-
{}
|
|
2572
|
-
)
|
|
2747
|
+
...data
|
|
2573
2748
|
};
|
|
2574
2749
|
[mappedFeatures, animatableValues] = mapFeatures(data.features);
|
|
2575
2750
|
isRectangleFeatures(mappedFeatures);
|
|
@@ -2592,7 +2767,6 @@ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds)
|
|
|
2592
2767
|
}
|
|
2593
2768
|
const [newWorldData, newAnimatableData] = importScene(
|
|
2594
2769
|
group,
|
|
2595
|
-
namespaces,
|
|
2596
2770
|
derivedRootBounds
|
|
2597
2771
|
);
|
|
2598
2772
|
Object.assign(worldData, newWorldData);
|
|
@@ -2605,7 +2779,10 @@ var MATERIAL_NAME_FEATURE_KEYS = [
|
|
|
2605
2779
|
"opacity",
|
|
2606
2780
|
"roughness",
|
|
2607
2781
|
"metalness",
|
|
2608
|
-
"shininess"
|
|
2782
|
+
"shininess",
|
|
2783
|
+
"emissive",
|
|
2784
|
+
"emissiveIntensity",
|
|
2785
|
+
"specular"
|
|
2609
2786
|
];
|
|
2610
2787
|
var MATERIAL_NAME_SUFFIXES2 = [
|
|
2611
2788
|
" color",
|
|
@@ -2614,7 +2791,10 @@ var MATERIAL_NAME_SUFFIXES2 = [
|
|
|
2614
2791
|
" opacity",
|
|
2615
2792
|
" roughness",
|
|
2616
2793
|
" metalness",
|
|
2617
|
-
" shininess"
|
|
2794
|
+
" shininess",
|
|
2795
|
+
" emissive intensity",
|
|
2796
|
+
" emissive",
|
|
2797
|
+
" specular"
|
|
2618
2798
|
];
|
|
2619
2799
|
function applyStoredRenderableNames(object, data) {
|
|
2620
2800
|
if (typeof data.name === "string" && data.name.length > 0) {
|
|
@@ -2834,12 +3014,29 @@ function applyVizijBundle(object, bundle) {
|
|
|
2834
3014
|
const userData = object.userData && typeof object.userData === "object" ? object.userData : {};
|
|
2835
3015
|
const originalExtensions = userData.gltfExtensions;
|
|
2836
3016
|
let applied = false;
|
|
3017
|
+
const staleCarriers = [];
|
|
2837
3018
|
if (bundle) {
|
|
2838
3019
|
userData.gltfExtensions = {
|
|
2839
3020
|
...originalExtensions ?? {},
|
|
2840
3021
|
VIZIJ_bundle: bundle
|
|
2841
3022
|
};
|
|
2842
3023
|
object.userData = userData;
|
|
3024
|
+
object.traverse((node) => {
|
|
3025
|
+
if (node === object) {
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
const extensions = node.userData?.gltfExtensions;
|
|
3029
|
+
if (!extensions || !(BUNDLE_KEYS[0] in extensions)) {
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
staleCarriers.push({ node, extensions });
|
|
3033
|
+
const { [BUNDLE_KEYS[0]]: _stale, ...rest } = extensions;
|
|
3034
|
+
if (Object.keys(rest).length > 0) {
|
|
3035
|
+
node.userData.gltfExtensions = rest;
|
|
3036
|
+
} else {
|
|
3037
|
+
delete node.userData.gltfExtensions;
|
|
3038
|
+
}
|
|
3039
|
+
});
|
|
2843
3040
|
applied = true;
|
|
2844
3041
|
}
|
|
2845
3042
|
return () => {
|
|
@@ -2856,6 +3053,10 @@ function applyVizijBundle(object, bundle) {
|
|
|
2856
3053
|
delete object.userData;
|
|
2857
3054
|
}
|
|
2858
3055
|
}
|
|
3056
|
+
for (const { node, extensions } of staleCarriers) {
|
|
3057
|
+
node.userData.gltfExtensions = extensions;
|
|
3058
|
+
}
|
|
3059
|
+
staleCarriers.length = 0;
|
|
2859
3060
|
applied = false;
|
|
2860
3061
|
};
|
|
2861
3062
|
}
|
|
@@ -3281,16 +3482,6 @@ async function resolveParserJson(parserJson, fallback) {
|
|
|
3281
3482
|
return fromArrayBuffer;
|
|
3282
3483
|
}
|
|
3283
3484
|
}
|
|
3284
|
-
if (fallback.blob) {
|
|
3285
|
-
try {
|
|
3286
|
-
const blobBuffer = typeof fallback.blob.arrayBuffer === "function" ? await fallback.blob.arrayBuffer() : await new Response(fallback.blob).arrayBuffer();
|
|
3287
|
-
const fromBlob = parseGlbJsonChunk(blobBuffer);
|
|
3288
|
-
if (fromBlob && typeof fromBlob === "object") {
|
|
3289
|
-
return fromBlob;
|
|
3290
|
-
}
|
|
3291
|
-
} catch {
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
3485
|
if (fallback.url && typeof fetch === "function") {
|
|
3295
3486
|
try {
|
|
3296
3487
|
const response = await fetch(fallback.url);
|
|
@@ -3306,81 +3497,21 @@ async function resolveParserJson(parserJson, fallback) {
|
|
|
3306
3497
|
}
|
|
3307
3498
|
return parserJson;
|
|
3308
3499
|
}
|
|
3309
|
-
async function loadGLTF(url,
|
|
3310
|
-
const
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3317
|
-
const asset = parseScene(
|
|
3318
|
-
modelData.scene,
|
|
3319
|
-
actualizedNamespaces,
|
|
3500
|
+
async function loadGLTF(url, aggressiveImport = false, rootBounds) {
|
|
3501
|
+
const asset = await loadGLTFWithBundle(url, aggressiveImport, rootBounds);
|
|
3502
|
+
return [asset.world, asset.animatables, asset.animations];
|
|
3503
|
+
}
|
|
3504
|
+
async function loadGLTFFromBlob(blob, aggressiveImport = false, rootBounds) {
|
|
3505
|
+
const asset = await loadGLTFFromBlobWithBundle(
|
|
3506
|
+
blob,
|
|
3320
3507
|
aggressiveImport,
|
|
3321
|
-
rootBounds
|
|
3322
|
-
parserJson,
|
|
3323
|
-
modelData.animations
|
|
3508
|
+
rootBounds
|
|
3324
3509
|
);
|
|
3325
3510
|
return [asset.world, asset.animatables, asset.animations];
|
|
3326
3511
|
}
|
|
3327
|
-
|
|
3328
|
-
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3329
|
-
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
3330
|
-
const objectUrl = URL.createObjectURL(blob);
|
|
3331
|
-
try {
|
|
3332
|
-
const asset = await loadGLTFWithBundle(
|
|
3333
|
-
objectUrl,
|
|
3334
|
-
actualizedNamespaces,
|
|
3335
|
-
aggressiveImport,
|
|
3336
|
-
rootBounds,
|
|
3337
|
-
{ blob }
|
|
3338
|
-
);
|
|
3339
|
-
return [asset.world, asset.animatables, asset.animations];
|
|
3340
|
-
} finally {
|
|
3341
|
-
URL.revokeObjectURL(objectUrl);
|
|
3342
|
-
}
|
|
3343
|
-
}
|
|
3344
|
-
const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
|
|
3345
|
-
return new Promise((resolve, reject) => {
|
|
3346
|
-
const loader = new GLTFLoader();
|
|
3347
|
-
loader.setDRACOLoader(new DRACOLoader());
|
|
3348
|
-
loader.parse(
|
|
3349
|
-
arrayBuffer,
|
|
3350
|
-
"",
|
|
3351
|
-
async (gltf) => {
|
|
3352
|
-
try {
|
|
3353
|
-
const parserJson = await resolveParserJson(
|
|
3354
|
-
gltf?.parser?.json,
|
|
3355
|
-
{ arrayBuffer }
|
|
3356
|
-
);
|
|
3357
|
-
const asset = parseScene(
|
|
3358
|
-
gltf.scene,
|
|
3359
|
-
actualizedNamespaces,
|
|
3360
|
-
aggressiveImport,
|
|
3361
|
-
rootBounds,
|
|
3362
|
-
parserJson,
|
|
3363
|
-
gltf.animations
|
|
3364
|
-
);
|
|
3365
|
-
resolve([asset.world, asset.animatables, asset.animations]);
|
|
3366
|
-
} catch (error) {
|
|
3367
|
-
if (error instanceof Error) {
|
|
3368
|
-
reject(error);
|
|
3369
|
-
} else {
|
|
3370
|
-
reject(new Error(String(error)));
|
|
3371
|
-
}
|
|
3372
|
-
}
|
|
3373
|
-
},
|
|
3374
|
-
(error) => {
|
|
3375
|
-
reject(new Error(`Error loading GLTF: ${error.message}`));
|
|
3376
|
-
}
|
|
3377
|
-
);
|
|
3378
|
-
});
|
|
3379
|
-
}
|
|
3380
|
-
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson, clips) {
|
|
3512
|
+
function parseScene(scene, aggressiveImport, rootBounds, parserJson, clips) {
|
|
3381
3513
|
const [world, animatables] = traverseThree(
|
|
3382
3514
|
scene,
|
|
3383
|
-
namespaces,
|
|
3384
3515
|
aggressiveImport,
|
|
3385
3516
|
rootBounds
|
|
3386
3517
|
);
|
|
@@ -3388,105 +3519,49 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson,
|
|
|
3388
3519
|
const animations = extractVizijAnimations(parserJson, clips);
|
|
3389
3520
|
return { world, animatables, bundle, animations, scene };
|
|
3390
3521
|
}
|
|
3391
|
-
|
|
3522
|
+
function createTrackedGLTFLoader() {
|
|
3523
|
+
recordRenderCounter("gltfLoadCount");
|
|
3524
|
+
recordRenderCounter("dracoLoaderCreationCount");
|
|
3392
3525
|
const modelLoader = new GLTFLoader();
|
|
3393
3526
|
modelLoader.setDRACOLoader(new DRACOLoader());
|
|
3527
|
+
return modelLoader;
|
|
3528
|
+
}
|
|
3529
|
+
async function loadGLTFWithBundle(url, aggressiveImport = false, rootBounds, parserJsonFallback) {
|
|
3530
|
+
recordRenderCounter("gltfUrlLoadCount");
|
|
3531
|
+
const modelLoader = createTrackedGLTFLoader();
|
|
3394
3532
|
const modelData = await modelLoader.loadAsync(url);
|
|
3395
3533
|
const parserJson = await resolveParserJson(modelData?.parser?.json, {
|
|
3396
3534
|
url,
|
|
3397
3535
|
...parserJsonFallback
|
|
3398
3536
|
});
|
|
3399
|
-
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3400
3537
|
return parseScene(
|
|
3401
3538
|
modelData.scene,
|
|
3402
|
-
actualizedNamespaces,
|
|
3403
3539
|
aggressiveImport,
|
|
3404
3540
|
rootBounds,
|
|
3405
3541
|
parserJson,
|
|
3406
3542
|
modelData.animations
|
|
3407
3543
|
);
|
|
3408
3544
|
}
|
|
3409
|
-
async function loadGLTFFromBlobWithBundle(blob,
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
aggressiveImport,
|
|
3418
|
-
rootBounds,
|
|
3419
|
-
{ blob }
|
|
3420
|
-
);
|
|
3421
|
-
} finally {
|
|
3422
|
-
URL.revokeObjectURL(objectUrl);
|
|
3423
|
-
}
|
|
3424
|
-
}
|
|
3425
|
-
const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
|
|
3426
|
-
return new Promise((resolve, reject) => {
|
|
3427
|
-
const loader = new GLTFLoader();
|
|
3428
|
-
loader.setDRACOLoader(new DRACOLoader());
|
|
3429
|
-
loader.parse(
|
|
3430
|
-
arrayBuffer,
|
|
3431
|
-
"",
|
|
3432
|
-
async (gltf) => {
|
|
3433
|
-
try {
|
|
3434
|
-
const parserJson = await resolveParserJson(
|
|
3435
|
-
gltf?.parser?.json,
|
|
3436
|
-
{ arrayBuffer }
|
|
3437
|
-
);
|
|
3438
|
-
const asset = parseScene(
|
|
3439
|
-
gltf.scene,
|
|
3440
|
-
actualizedNamespaces,
|
|
3441
|
-
aggressiveImport,
|
|
3442
|
-
rootBounds,
|
|
3443
|
-
parserJson,
|
|
3444
|
-
gltf.animations
|
|
3445
|
-
);
|
|
3446
|
-
resolve(asset);
|
|
3447
|
-
} catch (error) {
|
|
3448
|
-
if (error instanceof Error) {
|
|
3449
|
-
reject(error);
|
|
3450
|
-
} else {
|
|
3451
|
-
reject(new Error(String(error)));
|
|
3452
|
-
}
|
|
3453
|
-
}
|
|
3454
|
-
},
|
|
3455
|
-
(error) => {
|
|
3456
|
-
reject(new Error(`Error loading GLTF: ${error.message}`));
|
|
3457
|
-
}
|
|
3458
|
-
);
|
|
3545
|
+
async function loadGLTFFromBlobWithBundle(blob, aggressiveImport = false, rootBounds) {
|
|
3546
|
+
recordRenderCounter("gltfBlobLoadCount");
|
|
3547
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
3548
|
+
const loader = createTrackedGLTFLoader();
|
|
3549
|
+
const gltf = await new Promise((resolve, reject) => {
|
|
3550
|
+
loader.parse(arrayBuffer, "", resolve, (error) => {
|
|
3551
|
+
reject(new Error(`Error loading GLTF: ${error.message}`));
|
|
3552
|
+
});
|
|
3459
3553
|
});
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
// src/functions/load-gltf-blob.ts
|
|
3463
|
-
import { DRACOLoader as DRACOLoader2, GLTFLoader as GLTFLoader2 } from "three-stdlib";
|
|
3464
|
-
var loadGltfFromBlob = (blob, namespaces) => {
|
|
3465
|
-
return new Promise((resolve, reject) => {
|
|
3466
|
-
const loader = new GLTFLoader2();
|
|
3467
|
-
loader.setDRACOLoader(new DRACOLoader2());
|
|
3468
|
-
const reader = new FileReader();
|
|
3469
|
-
reader.onload = () => {
|
|
3470
|
-
const arrayBuffer = reader.result;
|
|
3471
|
-
loader.parse(
|
|
3472
|
-
arrayBuffer,
|
|
3473
|
-
"",
|
|
3474
|
-
// Base path for resolving external resources
|
|
3475
|
-
(gltf) => {
|
|
3476
|
-
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
3477
|
-
resolve(traverseThree(gltf.scene, actualizedNamespaces));
|
|
3478
|
-
},
|
|
3479
|
-
(error) => {
|
|
3480
|
-
reject(new Error(`Error loading GLTF: ${error.message}`));
|
|
3481
|
-
}
|
|
3482
|
-
);
|
|
3483
|
-
};
|
|
3484
|
-
reader.onerror = () => {
|
|
3485
|
-
reject(new Error("Failed to read Blob as ArrayBuffer."));
|
|
3486
|
-
};
|
|
3487
|
-
reader.readAsArrayBuffer(blob);
|
|
3554
|
+
const parserJson = await resolveParserJson(gltf?.parser?.json, {
|
|
3555
|
+
arrayBuffer
|
|
3488
3556
|
});
|
|
3489
|
-
|
|
3557
|
+
return parseScene(
|
|
3558
|
+
gltf.scene,
|
|
3559
|
+
aggressiveImport,
|
|
3560
|
+
rootBounds,
|
|
3561
|
+
parserJson,
|
|
3562
|
+
gltf.animations
|
|
3563
|
+
);
|
|
3564
|
+
}
|
|
3490
3565
|
|
|
3491
3566
|
// src/functions/export.ts
|
|
3492
3567
|
import { GLTFExporter } from "three-stdlib";
|
|
@@ -3501,17 +3576,6 @@ function normalizeExportError(error) {
|
|
|
3501
3576
|
}
|
|
3502
3577
|
return new Error("Failed to export scene.");
|
|
3503
3578
|
}
|
|
3504
|
-
function triggerBlobDownload(blob, filename) {
|
|
3505
|
-
const url = URL.createObjectURL(blob);
|
|
3506
|
-
const link = document.createElement("a");
|
|
3507
|
-
link.href = url;
|
|
3508
|
-
link.download = filename;
|
|
3509
|
-
link.style.display = "none";
|
|
3510
|
-
document.body.appendChild(link);
|
|
3511
|
-
link.click();
|
|
3512
|
-
document.body.removeChild(link);
|
|
3513
|
-
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
3514
|
-
}
|
|
3515
3579
|
var GLB_MAGIC2 = 1179937895;
|
|
3516
3580
|
var GLB_VERSION2 = 2;
|
|
3517
3581
|
var GLB_JSON_CHUNK_TYPE2 = 1313821514;
|
|
@@ -3593,7 +3657,7 @@ function normalizeExportedSceneJson(json, fallbackSceneName) {
|
|
|
3593
3657
|
}
|
|
3594
3658
|
return changed;
|
|
3595
3659
|
}
|
|
3596
|
-
function
|
|
3660
|
+
function patchGlbJson(buffer, mutate) {
|
|
3597
3661
|
if (buffer.byteLength < GLB_HEADER_BYTES2 + GLB_CHUNK_HEADER_BYTES2) {
|
|
3598
3662
|
return buffer;
|
|
3599
3663
|
}
|
|
@@ -3623,8 +3687,7 @@ function sanitizeExportedGlb(buffer, fallbackSceneName) {
|
|
|
3623
3687
|
} catch {
|
|
3624
3688
|
return buffer;
|
|
3625
3689
|
}
|
|
3626
|
-
|
|
3627
|
-
if (!changed) {
|
|
3690
|
+
if (!mutate(jsonPayload)) {
|
|
3628
3691
|
return buffer;
|
|
3629
3692
|
}
|
|
3630
3693
|
const encodedJson = new TextEncoder().encode(JSON.stringify(jsonPayload));
|
|
@@ -3646,11 +3709,41 @@ function sanitizeExportedGlb(buffer, fallbackSceneName) {
|
|
|
3646
3709
|
sanitizedBytes.set(remainingChunks, jsonChunkStart + paddedJsonLength);
|
|
3647
3710
|
return sanitized;
|
|
3648
3711
|
}
|
|
3649
|
-
function
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3712
|
+
function sanitizeExportedGlb(buffer, fallbackSceneName) {
|
|
3713
|
+
return patchGlbJson(
|
|
3714
|
+
buffer,
|
|
3715
|
+
(json) => normalizeExportedSceneJson(json, fallbackSceneName)
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3718
|
+
function patchVizijBundleMetadata(glb, metadata) {
|
|
3719
|
+
return patchGlbJson(glb, (json) => {
|
|
3720
|
+
const carriers = [];
|
|
3721
|
+
const rootExtensions = json.extensions;
|
|
3722
|
+
if (rootExtensions && typeof rootExtensions === "object") {
|
|
3723
|
+
carriers.push(rootExtensions);
|
|
3724
|
+
}
|
|
3725
|
+
const nodes = Array.isArray(json.nodes) ? json.nodes : [];
|
|
3726
|
+
for (const node of nodes) {
|
|
3727
|
+
const extensions = node?.extensions;
|
|
3728
|
+
if (extensions && typeof extensions === "object") {
|
|
3729
|
+
carriers.push(extensions);
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
let patched = false;
|
|
3733
|
+
for (const extensions of carriers) {
|
|
3734
|
+
const bundle = extensions.VIZIJ_bundle;
|
|
3735
|
+
if (!bundle || typeof bundle !== "object") {
|
|
3736
|
+
continue;
|
|
3737
|
+
}
|
|
3738
|
+
const record = bundle;
|
|
3739
|
+
const existing = record.metadata && typeof record.metadata === "object" ? record.metadata : {};
|
|
3740
|
+
record.metadata = { ...existing, ...metadata };
|
|
3741
|
+
patched = true;
|
|
3742
|
+
}
|
|
3743
|
+
return patched;
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
async function exportScene(root, options = {}) {
|
|
3654
3747
|
const exporter = new GLTFExporter();
|
|
3655
3748
|
exporter.register(() => ({
|
|
3656
3749
|
writeMesh(mesh, meshDef) {
|
|
@@ -3660,81 +3753,330 @@ function exportScene(data, fileNameOrOptions = "scene.glb") {
|
|
|
3660
3753
|
}
|
|
3661
3754
|
}
|
|
3662
3755
|
}));
|
|
3663
|
-
const
|
|
3664
|
-
const exportRoot = sourceRoot instanceof THREE6.Scene ? sourceRoot : sourceRoot.clone(true);
|
|
3756
|
+
const exportRoot = root instanceof THREE6.Scene ? root : root.clone(true);
|
|
3665
3757
|
const exportTarget = exportRoot instanceof THREE6.Scene ? exportRoot : (() => {
|
|
3666
3758
|
const scene = new THREE6.Scene();
|
|
3667
|
-
scene.name =
|
|
3759
|
+
scene.name = root.name?.trim() || "Scene";
|
|
3668
3760
|
scene.add(exportRoot);
|
|
3669
3761
|
return scene;
|
|
3670
3762
|
})();
|
|
3671
|
-
const detachBundle =
|
|
3763
|
+
const detachBundle = options.bundle ? applyVizijBundle(exportRoot, options.bundle) : () => {
|
|
3672
3764
|
};
|
|
3673
|
-
const
|
|
3674
|
-
|
|
3675
|
-
trs: true,
|
|
3676
|
-
onlyVisible: false,
|
|
3677
|
-
binary,
|
|
3678
|
-
includeCustomExtensions: true
|
|
3679
|
-
};
|
|
3680
|
-
if (animationClips.length > 0) {
|
|
3681
|
-
exporterOptions.animations = animationClips;
|
|
3682
|
-
}
|
|
3765
|
+
const animations = (options.animations ?? []).filter(Boolean);
|
|
3766
|
+
let gltf;
|
|
3683
3767
|
try {
|
|
3684
|
-
exporter.
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
return;
|
|
3692
|
-
}
|
|
3693
|
-
const sanitizedGltf = sanitizeExportedGlb(
|
|
3694
|
-
gltf,
|
|
3695
|
-
data.name?.trim() || void 0
|
|
3696
|
-
);
|
|
3697
|
-
const trimmed = fileName.trim();
|
|
3698
|
-
const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
|
|
3699
|
-
const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
|
|
3700
|
-
triggerBlobDownload(
|
|
3701
|
-
new Blob([sanitizedGltf], {
|
|
3702
|
-
type: "application/octet-stream"
|
|
3703
|
-
}),
|
|
3704
|
-
downloadName
|
|
3705
|
-
);
|
|
3706
|
-
options.onComplete?.();
|
|
3707
|
-
},
|
|
3708
|
-
(error) => {
|
|
3709
|
-
detachBundle();
|
|
3710
|
-
options.onError?.(normalizeExportError(error));
|
|
3711
|
-
},
|
|
3712
|
-
exporterOptions
|
|
3713
|
-
);
|
|
3768
|
+
gltf = await exporter.parseAsync(exportTarget, {
|
|
3769
|
+
trs: true,
|
|
3770
|
+
onlyVisible: false,
|
|
3771
|
+
binary: true,
|
|
3772
|
+
includeCustomExtensions: true,
|
|
3773
|
+
...animations.length > 0 ? { animations } : {}
|
|
3774
|
+
});
|
|
3714
3775
|
} catch (error) {
|
|
3776
|
+
throw normalizeExportError(error);
|
|
3777
|
+
} finally {
|
|
3715
3778
|
detachBundle();
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
throw
|
|
3779
|
+
}
|
|
3780
|
+
if (!(gltf instanceof ArrayBuffer)) {
|
|
3781
|
+
throw new Error("Failed to export scene.");
|
|
3782
|
+
}
|
|
3783
|
+
return sanitizeExportedGlb(gltf, root.name?.trim() || void 0);
|
|
3784
|
+
}
|
|
3785
|
+
|
|
3786
|
+
// src/functions/build-scene-graph.ts
|
|
3787
|
+
import * as THREE7 from "three";
|
|
3788
|
+
import {
|
|
3789
|
+
instanceOfRawEuler as instanceOfRawEuler5,
|
|
3790
|
+
instanceOfRawHSL as instanceOfRawHSL4,
|
|
3791
|
+
instanceOfRawNumber as instanceOfRawNumber5,
|
|
3792
|
+
instanceOfRawRGB as instanceOfRawRGB4,
|
|
3793
|
+
instanceOfRawVector2 as instanceOfRawVector24,
|
|
3794
|
+
instanceOfRawVector3 as instanceOfRawVector35
|
|
3795
|
+
} from "@vizij/utils";
|
|
3796
|
+
THREE7.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
3797
|
+
function buildSceneGraph(world, animatables, rootId) {
|
|
3798
|
+
const entry = world[rootId];
|
|
3799
|
+
if (!entry) {
|
|
3800
|
+
throw new Error(`The world has no element "${rootId}".`);
|
|
3801
|
+
}
|
|
3802
|
+
const used = {};
|
|
3803
|
+
for (const feature of Object.values(entry.features)) {
|
|
3804
|
+
if (feature.animated) {
|
|
3805
|
+
used[feature.value] = animatableOf(animatables, feature.value);
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
const robotData = createStoredRenderable(entry, used);
|
|
3809
|
+
switch (entry.type) {
|
|
3810
|
+
case "group": {
|
|
3811
|
+
const object = new THREE7.Group();
|
|
3812
|
+
object.name = entry.name;
|
|
3813
|
+
object.userData = { gltfExtensions: { RobotData: robotData } };
|
|
3814
|
+
applyFeatures(entry.features, animatables, groupTransform(object));
|
|
3815
|
+
for (const child of entry.children) {
|
|
3816
|
+
object.add(buildSceneGraph(world, animatables, child));
|
|
3817
|
+
}
|
|
3818
|
+
return object;
|
|
3819
|
+
}
|
|
3820
|
+
case "shape": {
|
|
3821
|
+
const geometry = entry.geometry.clone();
|
|
3822
|
+
if (entry.name) {
|
|
3823
|
+
geometry.name = entry.name;
|
|
3824
|
+
}
|
|
3825
|
+
const material = createMaterial(entry.material);
|
|
3826
|
+
material.name = deriveMaterialName(entry, used) ?? entry.name ?? "";
|
|
3827
|
+
const object = new THREE7.Mesh(geometry, material);
|
|
3828
|
+
object.name = entry.name;
|
|
3829
|
+
object.userData = { gltfExtensions: { RobotData: robotData } };
|
|
3830
|
+
applyFeatures(entry.features, animatables, {
|
|
3831
|
+
...shapeTransform(object),
|
|
3832
|
+
...materialFactors(material),
|
|
3833
|
+
...morphWeights(object, entry)
|
|
3834
|
+
});
|
|
3835
|
+
for (const child of entry.children ?? []) {
|
|
3836
|
+
object.add(buildSceneGraph(world, animatables, child));
|
|
3837
|
+
}
|
|
3838
|
+
return object;
|
|
3839
|
+
}
|
|
3840
|
+
default:
|
|
3841
|
+
throw new Error(
|
|
3842
|
+
`Element "${rootId}" is a ${entry.type}, which has no exported form.`
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
function animatableOf(animatables, id) {
|
|
3847
|
+
const animatable = animatables[id];
|
|
3848
|
+
if (!animatable) {
|
|
3849
|
+
throw new Error(`No animatable "${id}".`);
|
|
3850
|
+
}
|
|
3851
|
+
return animatable;
|
|
3852
|
+
}
|
|
3853
|
+
function applyFeatures(features, animatables, handlers) {
|
|
3854
|
+
for (const [key, handler] of Object.entries(handlers)) {
|
|
3855
|
+
const feature = features[key];
|
|
3856
|
+
if (!feature) {
|
|
3857
|
+
continue;
|
|
3858
|
+
}
|
|
3859
|
+
const value = feature.animated ? authoredDefault(animatableOf(animatables, feature.value)) : feature.value;
|
|
3860
|
+
if (value !== void 0) {
|
|
3861
|
+
handler(value);
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
function groupTransform(object) {
|
|
3866
|
+
return {
|
|
3867
|
+
translation: (value) => {
|
|
3868
|
+
if (instanceOfRawVector35(value)) {
|
|
3869
|
+
object.position.set(value.x, value.y, value.z);
|
|
3870
|
+
} else if (instanceOfRawVector24(value)) {
|
|
3871
|
+
object.position.set(value.x, value.y, object.position.z);
|
|
3872
|
+
}
|
|
3873
|
+
},
|
|
3874
|
+
rotation: (value) => {
|
|
3875
|
+
if (instanceOfRawEuler5(value)) {
|
|
3876
|
+
object.rotation.set(value.x, value.y, value.z, "ZYX");
|
|
3877
|
+
} else if (instanceOfRawNumber5(value)) {
|
|
3878
|
+
object.rotation.set(0, 0, 0);
|
|
3879
|
+
object.rotateZ(value);
|
|
3880
|
+
}
|
|
3881
|
+
},
|
|
3882
|
+
scale: (value) => {
|
|
3883
|
+
if (instanceOfRawVector35(value)) {
|
|
3884
|
+
if (value.x === null || value.y === null || value.z === null) {
|
|
3885
|
+
object.scale.set(0.1, 0.1, 0.1);
|
|
3886
|
+
} else {
|
|
3887
|
+
object.scale.set(value.x, value.y, value.z);
|
|
3888
|
+
}
|
|
3889
|
+
} else if (instanceOfRawNumber5(value)) {
|
|
3890
|
+
object.scale.set(value, value, value);
|
|
3891
|
+
} else {
|
|
3892
|
+
object.scale.set(1, 1, 1);
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
};
|
|
3896
|
+
}
|
|
3897
|
+
function shapeTransform(object) {
|
|
3898
|
+
return {
|
|
3899
|
+
translation: (value) => {
|
|
3900
|
+
if (instanceOfRawVector35(value)) {
|
|
3901
|
+
object.position.set(value.x, value.y, value.z);
|
|
3902
|
+
}
|
|
3903
|
+
},
|
|
3904
|
+
rotation: (value) => {
|
|
3905
|
+
if (instanceOfRawEuler5(value)) {
|
|
3906
|
+
object.rotation.set(value.x, value.y, value.z, "ZYX");
|
|
3907
|
+
}
|
|
3908
|
+
},
|
|
3909
|
+
scale: (value) => {
|
|
3910
|
+
if (instanceOfRawVector35(value)) {
|
|
3911
|
+
object.scale.set(value.x, value.y, value.z);
|
|
3912
|
+
} else if (instanceOfRawNumber5(value)) {
|
|
3913
|
+
object.scale.set(value, value, value);
|
|
3914
|
+
} else {
|
|
3915
|
+
object.scale.set(1, 1, 1);
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
};
|
|
3919
|
+
}
|
|
3920
|
+
function materialFactors(material) {
|
|
3921
|
+
const standard = material;
|
|
3922
|
+
const phong = material;
|
|
3923
|
+
return {
|
|
3924
|
+
opacity: (value) => {
|
|
3925
|
+
if (instanceOfRawNumber5(value)) {
|
|
3926
|
+
material.opacity = value;
|
|
3927
|
+
material.transparent = value < 1;
|
|
3928
|
+
}
|
|
3929
|
+
},
|
|
3930
|
+
color: (value) => {
|
|
3931
|
+
if (!standard.color) {
|
|
3932
|
+
return;
|
|
3933
|
+
}
|
|
3934
|
+
if (instanceOfRawRGB4(value)) {
|
|
3935
|
+
standard.color.setRGB(value.r, value.g, value.b);
|
|
3936
|
+
} else if (instanceOfRawVector35(value)) {
|
|
3937
|
+
standard.color.setRGB(value.x, value.y, value.z);
|
|
3938
|
+
} else if (instanceOfRawHSL4(value)) {
|
|
3939
|
+
standard.color.setHSL(value.h, value.s, value.l);
|
|
3940
|
+
}
|
|
3941
|
+
},
|
|
3942
|
+
roughness: (value) => {
|
|
3943
|
+
if (standard.roughness !== void 0 && instanceOfRawNumber5(value)) {
|
|
3944
|
+
standard.roughness = value;
|
|
3945
|
+
}
|
|
3946
|
+
},
|
|
3947
|
+
metalness: (value) => {
|
|
3948
|
+
if (standard.metalness !== void 0 && instanceOfRawNumber5(value)) {
|
|
3949
|
+
standard.metalness = value;
|
|
3950
|
+
}
|
|
3951
|
+
},
|
|
3952
|
+
shininess: (value) => {
|
|
3953
|
+
if (phong.shininess !== void 0 && instanceOfRawNumber5(value)) {
|
|
3954
|
+
phong.shininess = value;
|
|
3955
|
+
}
|
|
3956
|
+
},
|
|
3957
|
+
emissive: (value) => {
|
|
3958
|
+
if (standard.emissive && instanceOfRawRGB4(value)) {
|
|
3959
|
+
standard.emissive.setRGB(value.r, value.g, value.b);
|
|
3960
|
+
}
|
|
3961
|
+
},
|
|
3962
|
+
emissiveIntensity: (value) => {
|
|
3963
|
+
if (standard.emissiveIntensity !== void 0 && instanceOfRawNumber5(value)) {
|
|
3964
|
+
standard.emissiveIntensity = value;
|
|
3965
|
+
}
|
|
3966
|
+
},
|
|
3967
|
+
specular: (value) => {
|
|
3968
|
+
if (phong.specular && instanceOfRawRGB4(value)) {
|
|
3969
|
+
phong.specular.setRGB(value.r, value.g, value.b);
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
};
|
|
3973
|
+
}
|
|
3974
|
+
function morphWeights(object, shape) {
|
|
3975
|
+
const targets = shape.morphTargets ?? [];
|
|
3976
|
+
if (targets.length === 0) {
|
|
3977
|
+
return {};
|
|
3978
|
+
}
|
|
3979
|
+
const influences = targets.map(() => 0);
|
|
3980
|
+
object.morphTargetDictionary = Object.fromEntries(
|
|
3981
|
+
targets.map((target, index) => [target, index])
|
|
3982
|
+
);
|
|
3983
|
+
object.morphTargetInfluences = influences;
|
|
3984
|
+
return Object.fromEntries(
|
|
3985
|
+
targets.map((target, index) => [
|
|
3986
|
+
target,
|
|
3987
|
+
(value) => {
|
|
3988
|
+
if (instanceOfRawNumber5(value)) {
|
|
3989
|
+
influences[index] = value;
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
])
|
|
3993
|
+
);
|
|
3994
|
+
}
|
|
3995
|
+
function createMaterial(kind) {
|
|
3996
|
+
const parameters = { side: THREE7.DoubleSide };
|
|
3997
|
+
switch (kind) {
|
|
3998
|
+
case "basic" /* Basic */:
|
|
3999
|
+
return new THREE7.MeshBasicMaterial(parameters);
|
|
4000
|
+
case "lambert" /* Lambert */:
|
|
4001
|
+
return new THREE7.MeshLambertMaterial(parameters);
|
|
4002
|
+
case "phong" /* Phong */:
|
|
4003
|
+
return new THREE7.MeshPhongMaterial(parameters);
|
|
4004
|
+
case "normal" /* Normal */:
|
|
4005
|
+
return new THREE7.MeshNormalMaterial(parameters);
|
|
4006
|
+
case "standard" /* Standard */:
|
|
4007
|
+
return new THREE7.MeshStandardMaterial(parameters);
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
var SCALAR_KEYS = ["f32", "f64", "i64", "i32", "u64", "u32", "float"];
|
|
4011
|
+
function scalarOf(value) {
|
|
4012
|
+
if (typeof value === "number") {
|
|
4013
|
+
return value;
|
|
4014
|
+
}
|
|
4015
|
+
if (value && typeof value === "object") {
|
|
4016
|
+
for (const key of SCALAR_KEYS) {
|
|
4017
|
+
const scalar = value[key];
|
|
4018
|
+
if (typeof scalar === "number") {
|
|
4019
|
+
return scalar;
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
return void 0;
|
|
4024
|
+
}
|
|
4025
|
+
function authoredDefault(animatable) {
|
|
4026
|
+
const value = animatable.default;
|
|
4027
|
+
const scalar = scalarOf(value);
|
|
4028
|
+
if (scalar !== void 0) {
|
|
4029
|
+
return scalar;
|
|
4030
|
+
}
|
|
4031
|
+
const fields = value?.struct?.fields;
|
|
4032
|
+
if (!Array.isArray(fields)) {
|
|
4033
|
+
return value;
|
|
4034
|
+
}
|
|
4035
|
+
const n = fields.map(
|
|
4036
|
+
(field) => scalarOf(field?.value) ?? 0
|
|
4037
|
+
);
|
|
4038
|
+
switch (animatable.type) {
|
|
4039
|
+
case "vector3":
|
|
4040
|
+
case "euler":
|
|
4041
|
+
return { x: n[0], y: n[1], z: n[2] };
|
|
4042
|
+
case "vector2":
|
|
4043
|
+
return { x: n[0], y: n[1] };
|
|
4044
|
+
case "rgb":
|
|
4045
|
+
return { r: n[0], g: n[1], b: n[2] };
|
|
4046
|
+
case "hsl":
|
|
4047
|
+
return { h: n[0], s: n[1], l: n[2] };
|
|
4048
|
+
default:
|
|
4049
|
+
return void 0;
|
|
3719
4050
|
}
|
|
3720
4051
|
}
|
|
3721
4052
|
export {
|
|
4053
|
+
DEFAULT_TONE_MAPPING_MODE,
|
|
3722
4054
|
EmptyModelError,
|
|
3723
4055
|
InnerVizij,
|
|
3724
4056
|
ShapeMaterial,
|
|
4057
|
+
TONE_MAPPING_LABELS,
|
|
4058
|
+
TONE_MAPPING_MODES,
|
|
3725
4059
|
Vizij,
|
|
3726
4060
|
VizijContext,
|
|
3727
4061
|
VizijSlice,
|
|
3728
4062
|
applyVizijBundle,
|
|
4063
|
+
buildSceneGraph,
|
|
3729
4064
|
createVizijStore,
|
|
4065
|
+
deriveMorphFeatureKeys,
|
|
4066
|
+
deriveRootBounds,
|
|
3730
4067
|
exportScene,
|
|
3731
4068
|
extractVizijBundle,
|
|
4069
|
+
isToneMappingMode,
|
|
3732
4070
|
loadGLTF,
|
|
3733
4071
|
loadGLTFFromBlob,
|
|
3734
4072
|
loadGLTFFromBlobWithBundle,
|
|
3735
4073
|
loadGLTFWithBundle,
|
|
3736
|
-
|
|
4074
|
+
normalizeToneMappingMode,
|
|
3737
4075
|
parseGlbJsonChunk,
|
|
4076
|
+
patchGlbJson,
|
|
4077
|
+
patchVizijBundleMetadata,
|
|
4078
|
+
resolveToneMapping,
|
|
4079
|
+
sanitizeMorphKey,
|
|
3738
4080
|
useDefaultVizijStore,
|
|
3739
4081
|
useFeatures,
|
|
3740
4082
|
useVizijStore,
|