@combeenation/3d-viewer 6.2.1 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib-cjs/api/classes/element.js +3 -3
- package/dist/lib-cjs/api/classes/element.js.map +1 -1
- package/dist/lib-cjs/api/classes/variant.d.ts +0 -4
- package/dist/lib-cjs/api/classes/variant.js +0 -23
- package/dist/lib-cjs/api/classes/variant.js.map +1 -1
- package/dist/lib-cjs/api/classes/viewer.js +6 -2
- package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
- package/dist/lib-cjs/api/internal/sceneSetup.js +1 -1
- package/dist/lib-cjs/api/internal/sceneSetup.js.map +1 -1
- package/dist/lib-cjs/api/util/babylonHelper.d.ts +24 -5
- package/dist/lib-cjs/api/util/babylonHelper.js +82 -10
- package/dist/lib-cjs/api/util/babylonHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/sceneLoaderHelper.d.ts +3 -2
- package/dist/lib-cjs/api/util/sceneLoaderHelper.js +39 -25
- package/dist/lib-cjs/api/util/sceneLoaderHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/stringHelper.d.ts +5 -1
- package/dist/lib-cjs/api/util/stringHelper.js +8 -1
- package/dist/lib-cjs/api/util/stringHelper.js.map +1 -1
- package/dist/lib-cjs/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/api/classes/element.ts +3 -3
- package/src/api/classes/variant.ts +0 -26
- package/src/api/classes/viewer.ts +7 -2
- package/src/api/internal/sceneSetup.ts +1 -1
- package/src/api/util/babylonHelper.ts +88 -12
- package/src/api/util/sceneLoaderHelper.ts +38 -25
- package/src/api/util/stringHelper.ts +8 -1
- package/src/dev.ts +5 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@combeenation/3d-viewer",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "Combeenation 3D Viewer",
|
|
5
5
|
"homepage": "https://github.com/Combeenation/3d-viewer#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"src"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"clean-dist": "rimraf dist",
|
|
28
27
|
"bundle-analyzer": "npm run generate-profile && webpack-bundle-analyzer dist/webpack-stats.json dist/lib-full",
|
|
28
|
+
"clean-dist": "rimraf dist",
|
|
29
29
|
"dev": "cross-env NODE_ENV='dev' webpack serve --config build/webpack.conf.js --progress --hot",
|
|
30
30
|
"dist-cjs": "npm run clean-dist && npm run lint && tsc --project commonjs.tsconfig.json && npm run replace-version",
|
|
31
31
|
"dist-es6": "npm run clean-dist && npm run lint && tsc --project es6.tsconfig.json && npm run replace-version",
|
|
@@ -441,7 +441,7 @@ export class Element extends VariantParameterizable {
|
|
|
441
441
|
this._parameterObservers.set(Parameter.MATERIAL, [
|
|
442
442
|
async (element: Element, oldValue: ParameterValue, newValue: ParameterValue) => {
|
|
443
443
|
const materialName = newValue.toString();
|
|
444
|
-
element.nodes
|
|
444
|
+
for (const node of element.nodes) {
|
|
445
445
|
assertTransformNode(node, (node: AbstractMesh) => {
|
|
446
446
|
if (node instanceof InstancedMesh) {
|
|
447
447
|
throw new Error(
|
|
@@ -451,8 +451,8 @@ export class Element extends VariantParameterizable {
|
|
|
451
451
|
);
|
|
452
452
|
}
|
|
453
453
|
});
|
|
454
|
-
setMaterial(element.variant, node, materialName);
|
|
455
|
-
}
|
|
454
|
+
setMaterial(element.variant.viewer.scene, node, materialName, true, element.variant);
|
|
455
|
+
}
|
|
456
456
|
},
|
|
457
457
|
]);
|
|
458
458
|
this._parameterObservers.set(Parameter.MATERIAL_COLOR, [
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { deactivateTransformNode, getDottedPathForNode, injectNodeMetadata } from '../util/babylonHelper';
|
|
2
2
|
import { loadJson, mergeMaps } from '../util/resourceHelper';
|
|
3
|
-
import { createMaterialFromCbnAssets } from '../util/sceneLoaderHelper';
|
|
4
3
|
import { DottedPath } from './dottedPath';
|
|
5
4
|
import { Element } from './element';
|
|
6
5
|
import { Event } from './event';
|
|
@@ -421,31 +420,6 @@ export class Variant extends Parameterizable {
|
|
|
421
420
|
return element.getMesh(meshDottedPath);
|
|
422
421
|
}
|
|
423
422
|
|
|
424
|
-
/**
|
|
425
|
-
* Gets the Material defined in one of the variants glTFs by its id.
|
|
426
|
-
*/
|
|
427
|
-
public getOrCreateMaterial(id: string): Material {
|
|
428
|
-
const scene = this.viewer.scene;
|
|
429
|
-
|
|
430
|
-
for (const material of this.inheritedMaterials) {
|
|
431
|
-
if (material.id === id) {
|
|
432
|
-
return material;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
// fallback to dynamically created materials on scene
|
|
436
|
-
for (const material of scene.materials) {
|
|
437
|
-
if (material.id === id) {
|
|
438
|
-
return material;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
const cbnAssetMaterial = createMaterialFromCbnAssets(id, scene);
|
|
442
|
-
if (cbnAssetMaterial) {
|
|
443
|
-
return cbnAssetMaterial;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
throw new Error(`Material with id "${id}" does not exist for variant "${this.id}".`);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
423
|
/**
|
|
450
424
|
* Creates a living clone of this {@link Variant}. Will clone all parent {@link Variant}s in tree.
|
|
451
425
|
*
|
|
@@ -8,6 +8,7 @@ import { SpecStorage } from '../store/specStorage';
|
|
|
8
8
|
import { backgroundDomeName, envHelperMetadataName } from '../util/babylonHelper';
|
|
9
9
|
import { debounce, loadJavascript, loadJson } from '../util/resourceHelper';
|
|
10
10
|
import { getCustomCbnBabylonLoaderPlugin } from '../util/sceneLoaderHelper';
|
|
11
|
+
import { replaceDots } from '../util/stringHelper';
|
|
11
12
|
import { isMeshIncludedInExclusionList } from '../util/structureHelper';
|
|
12
13
|
import { AnimationInterface } from './animationInterface';
|
|
13
14
|
import { Event } from './event';
|
|
@@ -79,6 +80,10 @@ export class Viewer extends EventBroadcaster {
|
|
|
79
80
|
* This data is most likely coming from babylon assets from the Combeenation system but other sources are also valid.
|
|
80
81
|
*/
|
|
81
82
|
public static generateSpec(genData: SpecGenerationData[]): StructureJson {
|
|
83
|
+
// dots in the variant name indicate inheritance, but this should not be the case for an auto-generated spec
|
|
84
|
+
// therefore dots are exchanged with slashes
|
|
85
|
+
const safeGenData: SpecGenerationData[] = genData.map(data => ({ ...data, name: replaceDots(data.name) }));
|
|
86
|
+
|
|
82
87
|
const spec: StructureJson = {
|
|
83
88
|
// common scene settings as suggested in the viewer docs
|
|
84
89
|
scene: {
|
|
@@ -98,7 +103,7 @@ export class Viewer extends EventBroadcaster {
|
|
|
98
103
|
// create one instance for each input entry
|
|
99
104
|
// name and variant are named accordingly from the input, instance will be hidden by default and lazy loading
|
|
100
105
|
// is activated
|
|
101
|
-
instances:
|
|
106
|
+
instances: safeGenData.map(instanceData => ({
|
|
102
107
|
name: instanceData.name,
|
|
103
108
|
variant: instanceData.name,
|
|
104
109
|
lazy: true,
|
|
@@ -110,7 +115,7 @@ export class Viewer extends EventBroadcaster {
|
|
|
110
115
|
// variants definition is also mapped to the input array, using the name as key and url as glTF source
|
|
111
116
|
// no elements are created here, since this should be done automatically from the system
|
|
112
117
|
// => create one element which contains all root nodes of the imported 3d file (GLB or Babylon)
|
|
113
|
-
variants:
|
|
118
|
+
variants: safeGenData.reduce((accVariants, curVariant) => {
|
|
114
119
|
accVariants[curVariant.name] = {
|
|
115
120
|
glTF: curVariant.url,
|
|
116
121
|
};
|
|
@@ -121,7 +121,7 @@ const sceneSetup = async function (engine: Engine, sceneJson: SceneJson): Promis
|
|
|
121
121
|
cameras.push(camera);
|
|
122
122
|
}
|
|
123
123
|
// grounds
|
|
124
|
-
const groundDefinitions = get(sceneJson.scene, 'grounds') as GroundDefinitions;
|
|
124
|
+
const groundDefinitions = get(sceneJson.scene, 'grounds', {}) as GroundDefinitions;
|
|
125
125
|
if (!isEmpty(groundDefinitions)) {
|
|
126
126
|
for (const groundName in groundDefinitions) {
|
|
127
127
|
await processGround(scene, groundName, groundDefinitions[groundName]);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { DottedPath } from '../classes/dottedPath';
|
|
2
2
|
import { defaultEnvHelperColor, defaultSceneClearColor } from '../internal/sceneSetup';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
addMissingMaterialObserver,
|
|
5
|
+
createMaterialFromCbnAssets,
|
|
6
|
+
missingMaterialMetadataName,
|
|
7
|
+
} from './sceneLoaderHelper';
|
|
4
8
|
import { EnvironmentHelper } from '@babylonjs/core/Helpers/environmentHelper';
|
|
5
9
|
import { PhotoDome } from '@babylonjs/core/Helpers/photoDome';
|
|
6
10
|
import { HighlightLayer } from '@babylonjs/core/Layers/highlightLayer';
|
|
@@ -27,6 +31,7 @@ import { cloneDeep, get, has, merge } from 'lodash-es';
|
|
|
27
31
|
|
|
28
32
|
const backgroundDomeName = 'BackgroundDome_ViewerGenerated';
|
|
29
33
|
const envHelperMetadataName = 'viewerEnvHelper';
|
|
34
|
+
const materialWaitingToBeSetMetadataName = 'materialWaitingToBeSet';
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* @param node
|
|
@@ -354,32 +359,101 @@ const changeEnvironment = function (scene: Scene, envDef: EnvironmentDefinition)
|
|
|
354
359
|
};
|
|
355
360
|
|
|
356
361
|
/**
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
362
|
+
* Sets a material by a given material id as material property on the given node.
|
|
363
|
+
*
|
|
364
|
+
* If the material is not already available in the scene, the viewer tries to create a material based on a Combeenation
|
|
365
|
+
* [material asset](https://docs.combeenation.com/docs/howto-create-and-use-babylon-and-material-asset).
|
|
366
|
+
* This of course only works if the viewer is used inside a Combeenation configurator.
|
|
367
|
+
*
|
|
368
|
+
* Furthermore this function also defers the material creation if the node is not visible yet to improve network &
|
|
369
|
+
* viewer bootstrap performance as textures are automatically being lazy loaded only when they are actually visible in
|
|
370
|
+
* the scene.
|
|
371
|
+
*
|
|
372
|
+
* Finally the material will not be applied before all its textures have been loaded. In this way "flickering" effects
|
|
373
|
+
* will be avoided, since the material would be incomplete without its loaded textures.
|
|
360
374
|
*/
|
|
361
|
-
const setMaterial = function (
|
|
375
|
+
const setMaterial = function (
|
|
376
|
+
scene: Scene,
|
|
377
|
+
node: TransformNode,
|
|
378
|
+
materialId: string,
|
|
379
|
+
deep: boolean = true,
|
|
380
|
+
variant?: Variant
|
|
381
|
+
) {
|
|
362
382
|
if (node instanceof AbstractMesh) {
|
|
363
|
-
const materialExists =
|
|
383
|
+
const materialExists = scene.getMaterialById(materialId);
|
|
364
384
|
const hasMissingMaterial = has(node.metadata, missingMaterialMetadataName);
|
|
365
385
|
const deferMaterialCreation = !materialExists && !node.isEnabled();
|
|
366
|
-
|
|
367
386
|
if (deferMaterialCreation) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
//
|
|
387
|
+
// do not set the material
|
|
388
|
+
injectNodeMetadata(node, { [missingMaterialMetadataName]: materialId }, false);
|
|
389
|
+
// if it already had the missing material flag before, there already exists an observer...
|
|
371
390
|
if (!hasMissingMaterial) {
|
|
372
391
|
addMissingMaterialObserver(node);
|
|
373
392
|
}
|
|
374
393
|
} else {
|
|
375
|
-
|
|
394
|
+
// create material an apply it when textures have been loaded
|
|
395
|
+
const material = getOrCreateMaterial(scene, materialId, variant);
|
|
396
|
+
applyMaterialAfterTexturesLoaded(material, node);
|
|
397
|
+
|
|
376
398
|
if (hasMissingMaterial) {
|
|
377
399
|
delete node.metadata[missingMaterialMetadataName];
|
|
378
400
|
}
|
|
379
401
|
}
|
|
380
402
|
}
|
|
403
|
+
// recursively set materials on children (if desired)
|
|
381
404
|
if (deep) {
|
|
382
|
-
|
|
405
|
+
for (const child of node.getChildTransformNodes(true)) {
|
|
406
|
+
setMaterial(scene, child, materialId, deep, variant);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Gets the Material either from the given {@link Variant}, the given scene or tries to create it from an Combeenation
|
|
413
|
+
* material asset when inside a Combeenation configurator.
|
|
414
|
+
*/
|
|
415
|
+
const getOrCreateMaterial = function (scene: Scene, materialId: string, variant?: Variant): Material {
|
|
416
|
+
let chosenMaterial: Material | undefined | null;
|
|
417
|
+
chosenMaterial = variant?.inheritedMaterials.find(mat => mat.id === materialId);
|
|
418
|
+
chosenMaterial = chosenMaterial || scene.materials.find(mat => mat.id === materialId);
|
|
419
|
+
chosenMaterial = chosenMaterial || createMaterialFromCbnAssets(materialId, scene);
|
|
420
|
+
if (chosenMaterial) {
|
|
421
|
+
return chosenMaterial as Material;
|
|
422
|
+
}
|
|
423
|
+
// reject when material was not found
|
|
424
|
+
let rejectMessage = `Material with id "${materialId}" does not exist on scene.`;
|
|
425
|
+
if (variant) {
|
|
426
|
+
rejectMessage = `Material with id "${materialId}" does not exist for variant "${variant.id}".`;
|
|
427
|
+
}
|
|
428
|
+
throw new Error(rejectMessage);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Waits until the materials textures are loaded and sets the material on the node if there is no newer "set material"
|
|
433
|
+
* request
|
|
434
|
+
*/
|
|
435
|
+
const applyMaterialAfterTexturesLoaded = async function (material: Material, node: AbstractMesh) {
|
|
436
|
+
// set current material id as last valid id, in this case all previously set materials on the node will be invalidated
|
|
437
|
+
injectNodeMetadata(node, { [materialWaitingToBeSetMetadataName]: material.id }, false);
|
|
438
|
+
|
|
439
|
+
const promTexturesReady = new Promise<void>(resolve =>
|
|
440
|
+
BaseTexture.WhenAllReady(material.getActiveTextures(), resolve)
|
|
441
|
+
);
|
|
442
|
+
// this promise should only take some time on the first call of the corresponding shader (eg: PBRMaterial shader)
|
|
443
|
+
// on each other call of the same material/shader type there should be not be a waiting time, or at maximum one frame
|
|
444
|
+
// https://forum.babylonjs.com/t/mesh-flickering-when-setting-material-initially/37312
|
|
445
|
+
const promMaterialCompiled = material.forceCompilationAsync(node);
|
|
446
|
+
|
|
447
|
+
// material needs to fulfill 2 criterias before it's ready to use
|
|
448
|
+
// - textures need to be "ready" => downloaded
|
|
449
|
+
// - dedicated shader needs to be compiled
|
|
450
|
+
// if this would not be the case you can see some "flickering" when setting the material
|
|
451
|
+
await Promise.all([promTexturesReady, promMaterialCompiled]);
|
|
452
|
+
|
|
453
|
+
// textures ready, now check if the material is still up-to-date
|
|
454
|
+
if (material.id === node.metadata[materialWaitingToBeSetMetadataName]) {
|
|
455
|
+
node.material = material;
|
|
456
|
+
delete node.metadata[materialWaitingToBeSetMetadataName];
|
|
383
457
|
}
|
|
384
458
|
};
|
|
385
459
|
|
|
@@ -638,6 +712,8 @@ export {
|
|
|
638
712
|
cloneTransformNode,
|
|
639
713
|
cloneNodeWithParents,
|
|
640
714
|
cloneTransformNodeMaterial,
|
|
715
|
+
getOrCreateMaterial,
|
|
716
|
+
applyMaterialAfterTexturesLoaded,
|
|
641
717
|
injectNodeMetadata,
|
|
642
718
|
assertTransformNode,
|
|
643
719
|
activateTransformNode,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { injectNodeMetadata } from './babylonHelper';
|
|
1
|
+
import { applyMaterialAfterTexturesLoaded, getOrCreateMaterial, injectNodeMetadata } from './babylonHelper';
|
|
2
2
|
import { ISceneLoaderPlugin } from '@babylonjs/core/Loading/sceneLoader';
|
|
3
3
|
import { Material } from '@babylonjs/core/Materials/material';
|
|
4
4
|
import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
|
|
5
|
+
import { Observer } from '@babylonjs/core/Misc/observable';
|
|
5
6
|
import { AssetContainer } from '@babylonjs/core/assetContainer';
|
|
6
7
|
//! overload DOM API Node due to name-clash with BJS
|
|
7
8
|
import { Node as BjsNode } from '@babylonjs/core/node';
|
|
@@ -9,6 +10,11 @@ import { Scene } from '@babylonjs/core/scene';
|
|
|
9
10
|
import { Nullable } from '@babylonjs/core/types';
|
|
10
11
|
import has from 'lodash-es/has';
|
|
11
12
|
|
|
13
|
+
// map for keeping track of active "node enable" observers
|
|
14
|
+
const enableObserverMap: {
|
|
15
|
+
[concerningNodeId: string]: { currNodeId: string; observer: Nullable<Observer<boolean>> }[];
|
|
16
|
+
} = {};
|
|
17
|
+
|
|
12
18
|
export const missingMaterialMetadataName = 'missingMaterial';
|
|
13
19
|
|
|
14
20
|
/**
|
|
@@ -41,23 +47,37 @@ export const getCustomCbnBabylonLoaderPlugin = function (previousLoaderPlugin: I
|
|
|
41
47
|
/**
|
|
42
48
|
* Return an observer to be applied to meshes in order to post-load missing materials
|
|
43
49
|
* upon set enabled/visible.
|
|
44
|
-
*
|
|
50
|
+
*
|
|
45
51
|
* @param concerningMesh Mesh to look for missing materials on, and create/apply to (when found).
|
|
46
52
|
* @returns observer
|
|
47
53
|
*/
|
|
48
|
-
export const getMaterialPostLoadObserver = function (
|
|
49
|
-
return (
|
|
54
|
+
export const getMaterialPostLoadObserver = function (concerningMesh: Mesh) {
|
|
55
|
+
return async () => {
|
|
56
|
+
const scene = concerningMesh.getScene();
|
|
57
|
+
|
|
58
|
+
// can't check `isEnabled` immediatly, since the enabled state of parents and childs is not synced yet
|
|
59
|
+
// postpone to "when scene ready" to ensure a correct parent-child enable relation
|
|
60
|
+
await scene.whenReadyAsync();
|
|
61
|
+
|
|
50
62
|
const hasBeenEnabled = concerningMesh.isEnabled(true);
|
|
51
63
|
const materialMissing = has(concerningMesh.metadata, missingMaterialMetadataName);
|
|
52
64
|
if (!hasBeenEnabled || !materialMissing) return;
|
|
53
65
|
// get id of missing material
|
|
54
66
|
const missingMatId = concerningMesh.metadata[missingMaterialMetadataName];
|
|
55
|
-
//
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
concerningMesh.material = existingMat || createMaterialFromCbnAssets(missingMatId, concerningMesh.getScene());
|
|
67
|
+
// get material and apply it on the concerning mesh after all textures have been loaded
|
|
68
|
+
const material = getOrCreateMaterial(concerningMesh.getScene(), missingMatId);
|
|
69
|
+
applyMaterialAfterTexturesLoaded(material, concerningMesh);
|
|
59
70
|
// since the material is there now, we do not need the related metadata tag anymore
|
|
60
71
|
delete concerningMesh.metadata[missingMaterialMetadataName];
|
|
72
|
+
|
|
73
|
+
// remove all "enable" observers that were assigned to the concerning mesh
|
|
74
|
+
// the mesh got visible and therefore the observers are not needed anymore
|
|
75
|
+
enableObserverMap[concerningMesh.id].forEach(entry => {
|
|
76
|
+
const currNode = scene.getMeshById(entry.currNodeId);
|
|
77
|
+
currNode?.onEnabledStateChangedObservable.remove(entry.observer);
|
|
78
|
+
});
|
|
79
|
+
// also remove from the local observer map
|
|
80
|
+
delete enableObserverMap[concerningMesh.id];
|
|
61
81
|
};
|
|
62
82
|
};
|
|
63
83
|
|
|
@@ -99,30 +119,23 @@ export const addMissingMaterialObserver = function (node: BjsNode) {
|
|
|
99
119
|
// for each of our AbstractMeshes, set an observer on the AbstractMesh itself and all of its parents.
|
|
100
120
|
let currNode: Nullable<BjsNode> = node;
|
|
101
121
|
while (currNode) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// * `parentMesh` & `concerningMesh` are both enable
|
|
112
|
-
// -> material should be created as `concerningMesh` is now actually visible but it isn't, as all observers were
|
|
113
|
-
// only fired once 🔥
|
|
114
|
-
//
|
|
115
|
-
// However: Using `add` instead of `addOnce` requires rather complicated manual clean up work...
|
|
122
|
+
const callback = getMaterialPostLoadObserver(concerningNode);
|
|
123
|
+
const observer = currNode.onEnabledStateChangedObservable.add(callback);
|
|
124
|
+
|
|
125
|
+
// store the observer in a local map to keep track of the active "enable" observers
|
|
126
|
+
// observers will be removed when the concerning node gets enabled
|
|
127
|
+
if (!enableObserverMap[concerningNode.id]) {
|
|
128
|
+
enableObserverMap[concerningNode.id] = [];
|
|
129
|
+
}
|
|
130
|
+
enableObserverMap[concerningNode.id].push({ currNodeId: currNode.id, observer });
|
|
116
131
|
|
|
117
|
-
// add observer. needed only once per node, hence addOnce()
|
|
118
|
-
node.onEnabledStateChangedObservable.addOnce(getMaterialPostLoadObserver(currNode as AbstractMesh, concerningNode));
|
|
119
|
-
// console.log('## observer set on: ' + meshOrInstance.name);
|
|
120
132
|
currNode = currNode.parent;
|
|
121
133
|
}
|
|
122
134
|
};
|
|
123
135
|
|
|
124
136
|
/**
|
|
125
137
|
* Look up the provided materials (see library import) and create and return one if found.
|
|
138
|
+
*
|
|
126
139
|
* @param materialId BabylonJs material-id. E.g. 'concrete".
|
|
127
140
|
* @param scene BabylonJs scene
|
|
128
141
|
* @returns PBRMaterial | null
|
|
@@ -20,4 +20,11 @@ const camelToSnakeCase = function (str: string): string {
|
|
|
20
20
|
.toLowerCase();
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Replaces all dots from the input string with a desired character ('/' by default)
|
|
25
|
+
*/
|
|
26
|
+
const replaceDots = function (str: string, replaceChar = '/'): string {
|
|
27
|
+
return str.split('.').join(replaceChar);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { uuidv4, camelToSnakeCase, replaceDots };
|
package/src/dev.ts
CHANGED
|
@@ -12,12 +12,10 @@ import { set } from 'lodash-es';
|
|
|
12
12
|
const loadingElement = document.getElementById('loading') as HTMLDivElement;
|
|
13
13
|
|
|
14
14
|
Emitter.on(Event.BOOTSTRAP_START, () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
loadingElement!.style.display = 'none';
|
|
20
|
-
});
|
|
15
|
+
loadingElement!.style.display = 'block';
|
|
16
|
+
});
|
|
17
|
+
Emitter.on(Event.BOOTSTRAP_END, () => {
|
|
18
|
+
loadingElement!.style.display = 'none';
|
|
21
19
|
});
|
|
22
20
|
|
|
23
21
|
document.addEventListener('DOMContentLoaded', main);
|
|
@@ -25,6 +23,7 @@ document.addEventListener('DOMContentLoaded', main);
|
|
|
25
23
|
window.Cbn = {
|
|
26
24
|
Assets: {
|
|
27
25
|
getMaterial(materialId: string) {
|
|
26
|
+
//! this creates a new function on the object that uses the imported function of the same name..
|
|
28
27
|
const material = getMaterial(materialId);
|
|
29
28
|
if (material) return material;
|
|
30
29
|
|