@combeenation/3d-viewer 16.0.0-alpha1 → 16.0.0-beta1
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/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/dist/lib-cjs/helper/decals-helper.d.ts +27 -4
- package/dist/lib-cjs/helper/decals-helper.js +22 -10
- package/dist/lib-cjs/helper/decals-helper.js.map +1 -1
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.d.ts +0 -16
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +14 -20
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
- package/dist/lib-cjs/manager/material-manager.d.ts +3 -3
- package/dist/lib-cjs/manager/material-manager.js +17 -10
- package/dist/lib-cjs/manager/material-manager.js.map +1 -1
- package/dist/lib-cjs/manager/model-manager.d.ts +19 -2
- package/dist/lib-cjs/manager/model-manager.js +13 -8
- package/dist/lib-cjs/manager/model-manager.js.map +1 -1
- package/dist/lib-cjs/manager/parameter-manager.js +4 -0
- package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
- package/dist/lib-cjs/viewer-error.d.ts +0 -1
- package/dist/lib-cjs/viewer-error.js +0 -1
- package/dist/lib-cjs/viewer-error.js.map +1 -1
- package/package.json +1 -1
- package/src/helper/decals-helper.ts +42 -12
- package/src/internal/cbn-custom-babylon-loader-plugin.ts +19 -25
- package/src/manager/material-manager.ts +28 -12
- package/src/manager/model-manager.ts +17 -16
- package/src/manager/parameter-manager.ts +7 -0
- package/src/viewer-error.ts +0 -1
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
import { IAssetContainer, Material, Mesh, MeshBuilder, Tuple, Vector3, ViewerError, ViewerErrorIds } from '..';
|
|
2
2
|
|
|
3
|
+
export const DEFAULT_DECAL_CONFIG = {
|
|
4
|
+
normal: [0, 0, 1],
|
|
5
|
+
angle: 0,
|
|
6
|
+
offset: 0.001,
|
|
7
|
+
scaling: [1, 1, 1],
|
|
8
|
+
captureUVS: false,
|
|
9
|
+
cullBackFaces: true,
|
|
10
|
+
localMode: true,
|
|
11
|
+
sideOrientation: Material.ClockWiseSideOrientation,
|
|
12
|
+
};
|
|
13
|
+
|
|
3
14
|
export type DecalConfiguration = {
|
|
4
15
|
// basic settings for decal creation
|
|
5
16
|
name: string;
|
|
6
17
|
sourceMeshName: string;
|
|
7
18
|
position: Tuple<number, 3>;
|
|
8
|
-
normal: Tuple<number, 3>;
|
|
9
19
|
size: Tuple<number, 3>;
|
|
10
|
-
angle: number;
|
|
11
20
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
21
|
+
/** Default `[0, 0, 1]` (forward direction) */
|
|
22
|
+
normal?: Tuple<number, 3>;
|
|
23
|
+
|
|
24
|
+
/** Default `0` */
|
|
25
|
+
angle?: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Shifts decals away from source mesh in direction of "normal" vector
|
|
29
|
+
*
|
|
30
|
+
* Default `0.001` (1mm)
|
|
31
|
+
*/
|
|
32
|
+
offset?: number;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Can be used for shifting the decal away from the source mesh as alternative to `offset`.\
|
|
36
|
+
* Use this setting when the offset should be applied in radial direction (e.g. cylinders)
|
|
37
|
+
*
|
|
38
|
+
* Default `[1, 1, 1]` (no offset through scaling)
|
|
39
|
+
*/
|
|
40
|
+
scaling?: Tuple<number, 3>;
|
|
14
41
|
|
|
15
42
|
/**
|
|
16
43
|
* `true`: Use UV mapping from source mesh\
|
|
@@ -60,19 +87,19 @@ export function createDecalMesh(config: DecalConfiguration, assetContainer: IAss
|
|
|
60
87
|
}
|
|
61
88
|
|
|
62
89
|
const position = Vector3.FromArray(config.position);
|
|
63
|
-
const normal = Vector3.FromArray(config.normal).normalizeToNew();
|
|
90
|
+
const normal = Vector3.FromArray(config.normal ?? DEFAULT_DECAL_CONFIG.normal).normalizeToNew();
|
|
64
91
|
|
|
65
|
-
const localMode = config.localMode ??
|
|
92
|
+
const localMode = config.localMode ?? DEFAULT_DECAL_CONFIG.localMode;
|
|
66
93
|
const worldNormal = localMode ? Vector3.TransformNormal(normal, sourceMesh.getWorldMatrix()) : normal;
|
|
67
94
|
|
|
68
95
|
const decalMesh = MeshBuilder.CreateDecal(config.name, sourceMesh, {
|
|
69
96
|
position: position,
|
|
70
97
|
normal: normal,
|
|
71
98
|
size: Vector3.FromArray(config.size),
|
|
72
|
-
angle: config.angle,
|
|
73
|
-
captureUVS: config.captureUVS ??
|
|
74
|
-
cullBackFaces: config.cullBackFaces ??
|
|
75
|
-
localMode: config.localMode ??
|
|
99
|
+
angle: config.angle ?? DEFAULT_DECAL_CONFIG.angle,
|
|
100
|
+
captureUVS: config.captureUVS ?? DEFAULT_DECAL_CONFIG.captureUVS,
|
|
101
|
+
cullBackFaces: config.cullBackFaces ?? DEFAULT_DECAL_CONFIG.cullBackFaces,
|
|
102
|
+
localMode: config.localMode ?? DEFAULT_DECAL_CONFIG.localMode,
|
|
76
103
|
});
|
|
77
104
|
|
|
78
105
|
if (!addToScene) {
|
|
@@ -84,12 +111,15 @@ export function createDecalMesh(config: DecalConfiguration, assetContainer: IAss
|
|
|
84
111
|
decalMesh._parentContainer = assetContainer;
|
|
85
112
|
assetContainer.meshes.push(decalMesh);
|
|
86
113
|
|
|
87
|
-
decalMesh.sideOrientation = config.sideOrientation ??
|
|
114
|
+
decalMesh.sideOrientation = config.sideOrientation ?? DEFAULT_DECAL_CONFIG.sideOrientation;
|
|
88
115
|
|
|
89
116
|
// move decal away from mesh to avoid clipping
|
|
90
117
|
// NOTE: zOffset of material can't be used, since it's not supported in glTF and therefore not usable in AR
|
|
91
|
-
const offsetVector = worldNormal.scale(config.offset);
|
|
118
|
+
const offsetVector = worldNormal.scale(config.offset ?? DEFAULT_DECAL_CONFIG.offset);
|
|
92
119
|
decalMesh.position.addInPlace(offsetVector);
|
|
93
120
|
|
|
121
|
+
// apply scaling, this is an alternative approach for creating an offset, which is preferred for round surfaces
|
|
122
|
+
decalMesh.scaling = Vector3.FromArray(config.scaling ?? DEFAULT_DECAL_CONFIG.scaling);
|
|
123
|
+
|
|
94
124
|
return decalMesh;
|
|
95
125
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AssetContainer,
|
|
3
|
-
|
|
3
|
+
ExtendedAssetContainer,
|
|
4
4
|
ISceneLoaderPlugin,
|
|
5
5
|
InstancedMesh,
|
|
6
|
+
ParsedDecalConfiguration,
|
|
6
7
|
SceneLoader,
|
|
7
8
|
ViewerError,
|
|
8
9
|
ViewerErrorIds,
|
|
@@ -10,20 +11,7 @@ import {
|
|
|
10
11
|
} from '../index';
|
|
11
12
|
import { setInternalMetadataValue } from './metadata-helper';
|
|
12
13
|
import { deleteAllTags, getTags, setTagsAsString } from './tags-helper';
|
|
13
|
-
import { isArray,
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Contains cbn custom data, like decals.
|
|
17
|
-
* This is just a temporary type, as the `loadAssetContainer` function only returns an asset container, which can be
|
|
18
|
-
* altered by our file loader plugin.
|
|
19
|
-
* After loading the model, `cbnData` is cropped and a pure asset container is available for further processing.
|
|
20
|
-
*/
|
|
21
|
-
export class ExtendedAssetContainer extends AssetContainer {
|
|
22
|
-
cbnData?: CbnBabylonFileData;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type CbnBabylonFileData = { decals?: ParsedDecalConfiguration[] };
|
|
26
|
-
export type ParsedDecalConfiguration = DecalConfiguration & { materialId?: string };
|
|
14
|
+
import { isArray, isString } from 'lodash-es';
|
|
27
15
|
|
|
28
16
|
type DataWithMeshes = { meshes: unknown[] };
|
|
29
17
|
type DataWithDecalConfigurations = { cbnData: { decals: unknown[] } };
|
|
@@ -39,6 +27,8 @@ type InstanceData = {
|
|
|
39
27
|
tags?: string;
|
|
40
28
|
};
|
|
41
29
|
|
|
30
|
+
let customLoader: ISceneLoaderPlugin;
|
|
31
|
+
|
|
42
32
|
/**
|
|
43
33
|
* Create and return a custom loader plugin to be registered with SceneLoader, that allows
|
|
44
34
|
* us to run our own code against the input data before using the standard procedure to
|
|
@@ -51,12 +41,18 @@ type InstanceData = {
|
|
|
51
41
|
* editor area
|
|
52
42
|
*/
|
|
53
43
|
export function registerCustomCbnBabylonLoaderPlugin(): void {
|
|
44
|
+
if (customLoader) {
|
|
45
|
+
// create the custom loader only once, otherwise receiving the current .babylon plugin would return the custom
|
|
46
|
+
// loader, resulting in multiple calls of the plugin (e.g. decals will be created multiple times)
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
54
50
|
// get original plugin for babylon files
|
|
55
51
|
// we only want to manipulate Combeenation 3d assets, which are represented as babylon files
|
|
56
52
|
// the plugin is not used for GLB files, "local" babylon are also not really affected by this plugin
|
|
57
53
|
const previousLoaderPlugin = SceneLoader.GetPluginForExtension('.babylon') as ISceneLoaderPlugin;
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
customLoader = {
|
|
60
56
|
name: 'cbnCustomBabylonLoader',
|
|
61
57
|
extensions: '.babylon',
|
|
62
58
|
importMesh: previousLoaderPlugin.importMesh,
|
|
@@ -104,13 +100,7 @@ function _isMeshInstanceData(data: any): data is InstanceData {
|
|
|
104
100
|
|
|
105
101
|
function _isDecalConfiguration(data: any): data is ParsedDecalConfiguration {
|
|
106
102
|
const hasValidProps =
|
|
107
|
-
isString(data.name) &&
|
|
108
|
-
isString(data.sourceMeshName) &&
|
|
109
|
-
isArray(data.position) &&
|
|
110
|
-
isArray(data.normal) &&
|
|
111
|
-
isArray(data.size) &&
|
|
112
|
-
isNumber(data.angle) &&
|
|
113
|
-
isNumber(data.offset);
|
|
103
|
+
isString(data.name) && isString(data.sourceMeshName) && isArray(data.position) && isArray(data.size);
|
|
114
104
|
|
|
115
105
|
if (!hasValidProps) {
|
|
116
106
|
throw new ViewerError({
|
|
@@ -200,13 +190,17 @@ function _createDecals(dataParsed: unknown, container: AssetContainer): void {
|
|
|
200
190
|
const validatedDecals = dataParsed.cbnData.decals.filter(_isDecalConfiguration);
|
|
201
191
|
|
|
202
192
|
validatedDecals.forEach(decalConfig => {
|
|
203
|
-
const { materialId, ...decalMeshConfig } = decalConfig;
|
|
193
|
+
const { materialId, tags, ...decalMeshConfig } = decalConfig;
|
|
204
194
|
const decalMesh = createDecalMesh(decalMeshConfig, container, false);
|
|
205
195
|
|
|
206
|
-
// optionally set material directly
|
|
196
|
+
// optionally set material and tags directly
|
|
207
197
|
if (materialId) {
|
|
208
198
|
window.Cbn?.Assets.assertMaterialExists(materialId);
|
|
209
199
|
setInternalMetadataValue(decalMesh, 'deferredMaterial', materialId);
|
|
210
200
|
}
|
|
201
|
+
|
|
202
|
+
if (tags) {
|
|
203
|
+
setTagsAsString(decalMesh, tags);
|
|
204
|
+
}
|
|
211
205
|
});
|
|
212
206
|
}
|
|
@@ -47,7 +47,7 @@ export class MaterialManager {
|
|
|
47
47
|
|
|
48
48
|
// there may have been later "setMaterialOnMesh" calls with faster material creation
|
|
49
49
|
// make sure to assign the latest material!
|
|
50
|
-
if (getInternalMetadataValue(mesh, 'materialToBeSet') === materialId) {
|
|
50
|
+
if (material && getInternalMetadataValue(mesh, 'materialToBeSet') === materialId) {
|
|
51
51
|
mesh.material = material;
|
|
52
52
|
clearInternalMetadataValue(mesh, 'materialToBeSet');
|
|
53
53
|
clearInternalMetadataValue(mesh, 'deferredMaterial');
|
|
@@ -65,7 +65,7 @@ export class MaterialManager {
|
|
|
65
65
|
* @param mesh Required for shader compilation check, can be omitted if this check should not be done.\
|
|
66
66
|
* Use {@link setMaterialOnMesh} instead if the material should be applied on the mesh immediately.
|
|
67
67
|
*/
|
|
68
|
-
public async getOrCreateMaterial(materialId: string, mesh?: AbstractMesh): Promise<Material> {
|
|
68
|
+
public async getOrCreateMaterial(materialId: string, mesh?: AbstractMesh): Promise<Material | null> {
|
|
69
69
|
let chosenMaterial: Material | null = this.viewer.scene.materials.find(mat => mat.id === materialId) ?? null;
|
|
70
70
|
|
|
71
71
|
if (!chosenMaterial) {
|
|
@@ -78,7 +78,7 @@ export class MaterialManager {
|
|
|
78
78
|
this.viewer.eventManager.fireEvent(ViewerEvent.MaterialCreationStart, materialId);
|
|
79
79
|
|
|
80
80
|
// request not pending, call the dedicated function
|
|
81
|
-
const newCreationProm = this.
|
|
81
|
+
const newCreationProm = this._createFromMaterialAsset(materialId, mesh);
|
|
82
82
|
// store the promise in a global map, so that subsequent requests can reference it
|
|
83
83
|
this._createMaterialPromises[materialId] = newCreationProm;
|
|
84
84
|
chosenMaterial = await newCreationProm;
|
|
@@ -93,7 +93,7 @@ export class MaterialManager {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
return chosenMaterial
|
|
96
|
+
return chosenMaterial;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
@@ -105,7 +105,7 @@ export class MaterialManager {
|
|
|
105
105
|
materialId: string,
|
|
106
106
|
newMaterialId: string,
|
|
107
107
|
options?: MaterialCloneOptions
|
|
108
|
-
): Promise<Material> {
|
|
108
|
+
): Promise<Material | null> {
|
|
109
109
|
const existingMaterial = this._clonedMaterials[newMaterialId];
|
|
110
110
|
if (existingMaterial) {
|
|
111
111
|
throw new ViewerError({
|
|
@@ -115,6 +115,10 @@ export class MaterialManager {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
const sourceMaterial = await this.getOrCreateMaterial(materialId);
|
|
118
|
+
if (!sourceMaterial) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
const clonedMaterial = CloningHelper.cloneMaterial(sourceMaterial, newMaterialId, options?.tagNamingStrategy);
|
|
119
123
|
|
|
120
124
|
await this.viewer.parameterManager.applyParameterValuesToMaterial(clonedMaterial);
|
|
@@ -151,7 +155,7 @@ export class MaterialManager {
|
|
|
151
155
|
Object.keys(this._clonedMaterials).forEach(materialId => this.deleteClonedMaterial(materialId));
|
|
152
156
|
}
|
|
153
157
|
|
|
154
|
-
protected async
|
|
158
|
+
protected async _createFromMaterialAsset(materialId: string, mesh?: AbstractMesh): Promise<Material | null> {
|
|
155
159
|
if (materialId === MaterialManager.CBN_FALLBACK_MATERIAL_NAME) {
|
|
156
160
|
const fallbackMaterial = new StandardMaterial(MaterialManager.CBN_FALLBACK_MATERIAL_NAME, this.viewer.scene);
|
|
157
161
|
fallbackMaterial.disableLighting = true;
|
|
@@ -159,17 +163,29 @@ export class MaterialManager {
|
|
|
159
163
|
return fallbackMaterial;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
|
|
166
|
+
if (!window.Cbn) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const materialDefinition = await window.Cbn.Assets.getMaterial(materialId);
|
|
171
|
+
|
|
172
|
+
if (!materialDefinition) {
|
|
173
|
+
console.warn(
|
|
174
|
+
`Trying to create material "${materialId}" from Combeenation asset but according asset does not exist or is not connected to the configurator.`
|
|
175
|
+
);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
163
179
|
// The generic `Material.Parse` actually returns a more specific material like `BABYLON.StandardMaterial`,
|
|
164
180
|
// `BABYLON.PBRMaterial` or stuff like `BABYLON.PBRMetallicRoughnessMaterial` etc. based on the given `customType`
|
|
165
181
|
// within the material JSON definition
|
|
166
|
-
const material =
|
|
182
|
+
const material = Material.Parse(materialDefinition, this.viewer.scene, '');
|
|
167
183
|
|
|
168
184
|
if (!material) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
console.warn(
|
|
186
|
+
`Failed to create material "${materialId}" from Combeenation asset. Seems like the material could not be parsed.`
|
|
187
|
+
);
|
|
188
|
+
return null;
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
await this.viewer.parameterManager.applyParameterValuesToMaterial(material);
|
|
@@ -11,15 +11,25 @@ import {
|
|
|
11
11
|
ViewerError,
|
|
12
12
|
ViewerErrorIds,
|
|
13
13
|
} from '../index';
|
|
14
|
-
import {
|
|
15
|
-
CbnBabylonFileData,
|
|
16
|
-
ExtendedAssetContainer,
|
|
17
|
-
ParsedDecalConfiguration,
|
|
18
|
-
} from '../internal/cbn-custom-babylon-loader-plugin';
|
|
19
14
|
import { cloneModelAssetContainer } from '../internal/cloning-helper';
|
|
20
15
|
import { getInternalMetadataValue } from '../internal/metadata-helper';
|
|
21
16
|
import { isArray } from 'lodash-es';
|
|
22
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Contains cbn custom data, like decals.
|
|
20
|
+
* This is just a temporary type, as the `loadAssetContainer` function only returns an asset container, which can be
|
|
21
|
+
* altered by our file loader plugin.
|
|
22
|
+
* After loading the model, `cbnData` is cropped and a pure asset container is available for further processing.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export class ExtendedAssetContainer extends AssetContainer {
|
|
27
|
+
cbnData?: CbnBabylonFileData;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type CbnBabylonFileData = { decals?: ParsedDecalConfiguration[] };
|
|
31
|
+
export type ParsedDecalConfiguration = DecalConfiguration & { materialId?: string; tags?: string };
|
|
32
|
+
|
|
23
33
|
export type ModelAssetDefinition = {
|
|
24
34
|
name: string;
|
|
25
35
|
url: string;
|
|
@@ -372,7 +382,7 @@ export class ModelManager {
|
|
|
372
382
|
* Decals are already converted to "normal" meshes when loading a model, still the original decals configuration can
|
|
373
383
|
* be useful e.g. for alterning decals.
|
|
374
384
|
*/
|
|
375
|
-
public async getDecalsConfigurationOfModel(name: string): Promise<
|
|
385
|
+
public async getDecalsConfigurationOfModel(name: string): Promise<ParsedDecalConfiguration[]> {
|
|
376
386
|
const model = this._getModel(name);
|
|
377
387
|
if (!model) {
|
|
378
388
|
throw new ViewerError({
|
|
@@ -391,16 +401,7 @@ export class ModelManager {
|
|
|
391
401
|
await this._prepareModelForScene(model);
|
|
392
402
|
}
|
|
393
403
|
|
|
394
|
-
|
|
395
|
-
const decals = ((model.cbnBabylonFileData?.decals ?? []) as ParsedDecalConfiguration[]).map<DecalConfiguration>(
|
|
396
|
-
parsedDecal => {
|
|
397
|
-
const croppedDecal = parsedDecal;
|
|
398
|
-
delete croppedDecal.materialId;
|
|
399
|
-
return croppedDecal;
|
|
400
|
-
}
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
return decals;
|
|
404
|
+
return model.cbnBabylonFileData?.decals ?? [];
|
|
404
405
|
}
|
|
405
406
|
|
|
406
407
|
/**
|
|
@@ -377,6 +377,13 @@ export class ParameterManager {
|
|
|
377
377
|
const materialParamEntries = this._getEntriesOfSubject({ materialName: material.id });
|
|
378
378
|
parameterEntriesToApply.push(...materialParamEntries);
|
|
379
379
|
|
|
380
|
+
// also get parameter entries that have this material set as value, this is the case for node <=> material
|
|
381
|
+
// assignment parameter (`BuiltInParameter.Material`)
|
|
382
|
+
const materialAssignmentParamEntries = this._parameterEntries.filter(
|
|
383
|
+
entry => entry.parameterName === BuiltInParameter.Material && entry.value === material.id
|
|
384
|
+
);
|
|
385
|
+
parameterEntriesToApply.push(...materialAssignmentParamEntries);
|
|
386
|
+
|
|
380
387
|
await this._applyParameterValues(parameterEntriesToApply);
|
|
381
388
|
}
|
|
382
389
|
|
package/src/viewer-error.ts
CHANGED
|
@@ -25,7 +25,6 @@ export const ViewerErrorIds = {
|
|
|
25
25
|
ModelAlreadyExists: 'ModelAlreadyExists',
|
|
26
26
|
ModelIsNotAClone: 'ModelIsNotAClone',
|
|
27
27
|
AssetLoadingFailed: 'AssetLoadingFailed',
|
|
28
|
-
MaterialCouldNotBeParsed: 'MaterialCouldNotBeParsed',
|
|
29
28
|
TextureCouldNotBeParsed: 'TextureCouldNotBeParsed',
|
|
30
29
|
MaterialAlreadyExists: 'MaterialAlreadyExists',
|
|
31
30
|
NotAClonedMaterial: 'NotAClonedMaterial',
|