redhotmagma-visualization 1.22.4 → 1.22.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/DevApp.js +113 -0
- package/src/Three/Three3DScene.js +264 -69
package/package.json
CHANGED
package/src/DevApp.js
CHANGED
|
@@ -187,6 +187,119 @@ const modelData = {
|
|
|
187
187
|
},
|
|
188
188
|
},
|
|
189
189
|
},
|
|
190
|
+
FlexibleOptionsLocalParams: {
|
|
191
|
+
designAreaList: [],
|
|
192
|
+
configuration: {
|
|
193
|
+
visualizationData: {
|
|
194
|
+
sceneData: [
|
|
195
|
+
{ src: "models/3d/GroundVehicle/SceneBase.gltf" },
|
|
196
|
+
{
|
|
197
|
+
src: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
198
|
+
params: {
|
|
199
|
+
material: { params: { map: "FunnyWheel.jpg" } },
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
src: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
204
|
+
params: {
|
|
205
|
+
material: {
|
|
206
|
+
params: {
|
|
207
|
+
map: "FunnyWheel.jpg",
|
|
208
|
+
color: "#FF00FF",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
position: {
|
|
212
|
+
z: -3,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
src: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
218
|
+
params: {
|
|
219
|
+
material: {
|
|
220
|
+
params: {
|
|
221
|
+
map: "FunnyWheel.jpg",
|
|
222
|
+
color: "#00FF00",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
position: {
|
|
226
|
+
z: 3,
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
FlexibleOptionsGlobalParams: {
|
|
235
|
+
designAreaList: [],
|
|
236
|
+
configuration: {
|
|
237
|
+
visualizationData: {
|
|
238
|
+
sceneData: [
|
|
239
|
+
{ src: "models/3d/GroundVehicle/SceneBase.gltf" },
|
|
240
|
+
{ src: "models/3d/GroundVehicle/Body.gltf" },
|
|
241
|
+
{
|
|
242
|
+
model: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
243
|
+
params: {
|
|
244
|
+
position: {
|
|
245
|
+
z: 0,
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
model: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
251
|
+
params: {
|
|
252
|
+
position: {
|
|
253
|
+
z: -3.75,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
model: "models/3d/GroundVehicle/WheelsFront.gltf",
|
|
259
|
+
params: {
|
|
260
|
+
position: {
|
|
261
|
+
z: -5.05,
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
params: {
|
|
267
|
+
objectName: "Wheels",
|
|
268
|
+
material: {
|
|
269
|
+
params: {
|
|
270
|
+
map: "FunnyWheel.jpg",
|
|
271
|
+
color: "#FF00FF",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
files: {
|
|
276
|
+
"FunnyWheel.jpg": "models/3d/GroundVehicle/FunnyWheel.jpg",
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
params: {
|
|
281
|
+
objectName: "GroundVehicleMesh_0",
|
|
282
|
+
material: {
|
|
283
|
+
params: {
|
|
284
|
+
color: "#00FFFF",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
params: {
|
|
291
|
+
material: {
|
|
292
|
+
params: {
|
|
293
|
+
materialName: "CustomizableMaterial",
|
|
294
|
+
color: "#FFFF00",
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
},
|
|
190
303
|
},
|
|
191
304
|
};
|
|
192
305
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Group,
|
|
9
9
|
HemisphereLight,
|
|
10
10
|
ImageLoader,
|
|
11
|
+
LoadingManager,
|
|
11
12
|
Mesh,
|
|
12
13
|
MeshBasicMaterial,
|
|
13
14
|
MeshPhongMaterial,
|
|
@@ -30,29 +31,31 @@ import { isMobileDevice } from "../Utils/isMobileDevice";
|
|
|
30
31
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
31
32
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
32
33
|
import get from "lodash/get";
|
|
33
|
-
import find from "lodash/find";
|
|
34
34
|
import size from "lodash/size";
|
|
35
35
|
import isPlainObject from "lodash/isPlainObject";
|
|
36
36
|
import { exportGLTF } from "./Exporters/glTFExporter";
|
|
37
|
+
import findIndex from "lodash/findIndex";
|
|
37
38
|
|
|
38
39
|
const UNSET = Symbol("unset");
|
|
39
40
|
|
|
41
|
+
const allowedObjectProps = ["position", "rotation", "scale"];
|
|
42
|
+
|
|
40
43
|
function getSrc(item) {
|
|
41
|
-
return
|
|
44
|
+
return item && (item.model || item.src);
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
function getPatch(oldObj, newObj) {
|
|
45
48
|
const patch = {};
|
|
46
49
|
newObj &&
|
|
47
50
|
Object.keys(newObj).forEach(prop => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
patch[prop] = newObj[prop];
|
|
51
|
+
if (isPlainObject(newObj[prop])) {
|
|
52
|
+
const objPatch = getPatch(oldObj && oldObj[prop], newObj[prop]);
|
|
53
|
+
if (Object.keys(objPatch).length) {
|
|
54
|
+
patch[prop] = objPatch;
|
|
55
55
|
}
|
|
56
|
+
} else {
|
|
57
|
+
patch[prop] = newObj[prop];
|
|
58
|
+
}
|
|
56
59
|
});
|
|
57
60
|
oldObj &&
|
|
58
61
|
Object.keys(oldObj).forEach(prop => {
|
|
@@ -88,7 +91,6 @@ function disposeNonUsedObjects(root, disposeTarget) {
|
|
|
88
91
|
for (const object of disposableObjects) {
|
|
89
92
|
if (referencedObjects.indexOf(object) === -1) {
|
|
90
93
|
object.dispose();
|
|
91
|
-
console.log("disposed object:", object.constructor.name, object.uuid);
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
}
|
|
@@ -103,6 +105,16 @@ function getMaterials(tree) {
|
|
|
103
105
|
return materials;
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
function getAllMaterials(tree) {
|
|
109
|
+
const materials = [];
|
|
110
|
+
tree.traverse(({ material }) => {
|
|
111
|
+
if (material && materials.indexOf(material) === -1) {
|
|
112
|
+
materials.push(material);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return materials;
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
function findImageBySrc(tree, src) {
|
|
107
119
|
let result = null;
|
|
108
120
|
tree.traverse(({ material }) => {
|
|
@@ -133,35 +145,80 @@ function setLightShadow(light, d = 50) {
|
|
|
133
145
|
}
|
|
134
146
|
}
|
|
135
147
|
|
|
148
|
+
function createIndexCounter() {
|
|
149
|
+
let counters = {};
|
|
150
|
+
const add = index => {
|
|
151
|
+
if (undefined === counters[index]) {
|
|
152
|
+
counters[index] = 0;
|
|
153
|
+
} else {
|
|
154
|
+
counters[index]++;
|
|
155
|
+
}
|
|
156
|
+
return counters[index];
|
|
157
|
+
};
|
|
158
|
+
const reset = () => {
|
|
159
|
+
counters = {};
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
add,
|
|
163
|
+
reset,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
136
167
|
function diffResourceLists(oldList, newList) {
|
|
137
168
|
const toBeRemoved = [];
|
|
138
169
|
const toBeAdded = [];
|
|
139
170
|
const toBeUpdated = [];
|
|
171
|
+
const toBeApplied = [];
|
|
172
|
+
const indexCounter = createIndexCounter();
|
|
173
|
+
|
|
140
174
|
for (const item of oldList) {
|
|
141
175
|
const src = getSrc(item);
|
|
142
|
-
|
|
176
|
+
if (!src) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const index = indexCounter.add(src);
|
|
180
|
+
|
|
181
|
+
const newItem = newList.filter(newItem => getSrc(newItem) === src)[index];
|
|
143
182
|
if (!newItem) {
|
|
144
|
-
toBeRemoved.push(
|
|
183
|
+
toBeRemoved.push({
|
|
184
|
+
...item,
|
|
185
|
+
index,
|
|
186
|
+
});
|
|
145
187
|
} else {
|
|
146
188
|
const patch = getPatch(item, newItem);
|
|
147
189
|
if (Object.keys(patch).length) {
|
|
148
190
|
toBeUpdated.push({
|
|
149
|
-
src,
|
|
150
191
|
...patch,
|
|
192
|
+
model: src,
|
|
193
|
+
index,
|
|
151
194
|
});
|
|
152
195
|
}
|
|
153
196
|
}
|
|
154
197
|
}
|
|
198
|
+
|
|
199
|
+
indexCounter.reset();
|
|
200
|
+
|
|
155
201
|
for (const item of newList) {
|
|
156
202
|
const src = getSrc(item);
|
|
157
|
-
if (!
|
|
158
|
-
|
|
203
|
+
if (!src) {
|
|
204
|
+
item.params && toBeApplied.push(item);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const index = indexCounter.add(src);
|
|
209
|
+
|
|
210
|
+
if (!oldList.filter(oldItem => getSrc(oldItem) === src)[index]) {
|
|
211
|
+
toBeAdded.push({
|
|
212
|
+
...item,
|
|
213
|
+
index,
|
|
214
|
+
});
|
|
159
215
|
}
|
|
160
216
|
}
|
|
161
217
|
return {
|
|
162
218
|
toBeRemoved,
|
|
163
219
|
toBeAdded,
|
|
164
220
|
toBeUpdated,
|
|
221
|
+
toBeApplied,
|
|
165
222
|
};
|
|
166
223
|
}
|
|
167
224
|
|
|
@@ -175,23 +232,30 @@ function findObjectWith(root, testFn) {
|
|
|
175
232
|
return result;
|
|
176
233
|
}
|
|
177
234
|
|
|
235
|
+
function findAllObjectsWith(root, testFn) {
|
|
236
|
+
const result = [];
|
|
237
|
+
root.traverse(object => testFn(object) && result.push(object));
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function mapObjectValues(object, valueMap) {
|
|
242
|
+
return Object.keys(object).reduce(
|
|
243
|
+
(res, key) => ({ ...res, [key]: (valueMap && valueMap[object[key]]) || object[key] }),
|
|
244
|
+
{}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
178
248
|
function setCameraAspectFromRendererSize(camera, renderer) {
|
|
179
249
|
const { width, height } = renderer.domElement;
|
|
180
250
|
camera.aspect = width / height;
|
|
181
251
|
camera.updateProjectionMatrix();
|
|
182
252
|
}
|
|
183
253
|
|
|
184
|
-
// todo: fix draco loader
|
|
185
|
-
|
|
186
254
|
export class Three3DScene extends Three3D {
|
|
187
255
|
DefaultCustomizableMaterialKey = "CustomizableMaterial";
|
|
188
256
|
|
|
189
257
|
clock = new Clock();
|
|
190
258
|
|
|
191
|
-
loader = this.createLoader();
|
|
192
|
-
|
|
193
|
-
imageLoader = this.createImageLoader();
|
|
194
|
-
|
|
195
259
|
animations = [];
|
|
196
260
|
|
|
197
261
|
currentResourceList = [];
|
|
@@ -214,24 +278,37 @@ export class Three3DScene extends Three3D {
|
|
|
214
278
|
cfg.modelBasePath ? (this._modelBasePath = cfg.modelBasePath) : (this._modelBasePath = "");
|
|
215
279
|
}
|
|
216
280
|
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
281
|
+
createLoadingManager(options = {}) {
|
|
282
|
+
const { basePath = "", resourcePath = "/" } = options;
|
|
283
|
+
|
|
284
|
+
const { onLoad, onProgress, onError } = this._loadingManager;
|
|
285
|
+
const loadingManager = new LoadingManager(onLoad, onProgress, onError);
|
|
286
|
+
loadingManager.setURLModifier(url => {
|
|
222
287
|
if (/^(data|blob):/.test(url)) {
|
|
223
288
|
return url;
|
|
224
289
|
}
|
|
290
|
+
const fixedBasePath = basePath.replace(/\/$/, "");
|
|
225
291
|
return url.indexOf("/") === 0
|
|
226
|
-
? `${
|
|
227
|
-
: `${
|
|
292
|
+
? `${fixedBasePath}${url}`
|
|
293
|
+
: `${fixedBasePath}${resourcePath}${url.replace("./", "")}`;
|
|
228
294
|
});
|
|
295
|
+
return loadingManager;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
createLoader(options = {}) {
|
|
299
|
+
const loadingManager = this.createLoadingManager(options);
|
|
300
|
+
|
|
301
|
+
const dracoLoader = new DRACOLoader();
|
|
302
|
+
dracoLoader.setDecoderPath("libs/draco/gltf/");
|
|
303
|
+
|
|
304
|
+
const loader = new GLTFLoader(loadingManager);
|
|
229
305
|
loader.setDRACOLoader(dracoLoader);
|
|
230
306
|
return loader;
|
|
231
307
|
}
|
|
232
308
|
|
|
233
|
-
createImageLoader() {
|
|
234
|
-
const
|
|
309
|
+
createImageLoader(options = {}) {
|
|
310
|
+
const loadingManager = this.createLoadingManager(options);
|
|
311
|
+
const imageLoader = new ImageLoader(loadingManager);
|
|
235
312
|
return imageLoader;
|
|
236
313
|
}
|
|
237
314
|
|
|
@@ -260,6 +337,7 @@ export class Three3DScene extends Three3D {
|
|
|
260
337
|
}
|
|
261
338
|
|
|
262
339
|
setupDefaultLightning() {}
|
|
340
|
+
|
|
263
341
|
loadModel() {}
|
|
264
342
|
|
|
265
343
|
createScene() {
|
|
@@ -323,10 +401,31 @@ export class Three3DScene extends Three3D {
|
|
|
323
401
|
});
|
|
324
402
|
}
|
|
325
403
|
|
|
326
|
-
async applyCustomizations(model, item) {
|
|
327
|
-
const {
|
|
404
|
+
async applyCustomizations(model, item, imageLoader, options = {}) {
|
|
405
|
+
const { saveAndRestore = true } = options;
|
|
406
|
+
|
|
407
|
+
const { params } = item;
|
|
328
408
|
if (params) {
|
|
329
409
|
Object.keys(params).forEach(p => {
|
|
410
|
+
// skip not allowed props
|
|
411
|
+
if (allowedObjectProps.indexOf(p) === -1) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
// restore original value first
|
|
415
|
+
if (params[p] === UNSET) {
|
|
416
|
+
if (model.originalValues && model.originalValues[p]) {
|
|
417
|
+
model[p].copy(model.originalValues[p]);
|
|
418
|
+
}
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
// store original value for later restoration
|
|
422
|
+
if (!model.originalValues) {
|
|
423
|
+
model.originalValues = {};
|
|
424
|
+
}
|
|
425
|
+
if (!model.originalValues[p]) {
|
|
426
|
+
model.originalValues[p] = model[p] ? model[p].clone() : model[p];
|
|
427
|
+
}
|
|
428
|
+
// apply the param values
|
|
330
429
|
switch (p) {
|
|
331
430
|
case "scale": {
|
|
332
431
|
const { x = 1, y = 1, z = 1 } = params[p];
|
|
@@ -343,39 +442,46 @@ export class Three3DScene extends Three3D {
|
|
|
343
442
|
});
|
|
344
443
|
}
|
|
345
444
|
|
|
346
|
-
// store & restore
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
mat.original
|
|
350
|
-
|
|
351
|
-
.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
texture.original
|
|
445
|
+
// store & restore original material and textures before applying new param values
|
|
446
|
+
saveAndRestore &&
|
|
447
|
+
Object.values(getMaterials(model)).map(mat => {
|
|
448
|
+
if (!mat.original) {
|
|
449
|
+
mat.original = mat.clone();
|
|
450
|
+
Object.values(mat)
|
|
451
|
+
.filter(value => value && value.isTexture)
|
|
452
|
+
.forEach(texture => {
|
|
453
|
+
if (!texture.original) {
|
|
454
|
+
texture.original = texture.clone();
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
} else {
|
|
458
|
+
mat.copy(mat.original);
|
|
459
|
+
Object.keys(mat).forEach(key => {
|
|
460
|
+
const value = mat[key];
|
|
461
|
+
if (value && value.original) {
|
|
462
|
+
value.copy(value.original);
|
|
355
463
|
}
|
|
356
464
|
});
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
Object.keys(mat).forEach(key => {
|
|
361
|
-
const value = mat[key];
|
|
362
|
-
if (value && value.original) {
|
|
363
|
-
value.copy(value.original);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
mat.needsUpdate = true;
|
|
367
|
-
}
|
|
368
|
-
});
|
|
465
|
+
mat.needsUpdate = true;
|
|
466
|
+
}
|
|
467
|
+
});
|
|
369
468
|
|
|
370
|
-
// set new params if provided
|
|
469
|
+
// set new material params if provided
|
|
470
|
+
// the material object should be located under item.params.material
|
|
471
|
+
// item.material is only for backward compatibility
|
|
472
|
+
const material = (params && params.material) || item.material;
|
|
371
473
|
if (material) {
|
|
372
474
|
const { params } = material;
|
|
373
475
|
params &&
|
|
374
476
|
(await Promise.all(
|
|
375
|
-
|
|
376
|
-
const { materialNames } = params;
|
|
477
|
+
getAllMaterials(model).map(async material => {
|
|
478
|
+
const { materialName, materialNames } = params;
|
|
377
479
|
// check materialNames list if provided
|
|
378
|
-
if (
|
|
480
|
+
if (materialNames instanceof Array && materialNames.indexOf(material.name) === -1) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
// check materialName match if provided
|
|
484
|
+
if (materialName && material.name !== materialName) {
|
|
379
485
|
return;
|
|
380
486
|
}
|
|
381
487
|
await Promise.all(
|
|
@@ -397,7 +503,7 @@ export class Three3DScene extends Three3D {
|
|
|
397
503
|
texture.image =
|
|
398
504
|
findImageBySrc(this.sceneContainer, `${this._modelBasePath}${params[p]}`) ||
|
|
399
505
|
(await new Promise((resolve, reject) =>
|
|
400
|
-
|
|
506
|
+
imageLoader.load(params[p], resolve, undefined, reject)
|
|
401
507
|
));
|
|
402
508
|
texture.needsUpdate = true;
|
|
403
509
|
material[p] = texture;
|
|
@@ -438,20 +544,30 @@ export class Three3DScene extends Three3D {
|
|
|
438
544
|
if ("string" === itemType) {
|
|
439
545
|
path = item;
|
|
440
546
|
} else if ("object" === itemType) {
|
|
441
|
-
path = item
|
|
547
|
+
path = getSrc(item);
|
|
442
548
|
}
|
|
443
|
-
const
|
|
444
|
-
|
|
549
|
+
const { resourcePath, modelFileName } = this.parseModelPath(path);
|
|
550
|
+
|
|
551
|
+
const loaderOptions = {
|
|
552
|
+
basePath: this._modelBasePath,
|
|
553
|
+
resourcePath,
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const modelLoader = this.createLoader(loaderOptions);
|
|
557
|
+
const imageLoader = this.createImageLoader(loaderOptions);
|
|
445
558
|
|
|
446
559
|
return new Promise((resolve, reject) => {
|
|
447
|
-
|
|
448
|
-
|
|
560
|
+
modelLoader.load(
|
|
561
|
+
modelFileName,
|
|
449
562
|
async gltf => {
|
|
450
563
|
const model = gltf.scene;
|
|
451
564
|
model.userData.path = path;
|
|
565
|
+
if (undefined !== item.index) {
|
|
566
|
+
model.userData.index = item.index;
|
|
567
|
+
}
|
|
452
568
|
this.fixImportedScene(model);
|
|
453
569
|
if ("object" === itemType) {
|
|
454
|
-
await this.applyCustomizations(model, item);
|
|
570
|
+
await this.applyCustomizations(model, item, imageLoader);
|
|
455
571
|
}
|
|
456
572
|
resolve(gltf);
|
|
457
573
|
},
|
|
@@ -461,7 +577,25 @@ export class Three3DScene extends Three3D {
|
|
|
461
577
|
});
|
|
462
578
|
}
|
|
463
579
|
|
|
580
|
+
findCustomizableMaterials(materialsObj) {
|
|
581
|
+
for (let key of this._customizableMaterialKeys) {
|
|
582
|
+
const mat = materialsObj[key];
|
|
583
|
+
if (mat) {
|
|
584
|
+
this.prepareCustomCanvasForMaterial(mat);
|
|
585
|
+
const index = findIndex(this._customizableMaterials, { name: key });
|
|
586
|
+
if (index === -1) {
|
|
587
|
+
this._customizableMaterials.push(mat);
|
|
588
|
+
} else if (this._customizableMaterials[index] !== mat) {
|
|
589
|
+
this._customizableMaterials[index] = mat;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
464
595
|
async initCustomizableMaterialsIfNeeded() {
|
|
596
|
+
// reset customizable materials to always find the right one in the loaded scene
|
|
597
|
+
this._customizableMaterialKeys.length = 0;
|
|
598
|
+
this._customizableMaterials.length = 0;
|
|
465
599
|
const materials = getMaterials(this.sceneContainer);
|
|
466
600
|
if (size(materials)) {
|
|
467
601
|
this.guessCustomizableMaterialNameIfNotSet(materials);
|
|
@@ -470,12 +604,25 @@ export class Three3DScene extends Three3D {
|
|
|
470
604
|
await this.dispatchMaterialUpdateEvent();
|
|
471
605
|
}
|
|
472
606
|
|
|
607
|
+
parseModelPath(path) {
|
|
608
|
+
const matches = path.match(/([^/].+\/)([^/]+)/);
|
|
609
|
+
if (!matches.length) {
|
|
610
|
+
throw new Error("Model path cannot be parsed: " + path);
|
|
611
|
+
}
|
|
612
|
+
const resourcePath = "/" + matches[1];
|
|
613
|
+
const modelFileName = matches[2];
|
|
614
|
+
return {
|
|
615
|
+
resourcePath,
|
|
616
|
+
modelFileName,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
473
620
|
async loadScene(resourceList) {
|
|
474
621
|
const { sceneContainer } = this;
|
|
475
622
|
|
|
476
623
|
this.stopAnimation();
|
|
477
624
|
|
|
478
|
-
const { toBeRemoved, toBeAdded, toBeUpdated } = diffResourceLists(
|
|
625
|
+
const { toBeRemoved, toBeAdded, toBeUpdated, toBeApplied } = diffResourceLists(
|
|
479
626
|
this.currentResourceList || [],
|
|
480
627
|
resourceList || []
|
|
481
628
|
);
|
|
@@ -488,7 +635,10 @@ export class Three3DScene extends Three3D {
|
|
|
488
635
|
const toBeDisposed = [];
|
|
489
636
|
toBeRemoved.forEach(item => {
|
|
490
637
|
const itemSrc = getSrc(item);
|
|
491
|
-
const object = findObjectWith(
|
|
638
|
+
const object = findObjectWith(
|
|
639
|
+
sceneContainer,
|
|
640
|
+
({ userData }) => userData.path === itemSrc && userData.index === item.index
|
|
641
|
+
);
|
|
492
642
|
if (object) {
|
|
493
643
|
object.parent.remove(object);
|
|
494
644
|
toBeDisposed.push(object);
|
|
@@ -496,7 +646,7 @@ export class Three3DScene extends Three3D {
|
|
|
496
646
|
});
|
|
497
647
|
toBeDisposed.forEach(object => disposeNonUsedObjects(sceneContainer, object));
|
|
498
648
|
|
|
499
|
-
const triggerLoadEvent = !!(toBeAdded.length || toBeUpdated.length);
|
|
649
|
+
const triggerLoadEvent = !!(toBeAdded.length || toBeUpdated.length || toBeApplied.length);
|
|
500
650
|
|
|
501
651
|
triggerLoadEvent && this.onLoadStart();
|
|
502
652
|
|
|
@@ -504,6 +654,8 @@ export class Three3DScene extends Three3D {
|
|
|
504
654
|
|
|
505
655
|
sceneParts.forEach(({ scene, animations }) => {
|
|
506
656
|
sceneContainer.add(scene);
|
|
657
|
+
|
|
658
|
+
// collect animations
|
|
507
659
|
if (animations.length) {
|
|
508
660
|
this.animations.push(
|
|
509
661
|
...animations.filter(
|
|
@@ -518,8 +670,49 @@ export class Three3DScene extends Three3D {
|
|
|
518
670
|
await Promise.all(
|
|
519
671
|
toBeUpdated.map(item => {
|
|
520
672
|
const itemSrc = getSrc(item);
|
|
521
|
-
const object = findObjectWith(
|
|
522
|
-
|
|
673
|
+
const object = findObjectWith(
|
|
674
|
+
sceneContainer,
|
|
675
|
+
({ userData }) => userData.path === itemSrc && userData.index === item.index
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
const path = getSrc(item);
|
|
679
|
+
const { resourcePath } = this.parseModelPath(path);
|
|
680
|
+
const loaderOptions = {
|
|
681
|
+
basePath: this._modelBasePath,
|
|
682
|
+
resourcePath,
|
|
683
|
+
};
|
|
684
|
+
const imageLoader = this.createImageLoader(loaderOptions);
|
|
685
|
+
|
|
686
|
+
return object && this.applyCustomizations(object, item, imageLoader);
|
|
687
|
+
})
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
// apply global or targeted param values
|
|
691
|
+
const imageLoader = this.createImageLoader({
|
|
692
|
+
basePath: this._modelBasePath,
|
|
693
|
+
});
|
|
694
|
+
await Promise.all(
|
|
695
|
+
toBeApplied.map(({ params: optionParams, files }) => {
|
|
696
|
+
// find model based on objectName
|
|
697
|
+
const { objectName, material = {} } = optionParams;
|
|
698
|
+
const objects = objectName
|
|
699
|
+
? findAllObjectsWith(sceneContainer, ({ name }) => name === objectName)
|
|
700
|
+
: sceneContainer.children;
|
|
701
|
+
const { params } = material;
|
|
702
|
+
const item = {
|
|
703
|
+
params: {
|
|
704
|
+
...optionParams,
|
|
705
|
+
material: {
|
|
706
|
+
...material,
|
|
707
|
+
params: params && mapObjectValues(params, files),
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
};
|
|
711
|
+
return Promise.all(
|
|
712
|
+
objects.map(object =>
|
|
713
|
+
this.applyCustomizations(object, item, imageLoader, { saveAndRestore: false })
|
|
714
|
+
)
|
|
715
|
+
);
|
|
523
716
|
})
|
|
524
717
|
);
|
|
525
718
|
|
|
@@ -562,6 +755,8 @@ export class Three3DScene extends Three3D {
|
|
|
562
755
|
const center = new Vector3();
|
|
563
756
|
box.getCenter(center);
|
|
564
757
|
|
|
758
|
+
this.cameraViews.default = null;
|
|
759
|
+
|
|
565
760
|
this.cameraViews = cameras.reduce((views, camera) => {
|
|
566
761
|
const position = new Vector3();
|
|
567
762
|
camera.getWorldPosition(position);
|