@combeenation/3d-viewer 14.1.0 → 15.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/dist/lib-cjs/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
- package/dist/lib-cjs/internal/paintable-helper.js +2 -54
- package/dist/lib-cjs/internal/paintable-helper.js.map +1 -1
- package/dist/lib-cjs/internal/svg-helper.d.ts +4 -0
- package/dist/lib-cjs/internal/svg-helper.js +67 -0
- package/dist/lib-cjs/internal/svg-helper.js.map +1 -0
- package/dist/lib-cjs/internal/tags-helper.d.ts +1 -1
- package/dist/lib-cjs/internal/tags-helper.js +10 -8
- package/dist/lib-cjs/internal/tags-helper.js.map +1 -1
- package/dist/lib-cjs/internal/texture-parameter-helper.d.ts +37 -0
- package/dist/lib-cjs/internal/texture-parameter-helper.js +287 -0
- package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -0
- package/dist/lib-cjs/manager/parameter-manager.d.ts +19 -1
- package/dist/lib-cjs/manager/parameter-manager.js +66 -7
- package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
- package/dist/lib-cjs/viewer-error.d.ts +1 -0
- package/dist/lib-cjs/viewer-error.js +1 -0
- package/dist/lib-cjs/viewer-error.js.map +1 -1
- package/dist/lib-cjs/viewer.js.map +1 -1
- package/package.json +13 -10
- package/src/internal/cbn-custom-babylon-loader-plugin.ts +1 -1
- package/src/internal/paintable-helper.ts +2 -54
- package/src/internal/svg-helper.ts +52 -0
- package/src/internal/tags-helper.ts +9 -7
- package/src/internal/texture-parameter-helper.ts +353 -0
- package/src/manager/parameter-manager.ts +84 -6
- package/src/viewer-error.ts +1 -0
- package/src/viewer.ts +1 -1
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { BaseTexture, Material, PBRMaterial, Scene, Texture, ViewerError, ViewerErrorIds } from '..';
|
|
2
|
+
import { BuiltInParameter, ParameterManager } from '../manager/parameter-manager';
|
|
3
|
+
import { embedAssets } from './svg-helper';
|
|
4
|
+
import isSvg from 'is-svg';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Texture parameters are a combination of the channel (e.g. albedo, bump, AO) and the "sub" parameter (e.g. uScale).
|
|
8
|
+
* Each parameter is available in each texture, that's why these textures parameter are defined as dotted path
|
|
9
|
+
* `albedoTexture.uScale`
|
|
10
|
+
* - channel: albedoTexture
|
|
11
|
+
* - parameter: uScale
|
|
12
|
+
* The consumer doesn't have to know this as there is `BuiltInParameters.createTextureParameter(channel, parameter)`,
|
|
13
|
+
* which composes this string internally
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const BuiltInTextureParameter = {
|
|
17
|
+
image: 'image',
|
|
18
|
+
uOffset: 'uOffset',
|
|
19
|
+
vOffset: 'vOffset',
|
|
20
|
+
uScale: 'uScale',
|
|
21
|
+
vScale: 'vScale',
|
|
22
|
+
uAng: 'uAng',
|
|
23
|
+
vAng: 'vAng',
|
|
24
|
+
wAng: 'wAng',
|
|
25
|
+
clampU: 'clampU',
|
|
26
|
+
clampV: 'clampV',
|
|
27
|
+
uvSet: 'uvSet',
|
|
28
|
+
};
|
|
29
|
+
export type BuiltInTextureParameterKeys = keyof typeof BuiltInTextureParameter;
|
|
30
|
+
|
|
31
|
+
export const ParameterTextureChannels = {
|
|
32
|
+
albedoTexture: 'albedoTexture',
|
|
33
|
+
metallicRoughnessTexture: 'metallicRoughnessTexture',
|
|
34
|
+
bumpTexture: 'bumpTexture',
|
|
35
|
+
emissiveTexture: 'emissiveTexture',
|
|
36
|
+
opacityTexture: 'opacityTexture',
|
|
37
|
+
ambientTexture: 'ambientTexture',
|
|
38
|
+
lightmapTexture: 'lightmapTexture',
|
|
39
|
+
detailmapTexture: 'detailmapTexture',
|
|
40
|
+
};
|
|
41
|
+
export type ParameterTextureChannelsKeys = keyof typeof ParameterTextureChannels;
|
|
42
|
+
|
|
43
|
+
export function createBuiltInTextureParameter(parameterManager: ParameterManager, scene: Scene): void {
|
|
44
|
+
// create parameter observer for each channel
|
|
45
|
+
(Object.values(ParameterTextureChannels) as ParameterTextureChannelsKeys[]).forEach(channel => {
|
|
46
|
+
parameterManager.setParameterObserver(
|
|
47
|
+
`${channel}.${BuiltInTextureParameter.image}`,
|
|
48
|
+
async ({ newValue, materials }) => {
|
|
49
|
+
const image = ParameterManager.parseString(newValue);
|
|
50
|
+
let url = image;
|
|
51
|
+
|
|
52
|
+
const imageIsSvg = isSvg(image);
|
|
53
|
+
if (imageIsSvg) {
|
|
54
|
+
// NOTE: image can also be provided as "svg", which is more or less the successor of the "paintable"
|
|
55
|
+
// parameter. It misses the UV parameters, but we now have dedicated parameters for this.
|
|
56
|
+
// We used "Dynamic Textures" for paintables because we didn't know better I guess?
|
|
57
|
+
// However the rescaling functionality of "Dynamic Textures" is not required and therefore it can be
|
|
58
|
+
// implemented as a plain "Texture"
|
|
59
|
+
const svgWithAssetsEmbedded = await embedAssets(image);
|
|
60
|
+
// convert into a base64 string, as this can be directly interpreted as "url", at least for Babylon.js
|
|
61
|
+
url = 'data:image/svg+xml;base64,' + btoa(svgWithAssetsEmbedded);
|
|
62
|
+
} else if (image.includes('<svg') && image.includes('</svg>')) {
|
|
63
|
+
// seems like the user tried to use a SVG string, as <svg> tags are used
|
|
64
|
+
// inform the user that this is not a valid SVG string
|
|
65
|
+
throw new ViewerError({
|
|
66
|
+
id: ViewerErrorIds.InvalidParameterValue,
|
|
67
|
+
message: `Invalid value for parameter "image" given:\nsource string is no valid SVG string\nGiven value: ${image}`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const material of materials) {
|
|
72
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.image);
|
|
73
|
+
const texture = _getTextureFromParameterChannel(pbrMaterial, channel);
|
|
74
|
+
|
|
75
|
+
if (texture) {
|
|
76
|
+
// create a clone of the texture, in this way we can load the image before assigning it to the material
|
|
77
|
+
// channel
|
|
78
|
+
const clonedTexture = texture.clone();
|
|
79
|
+
// update texture and await loading time right away
|
|
80
|
+
await new Promise<void>(resolve => clonedTexture.updateURL(url, undefined, resolve));
|
|
81
|
+
|
|
82
|
+
_assignTextureParameterChannel(clonedTexture, pbrMaterial, channel);
|
|
83
|
+
|
|
84
|
+
// dispose old texture
|
|
85
|
+
texture.dispose();
|
|
86
|
+
} else {
|
|
87
|
+
// no texture, or wrong type => create texture from scratch
|
|
88
|
+
// first we check if some settings were provided in the material definition
|
|
89
|
+
const addMatSettings = await window.Cbn?.Assets.getMaterial(pbrMaterial.id);
|
|
90
|
+
const textureSettings = addMatSettings ? _getTextureObjFromParameterChannel(addMatSettings, channel) : {};
|
|
91
|
+
|
|
92
|
+
// overwrite the name with the url, as this is what the texture parser expects
|
|
93
|
+
(textureSettings as any).name = url;
|
|
94
|
+
// use parser instead of constructor to keep the original texture settings
|
|
95
|
+
const newTexture = Texture.Parse(textureSettings, scene, '') as Texture;
|
|
96
|
+
|
|
97
|
+
if (!newTexture) {
|
|
98
|
+
throw new ViewerError({
|
|
99
|
+
id: ViewerErrorIds.TextureCouldNotBeParsed,
|
|
100
|
+
message: `Texture with url "${url}" could not be parsed`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// await loading of texture
|
|
105
|
+
await new Promise<void>(resolve => BaseTexture.WhenAllReady([newTexture], resolve));
|
|
106
|
+
_assignTextureParameterChannel(newTexture, pbrMaterial, channel);
|
|
107
|
+
|
|
108
|
+
// apply texture settings, which have been set before the texture creation
|
|
109
|
+
await parameterManager.applyTextureSettingsParameter(pbrMaterial, channel);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
parameterManager.setParameterObserver(
|
|
115
|
+
`${channel}.${BuiltInTextureParameter.uOffset}`,
|
|
116
|
+
async ({ newValue, materials }) => {
|
|
117
|
+
const uOffset = ParameterManager.parseNumber(newValue);
|
|
118
|
+
|
|
119
|
+
for (const material of materials) {
|
|
120
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.uOffset);
|
|
121
|
+
|
|
122
|
+
_setUVTextureSetting('uOffset', uOffset, pbrMaterial, channel);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
parameterManager.setParameterObserver(
|
|
127
|
+
`${channel}.${BuiltInTextureParameter.vOffset}`,
|
|
128
|
+
async ({ newValue, materials }) => {
|
|
129
|
+
const vOffset = ParameterManager.parseNumber(newValue);
|
|
130
|
+
|
|
131
|
+
for (const material of materials) {
|
|
132
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.vOffset);
|
|
133
|
+
|
|
134
|
+
_setUVTextureSetting('vOffset', vOffset, pbrMaterial, channel);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
parameterManager.setParameterObserver(
|
|
139
|
+
`${channel}.${BuiltInTextureParameter.uScale}`,
|
|
140
|
+
async ({ newValue, materials }) => {
|
|
141
|
+
const uScale = ParameterManager.parseNumber(newValue);
|
|
142
|
+
|
|
143
|
+
for (const material of materials) {
|
|
144
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.uScale);
|
|
145
|
+
|
|
146
|
+
_setUVTextureSetting('uScale', uScale, pbrMaterial, channel);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
parameterManager.setParameterObserver(
|
|
151
|
+
`${channel}.${BuiltInTextureParameter.vScale}`,
|
|
152
|
+
async ({ newValue, materials }) => {
|
|
153
|
+
const vScale = ParameterManager.parseNumber(newValue);
|
|
154
|
+
|
|
155
|
+
for (const material of materials) {
|
|
156
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.vScale);
|
|
157
|
+
|
|
158
|
+
_setUVTextureSetting('vScale', vScale, pbrMaterial, channel);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
parameterManager.setParameterObserver(
|
|
163
|
+
`${channel}.${BuiltInTextureParameter.uAng}`,
|
|
164
|
+
async ({ newValue, materials }) => {
|
|
165
|
+
const uAng = ParameterManager.parseNumber(newValue);
|
|
166
|
+
|
|
167
|
+
for (const material of materials) {
|
|
168
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.uAng);
|
|
169
|
+
|
|
170
|
+
_setUVTextureSetting('uAng', uAng, pbrMaterial, channel);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
parameterManager.setParameterObserver(
|
|
175
|
+
`${channel}.${BuiltInTextureParameter.vAng}`,
|
|
176
|
+
async ({ newValue, materials }) => {
|
|
177
|
+
const vAng = ParameterManager.parseNumber(newValue);
|
|
178
|
+
|
|
179
|
+
for (const material of materials) {
|
|
180
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.vAng);
|
|
181
|
+
|
|
182
|
+
_setUVTextureSetting('vAng', vAng, pbrMaterial, channel);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
parameterManager.setParameterObserver(
|
|
187
|
+
`${channel}.${BuiltInTextureParameter.wAng}`,
|
|
188
|
+
async ({ newValue, materials }) => {
|
|
189
|
+
const wAng = ParameterManager.parseNumber(newValue);
|
|
190
|
+
|
|
191
|
+
for (const material of materials) {
|
|
192
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.wAng);
|
|
193
|
+
|
|
194
|
+
_setUVTextureSetting('wAng', wAng, pbrMaterial, channel);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
parameterManager.setParameterObserver(
|
|
199
|
+
`${channel}.${BuiltInTextureParameter.clampU}`,
|
|
200
|
+
async ({ newValue, materials }) => {
|
|
201
|
+
const clampU = ParameterManager.parseBoolean(newValue);
|
|
202
|
+
|
|
203
|
+
for (const material of materials) {
|
|
204
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.clampU);
|
|
205
|
+
|
|
206
|
+
// we don't use _setUVTextureSetting here as the parameter ("clampU" - boolean) doesn't align with the actual
|
|
207
|
+
// texture setting ("wrapU" - enumeration)
|
|
208
|
+
const texture = _getTextureFromParameterChannel(pbrMaterial, channel);
|
|
209
|
+
if (texture) {
|
|
210
|
+
texture.wrapU = clampU ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
parameterManager.setParameterObserver(
|
|
216
|
+
`${channel}.${BuiltInTextureParameter.clampV}`,
|
|
217
|
+
async ({ newValue, materials }) => {
|
|
218
|
+
const clampV = ParameterManager.parseBoolean(newValue);
|
|
219
|
+
|
|
220
|
+
for (const material of materials) {
|
|
221
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.clampV);
|
|
222
|
+
|
|
223
|
+
const texture = _getTextureFromParameterChannel(pbrMaterial, channel);
|
|
224
|
+
if (texture) {
|
|
225
|
+
texture.wrapV = clampV ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
parameterManager.setParameterObserver(
|
|
231
|
+
`${channel}.${BuiltInTextureParameter.uvSet}`,
|
|
232
|
+
async ({ newValue, materials }) => {
|
|
233
|
+
const uvSet = ParameterManager.parseNumber(newValue);
|
|
234
|
+
|
|
235
|
+
for (const material of materials) {
|
|
236
|
+
const pbrMaterial = _assertAndConvertPBRMaterial(material, channel, BuiltInTextureParameter.uvSet);
|
|
237
|
+
|
|
238
|
+
const texture = _getTextureFromParameterChannel(pbrMaterial, channel);
|
|
239
|
+
if (texture) {
|
|
240
|
+
texture.coordinatesIndex = uvSet;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// this parameter is required for activating the detailmap texture, as only assigning the texture is not enough
|
|
248
|
+
parameterManager.setParameterObserver(BuiltInParameter.UseDetailmap, async ({ newValue, materials }) => {
|
|
249
|
+
const useDetailmap = ParameterManager.parseBoolean(newValue);
|
|
250
|
+
|
|
251
|
+
for (const material of materials) {
|
|
252
|
+
const materialCls = material.getClassName();
|
|
253
|
+
if (materialCls !== 'PBRMaterial') {
|
|
254
|
+
throw new Error(`Enabling detailmap for material of instance "${materialCls}" not implemented`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const pbrMaterial = material as PBRMaterial;
|
|
258
|
+
pbrMaterial.detailMap.isEnabled = useDetailmap;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Help function for casting a material into a PBRMaterial type.\
|
|
265
|
+
* Only works if the class name confirms that this is a PBR material, throws an error for any other material type.
|
|
266
|
+
*
|
|
267
|
+
* @param channel only used for error message
|
|
268
|
+
* @param parameter only used for error message
|
|
269
|
+
*/
|
|
270
|
+
function _assertAndConvertPBRMaterial(material: Material, channel: string, parameter: string): PBRMaterial {
|
|
271
|
+
const materialCls = material.getClassName();
|
|
272
|
+
if (materialCls !== 'PBRMaterial') {
|
|
273
|
+
throw new Error(`Setting ${channel} ${parameter} for material of instance "${materialCls}" not implemented`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return material as PBRMaterial;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Help function for adjusting "simple" UV texture settings, as described in the typing of `setting`
|
|
281
|
+
*/
|
|
282
|
+
function _setUVTextureSetting(
|
|
283
|
+
setting: keyof Pick<Texture, 'uOffset' | 'vOffset' | 'uScale' | 'vScale' | 'uAng' | 'vAng' | 'wAng'>,
|
|
284
|
+
value: number,
|
|
285
|
+
pbrMaterial: PBRMaterial,
|
|
286
|
+
channel: ParameterTextureChannelsKeys
|
|
287
|
+
): void {
|
|
288
|
+
const texture = _getTextureFromParameterChannel(pbrMaterial, channel);
|
|
289
|
+
|
|
290
|
+
if (texture) {
|
|
291
|
+
texture[setting] = value;
|
|
292
|
+
} else {
|
|
293
|
+
// this is fine, the texture may be created in a later step
|
|
294
|
+
// texture settings are applied automatically after the creation is done
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get the runtime texture object from a certain channel in the material.\
|
|
300
|
+
* Only returns the texture if it's from type "Texture".
|
|
301
|
+
*/
|
|
302
|
+
function _getTextureFromParameterChannel(
|
|
303
|
+
pbrMaterial: PBRMaterial,
|
|
304
|
+
channel: ParameterTextureChannelsKeys
|
|
305
|
+
): Texture | undefined {
|
|
306
|
+
let baseTexture: BaseTexture | null;
|
|
307
|
+
|
|
308
|
+
if (channel === 'metallicRoughnessTexture') {
|
|
309
|
+
baseTexture = pbrMaterial.metallicTexture;
|
|
310
|
+
} else if (channel === 'detailmapTexture') {
|
|
311
|
+
baseTexture = pbrMaterial.detailMap.texture;
|
|
312
|
+
} else {
|
|
313
|
+
// most times it's a direct assignment, special cases are handled above
|
|
314
|
+
baseTexture = pbrMaterial[channel];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// only return "Texture" types
|
|
318
|
+
return baseTexture instanceof Texture ? baseTexture : undefined;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Assign runtime texture to the dedicated channel in the PBR material
|
|
323
|
+
*/
|
|
324
|
+
function _assignTextureParameterChannel(
|
|
325
|
+
texture: Texture,
|
|
326
|
+
pbrMaterial: PBRMaterial,
|
|
327
|
+
channel: ParameterTextureChannelsKeys
|
|
328
|
+
): void {
|
|
329
|
+
if (channel === 'metallicRoughnessTexture') {
|
|
330
|
+
pbrMaterial.metallicTexture = texture;
|
|
331
|
+
} else if (channel === 'detailmapTexture') {
|
|
332
|
+
pbrMaterial.detailMap.texture = texture;
|
|
333
|
+
} else {
|
|
334
|
+
pbrMaterial[channel] = texture;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Similar to `_getTextureFromParameterChannel`, whereas the input is a plain JSON object instead of a runtime material
|
|
340
|
+
*/
|
|
341
|
+
function _getTextureObjFromParameterChannel(materialObj: object, channel: ParameterTextureChannelsKeys): object {
|
|
342
|
+
let textureObj: object | undefined;
|
|
343
|
+
|
|
344
|
+
if (channel === 'metallicRoughnessTexture') {
|
|
345
|
+
textureObj = (materialObj as any).metallicTexture;
|
|
346
|
+
} else if (channel === 'detailmapTexture') {
|
|
347
|
+
textureObj = (materialObj as any).detailMap?.texture;
|
|
348
|
+
} else {
|
|
349
|
+
textureObj = (materialObj as any)[channel];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return textureObj ?? {};
|
|
353
|
+
}
|
|
@@ -14,6 +14,12 @@ import {
|
|
|
14
14
|
import { getInternalMetadataValue, setInternalMetadataValue } from '../internal/metadata-helper';
|
|
15
15
|
import { paintableParameterObserver } from '../internal/paintable-helper';
|
|
16
16
|
import { getTags, hasTag } from '../internal/tags-helper';
|
|
17
|
+
import {
|
|
18
|
+
BuiltInTextureParameter,
|
|
19
|
+
BuiltInTextureParameterKeys,
|
|
20
|
+
ParameterTextureChannelsKeys,
|
|
21
|
+
createBuiltInTextureParameter,
|
|
22
|
+
} from '../internal/texture-parameter-helper';
|
|
17
23
|
import { capitalize, isString } from 'lodash-es';
|
|
18
24
|
|
|
19
25
|
/**
|
|
@@ -28,6 +34,18 @@ export const BuiltInParameter = {
|
|
|
28
34
|
Color: 'color',
|
|
29
35
|
Roughness: 'roughness',
|
|
30
36
|
Metallic: 'metallic',
|
|
37
|
+
/**
|
|
38
|
+
* Texture parameters are always a combination of the channel (e.g. `albedoTexture`) and a sub parameter
|
|
39
|
+
* (e.g. `uScale`). Use this function to create the parameter accordingly
|
|
40
|
+
* (e.g. createTextureParameter("albedoTexture", "uScale")).
|
|
41
|
+
*/
|
|
42
|
+
createTextureParameter: (channel: ParameterTextureChannelsKeys, parameter: BuiltInTextureParameterKeys): string =>
|
|
43
|
+
`${channel}.${parameter}`,
|
|
44
|
+
UseDetailmap: 'useDetailmap',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** @ignore @deprected Use "texture parameters" {@link BuiltInParameter}.`createTextureParameter` instead */
|
|
48
|
+
export const LegacyParameter = {
|
|
31
49
|
Paintable: 'paintable',
|
|
32
50
|
};
|
|
33
51
|
|
|
@@ -350,6 +368,40 @@ export class ParameterManager {
|
|
|
350
368
|
await this._applyParameterValues(parameterEntriesToApply);
|
|
351
369
|
}
|
|
352
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Applies subset of texture parameter values which are targeting a certain texture channel in a material.\
|
|
373
|
+
* This can be useful when updating texture settings (e.g. uScale) before the texture is actually created.
|
|
374
|
+
*
|
|
375
|
+
* @internal
|
|
376
|
+
*/
|
|
377
|
+
public async applyTextureSettingsParameter(
|
|
378
|
+
material: PBRMaterial,
|
|
379
|
+
channel: ParameterTextureChannelsKeys
|
|
380
|
+
): Promise<void> {
|
|
381
|
+
const tags = getTags(material);
|
|
382
|
+
|
|
383
|
+
const parameterEntriesToApply: ParameterEntry[] = [];
|
|
384
|
+
tags.forEach(tagName => {
|
|
385
|
+
const tagParamEntries = this._getEntriesOfSubject({ tagName });
|
|
386
|
+
parameterEntriesToApply.push(...tagParamEntries);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const materialParamEntries = this._getEntriesOfSubject({ materialName: material.id });
|
|
390
|
+
parameterEntriesToApply.push(...materialParamEntries);
|
|
391
|
+
|
|
392
|
+
const textureParameterEntriesToApply = parameterEntriesToApply.filter(parameterEntry => {
|
|
393
|
+
const paramPath = parameterEntry.parameterName.split('.');
|
|
394
|
+
// find texture parameters of this channel, e.g. "albedoTexture.uScale"
|
|
395
|
+
// "image" should not be applied here as this is part of the texture initialization anyway
|
|
396
|
+
const isTextureParamOfChannel =
|
|
397
|
+
paramPath.length === 2 && paramPath[0] === channel && paramPath[1] !== BuiltInTextureParameter.image;
|
|
398
|
+
|
|
399
|
+
return isTextureParamOfChannel;
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
await this._applyParameterValues(textureParameterEntriesToApply);
|
|
403
|
+
}
|
|
404
|
+
|
|
353
405
|
/**
|
|
354
406
|
* @returns Desired parameter value of a certain node.
|
|
355
407
|
* Tags are considered as well but have lower priority than node parameters, as these are more specific.
|
|
@@ -405,9 +457,19 @@ export class ParameterManager {
|
|
|
405
457
|
|
|
406
458
|
for (const node of nodes) {
|
|
407
459
|
if (visible) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
460
|
+
// if a mesh gets visible by this operation we have to activate the assigned material which is stored in the
|
|
461
|
+
// internal metadata
|
|
462
|
+
// => consider child meshes as well (CB-10143)
|
|
463
|
+
const activatedNodes = [node, ...node.getChildMeshes(false)];
|
|
464
|
+
for (const activatedNode of activatedNodes) {
|
|
465
|
+
const deferredMaterial = getInternalMetadataValue(activatedNode, 'deferredMaterial');
|
|
466
|
+
if (deferredMaterial) {
|
|
467
|
+
await this.viewer.materialManager.setMaterialOnMesh(
|
|
468
|
+
deferredMaterial as string,
|
|
469
|
+
// this cast is fine, as deferred material can only be set on meshes
|
|
470
|
+
activatedNode as AbstractMesh
|
|
471
|
+
);
|
|
472
|
+
}
|
|
411
473
|
}
|
|
412
474
|
|
|
413
475
|
node.setEnabled(true);
|
|
@@ -422,9 +484,22 @@ export class ParameterManager {
|
|
|
422
484
|
for (const node of nodes) {
|
|
423
485
|
// NOTE: don't use node.isEnabled() as visibility observer is probably called in same cycle but later
|
|
424
486
|
// however the parameter value is already correct at this stage
|
|
425
|
-
|
|
487
|
+
// we have to go through all parents as well, because a parent may have been set to false, which also disables
|
|
488
|
+
// this child node
|
|
489
|
+
let curNode: TransformNode | null = node;
|
|
490
|
+
let visibleByParameter: boolean | undefined = undefined;
|
|
491
|
+
while (curNode && visibleByParameter !== false) {
|
|
492
|
+
const curNodeVisibleByParameter = this.getParameterValueOfNode(curNode, BuiltInParameter.Visible);
|
|
493
|
+
if (curNodeVisibleByParameter !== undefined) {
|
|
494
|
+
visibleByParameter = curNodeVisibleByParameter as boolean;
|
|
495
|
+
}
|
|
496
|
+
curNode = curNode.parent as TransformNode;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// parameter visibility has priority, but if the visiblity is not controlled by the parameter use the plain
|
|
500
|
+
// Babylon.js isEnabled() check
|
|
426
501
|
const visible =
|
|
427
|
-
|
|
502
|
+
visibleByParameter !== undefined ? ParameterManager.parseBoolean(visibleByParameter) : node.isEnabled();
|
|
428
503
|
if (visible) {
|
|
429
504
|
// TODO WTT: check mesh type and throw error if it doesn't fit
|
|
430
505
|
// think of creating a framework with type guards (isMesh, canHaveMaterial, ...) around this
|
|
@@ -503,9 +578,12 @@ export class ParameterManager {
|
|
|
503
578
|
}
|
|
504
579
|
}
|
|
505
580
|
});
|
|
506
|
-
this.setParameterObserver(
|
|
581
|
+
this.setParameterObserver(LegacyParameter.Paintable, async ({ newValue, materials }) => {
|
|
507
582
|
paintableParameterObserver(newValue, materials, this.viewer.scene);
|
|
508
583
|
});
|
|
584
|
+
|
|
585
|
+
// texture parameter use a more generic approach (`channel`.`parameter`) and are therefore coded in a dedicated file
|
|
586
|
+
createBuiltInTextureParameter(this, this.viewer.scene);
|
|
509
587
|
}
|
|
510
588
|
|
|
511
589
|
/**
|
package/src/viewer-error.ts
CHANGED
package/src/viewer.ts
CHANGED