@archvisioninc/canvas 2.7.6 → 2.8.1
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_DEV.md +74 -0
- package/dist/helpers/canvasUpdateHelpers.js +94 -4
- package/dist/helpers/initHelpers.js +2 -0
- package/dist/helpers/utilityHelpers.js +49 -3
- package/package.json +1 -1
- package/src/package/helpers/canvasUpdateHelpers.js +90 -3
- package/src/package/helpers/initHelpers.js +2 -0
- package/src/package/helpers/utilityHelpers.js +51 -3
- package/src/scenes/App/App.js +29 -2
package/README_DEV.md
CHANGED
|
@@ -391,6 +391,12 @@ const inboundData = {
|
|
|
391
391
|
};
|
|
392
392
|
|
|
393
393
|
updateCanvas(updateArgs, inboundData);
|
|
394
|
+
|
|
395
|
+
// Clearing all texture channels
|
|
396
|
+
const inboundData = {
|
|
397
|
+
id: selectedMaterialId,
|
|
398
|
+
clearTextureChannels: true,
|
|
399
|
+
}
|
|
394
400
|
```
|
|
395
401
|
|
|
396
402
|
### Materials: Clear-coat
|
|
@@ -522,6 +528,74 @@ const inboundData = {
|
|
|
522
528
|
updateCanvas(removeArgs, inboundData);
|
|
523
529
|
```
|
|
524
530
|
|
|
531
|
+
### Materials: UV's
|
|
532
|
+
```jsx
|
|
533
|
+
// Setting UV X Scaling
|
|
534
|
+
const inboundData = {
|
|
535
|
+
id: selectedMaterialId,
|
|
536
|
+
uvXScale: newVal,
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
updateCanvas(updateArgs, inboundData);
|
|
540
|
+
|
|
541
|
+
// Setting UV Y Scaling
|
|
542
|
+
const inboundData = {
|
|
543
|
+
id: selectedMaterialId,
|
|
544
|
+
uvYScale: newVal,
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
updateCanvas(updateArgs, inboundData);
|
|
548
|
+
|
|
549
|
+
// Locking UV Y to X (or vice-versa) Scaling
|
|
550
|
+
const inboundData = {
|
|
551
|
+
id: selectedMaterialId,
|
|
552
|
+
uvXScale: newVal,
|
|
553
|
+
uvScaleLock: true,
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
updateCanvas(updateArgs, inboundData);
|
|
557
|
+
|
|
558
|
+
// Setting UV X Offset
|
|
559
|
+
const inboundData = {
|
|
560
|
+
id: selectedMaterialId,
|
|
561
|
+
uvXOffset: newVal,
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
updateCanvas(updateArgs, inboundData);
|
|
565
|
+
|
|
566
|
+
// Setting UV Y Offset
|
|
567
|
+
const inboundData = {
|
|
568
|
+
id: selectedMaterialId,
|
|
569
|
+
uvYOffset: newVal,
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
updateCanvas(updateArgs, inboundData);
|
|
573
|
+
|
|
574
|
+
// Setting UV X Rotation
|
|
575
|
+
const inboundData = {
|
|
576
|
+
id: selectedMaterialId,
|
|
577
|
+
uvXRotation: newVal,
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
updateCanvas(updateArgs, inboundData);
|
|
581
|
+
|
|
582
|
+
// Setting UV Y Rotation
|
|
583
|
+
const inboundData = {
|
|
584
|
+
id: selectedMaterialId,
|
|
585
|
+
uvYRotation: newVal,
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
updateCanvas(updateArgs, inboundData);
|
|
589
|
+
|
|
590
|
+
// Setting UV Z Rotation
|
|
591
|
+
const inboundData = {
|
|
592
|
+
id: selectedMaterialId,
|
|
593
|
+
uvZRotation: newVal,
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
updateCanvas(updateArgs, inboundData);
|
|
597
|
+
```
|
|
598
|
+
|
|
525
599
|
### Materials: General
|
|
526
600
|
```jsx
|
|
527
601
|
// Toggling back-face culling
|
|
@@ -66,8 +66,8 @@ const performTransform = args => {
|
|
|
66
66
|
const userMeshes = getUserMeshes();
|
|
67
67
|
const updatedPositions = scene.metadata.meshChangeTracking.map(mesh => {
|
|
68
68
|
const userMesh = userMeshes.find(userMesh => userMesh.id === mesh.meshId);
|
|
69
|
-
const parent = userMesh
|
|
70
|
-
userMesh
|
|
69
|
+
const parent = userMesh?.parent;
|
|
70
|
+
userMesh?.setParent?.(null);
|
|
71
71
|
const boundingBox = getBoundingMeshData([userMesh]);
|
|
72
72
|
const {
|
|
73
73
|
center,
|
|
@@ -82,7 +82,7 @@ const performTransform = args => {
|
|
|
82
82
|
ry: toDegrees(rotation.y) % 360,
|
|
83
83
|
rz: -toDegrees(rotation.z) % 360
|
|
84
84
|
};
|
|
85
|
-
userMesh
|
|
85
|
+
userMesh?.setParent?.(parent);
|
|
86
86
|
return newTracking;
|
|
87
87
|
});
|
|
88
88
|
return updatedPositions;
|
|
@@ -114,6 +114,31 @@ const performTransform = args => {
|
|
|
114
114
|
updateNode();
|
|
115
115
|
newMetaDataEntry('meshChangeTracking', newTrackingData(newTransforms));
|
|
116
116
|
};
|
|
117
|
+
const applyUVSettings = args => {
|
|
118
|
+
const {
|
|
119
|
+
texture,
|
|
120
|
+
material
|
|
121
|
+
} = args || {};
|
|
122
|
+
if (!_.isEmpty(texture) && !_.isEmpty(material)) {
|
|
123
|
+
const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === material.id);
|
|
124
|
+
const {
|
|
125
|
+
uvXScale,
|
|
126
|
+
uvYScale,
|
|
127
|
+
uvXRotation,
|
|
128
|
+
uvYRotation,
|
|
129
|
+
uvZRotation,
|
|
130
|
+
uvXOffset,
|
|
131
|
+
uvYOffset
|
|
132
|
+
} = workingMaterial?.uvSettings || {};
|
|
133
|
+
texture.uAng = uvXRotation;
|
|
134
|
+
texture.wAng = uvYRotation;
|
|
135
|
+
texture.vAng = uvZRotation;
|
|
136
|
+
texture.uOffset = uvXOffset;
|
|
137
|
+
texture.vOffset = uvYOffset;
|
|
138
|
+
texture.uScale = uvXScale;
|
|
139
|
+
texture.vScale = uvYScale;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
117
142
|
export const updateMaterial = inboundData => {
|
|
118
143
|
const {
|
|
119
144
|
payload
|
|
@@ -151,7 +176,15 @@ export const updateMaterial = inboundData => {
|
|
|
151
176
|
opacityTexture,
|
|
152
177
|
newSelectedMaterial,
|
|
153
178
|
albedoHasAlpha,
|
|
154
|
-
clearTextureChannels
|
|
179
|
+
clearTextureChannels,
|
|
180
|
+
uvXScale,
|
|
181
|
+
uvYScale,
|
|
182
|
+
uvScaleLock,
|
|
183
|
+
uvXRotation,
|
|
184
|
+
uvYRotation,
|
|
185
|
+
uvZRotation,
|
|
186
|
+
uvXOffset,
|
|
187
|
+
uvYOffset
|
|
155
188
|
} = payload;
|
|
156
189
|
const material = scene?.getMaterialByName?.(id, true);
|
|
157
190
|
if (material) {
|
|
@@ -219,6 +252,10 @@ export const updateMaterial = inboundData => {
|
|
|
219
252
|
if (!_.isEmpty(albedoTexture?.src || albedoTexture?.url)) {
|
|
220
253
|
material.albedoTexture = newTexture(albedoTexture?.src || albedoTexture?.url);
|
|
221
254
|
material.albedoTexture.name = albedoTexture.name;
|
|
255
|
+
applyUVSettings({
|
|
256
|
+
texture: material.albedoTexture,
|
|
257
|
+
material
|
|
258
|
+
});
|
|
222
259
|
}
|
|
223
260
|
|
|
224
261
|
// Metallic
|
|
@@ -226,6 +263,10 @@ export const updateMaterial = inboundData => {
|
|
|
226
263
|
if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
|
|
227
264
|
material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
|
|
228
265
|
material.metallicTexture.name = metallicTexture.name;
|
|
266
|
+
applyUVSettings({
|
|
267
|
+
texture: material.metallicTexture,
|
|
268
|
+
material
|
|
269
|
+
});
|
|
229
270
|
}
|
|
230
271
|
|
|
231
272
|
// Roughness
|
|
@@ -233,6 +274,10 @@ export const updateMaterial = inboundData => {
|
|
|
233
274
|
if (!_.isEmpty(microSurfaceTexture?.src || microSurfaceTexture?.url)) {
|
|
234
275
|
material.microSurfaceTexture = newTexture(microSurfaceTexture?.src || microSurfaceTexture?.url);
|
|
235
276
|
material.microSurfaceTexture.name = microSurfaceTexture.name;
|
|
277
|
+
applyUVSettings({
|
|
278
|
+
texture: material.microSurfaceTexture,
|
|
279
|
+
material
|
|
280
|
+
});
|
|
236
281
|
}
|
|
237
282
|
|
|
238
283
|
// Emissive
|
|
@@ -241,6 +286,10 @@ export const updateMaterial = inboundData => {
|
|
|
241
286
|
if (!_.isEmpty(emissiveTexture?.src || emissiveTexture?.url)) {
|
|
242
287
|
material.emissiveTexture = newTexture(emissiveTexture?.src || emissiveTexture?.url);
|
|
243
288
|
material.emissiveTexture.name = emissiveTexture.name;
|
|
289
|
+
applyUVSettings({
|
|
290
|
+
texture: material.emissiveTexture,
|
|
291
|
+
material
|
|
292
|
+
});
|
|
244
293
|
}
|
|
245
294
|
|
|
246
295
|
// Normal/Bump
|
|
@@ -250,6 +299,10 @@ export const updateMaterial = inboundData => {
|
|
|
250
299
|
if (!_.isEmpty(bumpTexture?.src || bumpTexture?.url)) {
|
|
251
300
|
material.bumpTexture = newTexture(bumpTexture?.src || bumpTexture?.url);
|
|
252
301
|
material.bumpTexture.name = bumpTexture.name;
|
|
302
|
+
applyUVSettings({
|
|
303
|
+
texture: material.bumpTexture,
|
|
304
|
+
material
|
|
305
|
+
});
|
|
253
306
|
}
|
|
254
307
|
|
|
255
308
|
// Clear coat
|
|
@@ -282,6 +335,10 @@ export const updateMaterial = inboundData => {
|
|
|
282
335
|
if (!_.isEmpty(opacityTexture?.src || opacityTexture?.url)) {
|
|
283
336
|
material.opacityTexture = newTexture(opacityTexture?.src || opacityTexture?.url);
|
|
284
337
|
material.opacityTexture.name = opacityTexture.name;
|
|
338
|
+
applyUVSettings({
|
|
339
|
+
texture: material.opacityTexture,
|
|
340
|
+
material
|
|
341
|
+
});
|
|
285
342
|
}
|
|
286
343
|
if (transparencyType) {
|
|
287
344
|
material.transparencyType = _.toLower(transparencyType);
|
|
@@ -294,6 +351,39 @@ export const updateMaterial = inboundData => {
|
|
|
294
351
|
if (sssRefractionIntensity !== undefined) material.subSurface.refractionIntensity = sssRefractionIntensity ?? 1;
|
|
295
352
|
if (sssIOR !== undefined) material.subSurface.indexOfRefraction = sssIOR ?? 1.52;
|
|
296
353
|
}
|
|
354
|
+
|
|
355
|
+
// UV scale, rotation and offset
|
|
356
|
+
const xScaleReq = uvXScale !== undefined;
|
|
357
|
+
const yScaleReq = uvYScale !== undefined;
|
|
358
|
+
const xRotationReq = uvXRotation !== undefined;
|
|
359
|
+
const yRotationReq = uvYRotation !== undefined;
|
|
360
|
+
const zRotationReq = uvZRotation !== undefined;
|
|
361
|
+
const xOffsetReq = uvXOffset !== undefined;
|
|
362
|
+
const yOffsetReq = uvYOffset !== undefined;
|
|
363
|
+
const uvChangeRequest = xScaleReq || yScaleReq || xRotationReq || yRotationReq || zRotationReq || xOffsetReq || yOffsetReq;
|
|
364
|
+
if (uvChangeRequest) {
|
|
365
|
+
const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === id) || {};
|
|
366
|
+
Object.keys(workingMaterial)?.forEach(key => {
|
|
367
|
+
const texture = material[key];
|
|
368
|
+
const validMaterialWithTexture = _.isObject(texture) && !_.isArray(texture) && key.endsWith('Texture');
|
|
369
|
+
const hasAllKeys = texture && ['uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale'].every(key => texture[key] !== undefined);
|
|
370
|
+
if (validMaterialWithTexture && hasAllKeys) {
|
|
371
|
+
if (xRotationReq) texture.uAng = uvXRotation;
|
|
372
|
+
if (yRotationReq) texture.wAng = uvYRotation;
|
|
373
|
+
if (zRotationReq) texture.vAng = uvZRotation;
|
|
374
|
+
if (xOffsetReq) texture.uOffset = uvXOffset;
|
|
375
|
+
if (yOffsetReq) texture.vOffset = uvYOffset;
|
|
376
|
+
if ((xScaleReq || yScaleReq) && uvScaleLock) {
|
|
377
|
+
texture.uScale = uvXScale ?? uvYScale;
|
|
378
|
+
texture.vScale = uvXScale ?? uvYScale;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (xScaleReq) texture.uScale = uvXScale;
|
|
382
|
+
if (yScaleReq) texture.vScale = uvYScale;
|
|
383
|
+
if (uvScaleLock !== undefined) newMetaDataEntry('uvScaleLock', uvScaleLock);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
297
387
|
newMetaDataEntry('materials', buildMaterialsArray());
|
|
298
388
|
newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
|
|
299
389
|
}
|
|
@@ -327,6 +327,7 @@ const initMetadataKeyDefaults = () => {
|
|
|
327
327
|
newMetaDataEntry('viewportAxes', true);
|
|
328
328
|
newMetaDataEntry('viewportShadows', mirrorGround.receiveShadows);
|
|
329
329
|
newMetaDataEntry('fileName', null);
|
|
330
|
+
newMetaDataEntry('uvScaleLock', false);
|
|
330
331
|
};
|
|
331
332
|
const checkForRootNode = () => {
|
|
332
333
|
let rootNode = scene.getNodeById('__root__');
|
|
@@ -447,6 +448,7 @@ export const initSceneFromFile = (sceneFromFile, fileName) => {
|
|
|
447
448
|
newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
|
|
448
449
|
newMetaDataEntry('fileName', fileName);
|
|
449
450
|
newMetaDataEntry('materialVariants', buildMaterialVariantsArray());
|
|
451
|
+
newMetaDataEntry('uvScaleLock', scene.metadata.uvScaleLock || false);
|
|
450
452
|
updatePublish(fileName ? {
|
|
451
453
|
payload: {
|
|
452
454
|
title: fileName
|
|
@@ -448,6 +448,46 @@ export const getTextureUrl = args => {
|
|
|
448
448
|
asDataUrl
|
|
449
449
|
});
|
|
450
450
|
};
|
|
451
|
+
export const getExistingUVSettings = args => {
|
|
452
|
+
const {
|
|
453
|
+
materialId
|
|
454
|
+
} = args || {};
|
|
455
|
+
let settingsFound = false;
|
|
456
|
+
let uvSettings = {
|
|
457
|
+
uvXScale: 1,
|
|
458
|
+
uvYScale: 1,
|
|
459
|
+
uvXRotation: 0,
|
|
460
|
+
uvYRotation: 0,
|
|
461
|
+
uvZRotation: 0,
|
|
462
|
+
uvXOffset: 0,
|
|
463
|
+
uvYOffset: 0
|
|
464
|
+
};
|
|
465
|
+
const userMaterials = getUserMaterials();
|
|
466
|
+
const material = userMaterials.find(mat => mat.id === materialId);
|
|
467
|
+
Object.keys(material)?.find?.(key => {
|
|
468
|
+
const validMaterialWithTexture = _.isObject(material[key]) && !_.isArray(material[key]) && key.endsWith('Texture');
|
|
469
|
+
const texture = material[key];
|
|
470
|
+
const isEnvironment = key.toLowerCase().includes('environment');
|
|
471
|
+
const hasAllKeys = texture && ['uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale'].every(key => texture[key] !== undefined);
|
|
472
|
+
|
|
473
|
+
// NOTE: All UV's are adjusted globally, at the same time in canvasUpdateHelpers.js
|
|
474
|
+
// when **any** UV setting is changed. So we only need to find the first one to
|
|
475
|
+
// restore the UV settings.
|
|
476
|
+
if (!isEnvironment && validMaterialWithTexture && hasAllKeys && !settingsFound) {
|
|
477
|
+
settingsFound = true;
|
|
478
|
+
uvSettings = {
|
|
479
|
+
uvXScale: texture.uScale,
|
|
480
|
+
uvYScale: texture.vScale,
|
|
481
|
+
uvXRotation: texture.uAng,
|
|
482
|
+
uvYRotation: texture.wAng,
|
|
483
|
+
uvZRotation: texture.vAng,
|
|
484
|
+
uvXOffset: texture.uOffset,
|
|
485
|
+
uvYOffset: texture.vOffset
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
return uvSettings;
|
|
490
|
+
};
|
|
451
491
|
export const materialData = material => {
|
|
452
492
|
const meshesWithMaterial = getUserMeshes().map(mesh => {
|
|
453
493
|
if (mesh.material.name === material.id) return mesh;
|
|
@@ -509,6 +549,12 @@ export const materialData = material => {
|
|
|
509
549
|
asDataUrl: true
|
|
510
550
|
})
|
|
511
551
|
},
|
|
552
|
+
// UV
|
|
553
|
+
uvSettings: {
|
|
554
|
+
...getExistingUVSettings({
|
|
555
|
+
materialId: material.id
|
|
556
|
+
})
|
|
557
|
+
},
|
|
512
558
|
// Advanced
|
|
513
559
|
clearCoatEnabled: material.clearCoat?.isEnabled || false,
|
|
514
560
|
clearCoatIntensity: material.clearCoat?.intensity,
|
|
@@ -573,9 +619,9 @@ export const takePreviewScreenshots = () => {
|
|
|
573
619
|
const yAxisMesh = scene.getMeshByName('yAxisMesh');
|
|
574
620
|
const zAxisMesh = scene.getMeshByName('zAxisMesh');
|
|
575
621
|
const hdrSkyBox = scene.getMeshByName('hdrSkyBox');
|
|
576
|
-
const axesVisible = xAxisMesh
|
|
577
|
-
const skyBoxVisible = hdrSkyBox
|
|
578
|
-
const frameVisible = outerFrame
|
|
622
|
+
const axesVisible = xAxisMesh?.isVisible;
|
|
623
|
+
const skyBoxVisible = hdrSkyBox?.isVisible;
|
|
624
|
+
const frameVisible = outerFrame?.isVisible;
|
|
579
625
|
const groundVisible = ground.isVisible;
|
|
580
626
|
const mirrorGroundVisible = mirrorGround.isVisible;
|
|
581
627
|
const {
|
package/package.json
CHANGED
|
@@ -102,9 +102,9 @@ const performTransform = args => {
|
|
|
102
102
|
const userMeshes = getUserMeshes();
|
|
103
103
|
const updatedPositions = scene.metadata.meshChangeTracking.map(mesh => {
|
|
104
104
|
const userMesh = userMeshes.find(userMesh => userMesh.id === mesh.meshId);
|
|
105
|
-
const parent = userMesh
|
|
105
|
+
const parent = userMesh?.parent;
|
|
106
106
|
|
|
107
|
-
userMesh
|
|
107
|
+
userMesh?.setParent?.(null);
|
|
108
108
|
|
|
109
109
|
const boundingBox = getBoundingMeshData([ userMesh ]);
|
|
110
110
|
const { center, rotation } = boundingBox;
|
|
@@ -119,7 +119,7 @@ const performTransform = args => {
|
|
|
119
119
|
rz: -toDegrees(rotation.z) % 360,
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
userMesh
|
|
122
|
+
userMesh?.setParent?.(parent);
|
|
123
123
|
return newTracking;
|
|
124
124
|
});
|
|
125
125
|
|
|
@@ -152,6 +152,31 @@ const performTransform = args => {
|
|
|
152
152
|
newMetaDataEntry('meshChangeTracking', newTrackingData(newTransforms));
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
+
const applyUVSettings = args => {
|
|
156
|
+
const { texture, material } = args || {};
|
|
157
|
+
|
|
158
|
+
if (!_.isEmpty(texture) && !_.isEmpty(material)) {
|
|
159
|
+
const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === material.id);
|
|
160
|
+
const {
|
|
161
|
+
uvXScale,
|
|
162
|
+
uvYScale,
|
|
163
|
+
uvXRotation,
|
|
164
|
+
uvYRotation,
|
|
165
|
+
uvZRotation,
|
|
166
|
+
uvXOffset,
|
|
167
|
+
uvYOffset,
|
|
168
|
+
} = workingMaterial?.uvSettings || {};
|
|
169
|
+
|
|
170
|
+
texture.uAng = uvXRotation;
|
|
171
|
+
texture.wAng = uvYRotation;
|
|
172
|
+
texture.vAng = uvZRotation;
|
|
173
|
+
texture.uOffset = uvXOffset;
|
|
174
|
+
texture.vOffset = uvYOffset;
|
|
175
|
+
texture.uScale = uvXScale;
|
|
176
|
+
texture.vScale = uvYScale;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
155
180
|
export const updateMaterial = inboundData => {
|
|
156
181
|
const { payload } = inboundData;
|
|
157
182
|
const {
|
|
@@ -188,6 +213,14 @@ export const updateMaterial = inboundData => {
|
|
|
188
213
|
newSelectedMaterial,
|
|
189
214
|
albedoHasAlpha,
|
|
190
215
|
clearTextureChannels,
|
|
216
|
+
uvXScale,
|
|
217
|
+
uvYScale,
|
|
218
|
+
uvScaleLock,
|
|
219
|
+
uvXRotation,
|
|
220
|
+
uvYRotation,
|
|
221
|
+
uvZRotation,
|
|
222
|
+
uvXOffset,
|
|
223
|
+
uvYOffset,
|
|
191
224
|
} = payload;
|
|
192
225
|
|
|
193
226
|
const material = scene?.getMaterialByName?.(id, true);
|
|
@@ -253,6 +286,8 @@ export const updateMaterial = inboundData => {
|
|
|
253
286
|
if (!_.isEmpty(albedoTexture?.src || albedoTexture?.url)) {
|
|
254
287
|
material.albedoTexture = newTexture(albedoTexture?.src || albedoTexture?.url);
|
|
255
288
|
material.albedoTexture.name = albedoTexture.name;
|
|
289
|
+
|
|
290
|
+
applyUVSettings({ texture: material.albedoTexture, material });
|
|
256
291
|
}
|
|
257
292
|
|
|
258
293
|
// Metallic
|
|
@@ -260,6 +295,8 @@ export const updateMaterial = inboundData => {
|
|
|
260
295
|
if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
|
|
261
296
|
material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
|
|
262
297
|
material.metallicTexture.name = metallicTexture.name;
|
|
298
|
+
|
|
299
|
+
applyUVSettings({ texture: material.metallicTexture, material });
|
|
263
300
|
}
|
|
264
301
|
|
|
265
302
|
// Roughness
|
|
@@ -267,6 +304,8 @@ export const updateMaterial = inboundData => {
|
|
|
267
304
|
if (!_.isEmpty(microSurfaceTexture?.src || microSurfaceTexture?.url)) {
|
|
268
305
|
material.microSurfaceTexture = newTexture(microSurfaceTexture?.src || microSurfaceTexture?.url);
|
|
269
306
|
material.microSurfaceTexture.name = microSurfaceTexture.name;
|
|
307
|
+
|
|
308
|
+
applyUVSettings({ texture: material.microSurfaceTexture, material });
|
|
270
309
|
}
|
|
271
310
|
|
|
272
311
|
// Emissive
|
|
@@ -275,6 +314,8 @@ export const updateMaterial = inboundData => {
|
|
|
275
314
|
if (!_.isEmpty(emissiveTexture?.src || emissiveTexture?.url)) {
|
|
276
315
|
material.emissiveTexture = newTexture(emissiveTexture?.src || emissiveTexture?.url);
|
|
277
316
|
material.emissiveTexture.name = emissiveTexture.name;
|
|
317
|
+
|
|
318
|
+
applyUVSettings({ texture: material.emissiveTexture, material });
|
|
278
319
|
}
|
|
279
320
|
|
|
280
321
|
// Normal/Bump
|
|
@@ -285,6 +326,8 @@ export const updateMaterial = inboundData => {
|
|
|
285
326
|
if (!_.isEmpty(bumpTexture?.src || bumpTexture?.url)) {
|
|
286
327
|
material.bumpTexture = newTexture(bumpTexture?.src || bumpTexture?.url);
|
|
287
328
|
material.bumpTexture.name = bumpTexture.name;
|
|
329
|
+
|
|
330
|
+
applyUVSettings({ texture: material.bumpTexture, material });
|
|
288
331
|
}
|
|
289
332
|
|
|
290
333
|
// Clear coat
|
|
@@ -322,6 +365,8 @@ export const updateMaterial = inboundData => {
|
|
|
322
365
|
if (!_.isEmpty(opacityTexture?.src || opacityTexture?.url)) {
|
|
323
366
|
material.opacityTexture = newTexture(opacityTexture?.src || opacityTexture?.url);
|
|
324
367
|
material.opacityTexture.name = opacityTexture.name;
|
|
368
|
+
|
|
369
|
+
applyUVSettings({ texture: material.opacityTexture, material });
|
|
325
370
|
}
|
|
326
371
|
|
|
327
372
|
if (transparencyType) {
|
|
@@ -339,6 +384,48 @@ export const updateMaterial = inboundData => {
|
|
|
339
384
|
if (sssIOR !== undefined) material.subSurface.indexOfRefraction = sssIOR ?? 1.52;
|
|
340
385
|
}
|
|
341
386
|
|
|
387
|
+
// UV scale, rotation and offset
|
|
388
|
+
const xScaleReq = uvXScale !== undefined;
|
|
389
|
+
const yScaleReq = uvYScale !== undefined;
|
|
390
|
+
const xRotationReq = uvXRotation !== undefined;
|
|
391
|
+
const yRotationReq = uvYRotation !== undefined;
|
|
392
|
+
const zRotationReq = uvZRotation !== undefined;
|
|
393
|
+
const xOffsetReq = uvXOffset !== undefined;
|
|
394
|
+
const yOffsetReq = uvYOffset !== undefined;
|
|
395
|
+
const uvChangeRequest = xScaleReq || yScaleReq || xRotationReq
|
|
396
|
+
|| yRotationReq || zRotationReq || xOffsetReq || yOffsetReq;
|
|
397
|
+
|
|
398
|
+
if (uvChangeRequest) {
|
|
399
|
+
const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === id) || {};
|
|
400
|
+
|
|
401
|
+
Object.keys(workingMaterial)?.forEach(key => {
|
|
402
|
+
const texture = material[key];
|
|
403
|
+
const validMaterialWithTexture = _.isObject(texture) && !_.isArray(texture) && key.endsWith('Texture');
|
|
404
|
+
const hasAllKeys = texture && [ 'uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale' ]
|
|
405
|
+
.every(key => texture[key] !== undefined);
|
|
406
|
+
|
|
407
|
+
if (validMaterialWithTexture && hasAllKeys) {
|
|
408
|
+
if (xRotationReq) texture.uAng = uvXRotation;
|
|
409
|
+
if (yRotationReq) texture.wAng = uvYRotation;
|
|
410
|
+
if (zRotationReq) texture.vAng = uvZRotation;
|
|
411
|
+
|
|
412
|
+
if (xOffsetReq) texture.uOffset = uvXOffset;
|
|
413
|
+
if (yOffsetReq) texture.vOffset = uvYOffset;
|
|
414
|
+
|
|
415
|
+
if ((xScaleReq || yScaleReq) && uvScaleLock) {
|
|
416
|
+
texture.uScale = uvXScale ?? uvYScale;
|
|
417
|
+
texture.vScale = uvXScale ?? uvYScale;
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (xScaleReq) texture.uScale = uvXScale;
|
|
422
|
+
if (yScaleReq) texture.vScale = uvYScale;
|
|
423
|
+
|
|
424
|
+
if (uvScaleLock !== undefined) newMetaDataEntry('uvScaleLock', uvScaleLock);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
342
429
|
newMetaDataEntry('materials', buildMaterialsArray());
|
|
343
430
|
newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
|
|
344
431
|
}
|
|
@@ -364,6 +364,7 @@ const initMetadataKeyDefaults = () => {
|
|
|
364
364
|
newMetaDataEntry('viewportAxes', true);
|
|
365
365
|
newMetaDataEntry('viewportShadows', mirrorGround.receiveShadows);
|
|
366
366
|
newMetaDataEntry('fileName', null);
|
|
367
|
+
newMetaDataEntry('uvScaleLock', false);
|
|
367
368
|
};
|
|
368
369
|
|
|
369
370
|
const checkForRootNode = () => {
|
|
@@ -482,6 +483,7 @@ export const initSceneFromFile = (sceneFromFile, fileName) => {
|
|
|
482
483
|
newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
|
|
483
484
|
newMetaDataEntry('fileName', fileName);
|
|
484
485
|
newMetaDataEntry('materialVariants', buildMaterialVariantsArray());
|
|
486
|
+
newMetaDataEntry('uvScaleLock', scene.metadata.uvScaleLock || false);
|
|
485
487
|
|
|
486
488
|
updatePublish(fileName ? { payload: { title: fileName } } : {});
|
|
487
489
|
|
|
@@ -509,6 +509,49 @@ export const getTextureUrl = args => {
|
|
|
509
509
|
return getImageFileFromBuffer({ buffer, asDataUrl });
|
|
510
510
|
};
|
|
511
511
|
|
|
512
|
+
export const getExistingUVSettings = args => {
|
|
513
|
+
const { materialId } = args || {};
|
|
514
|
+
let settingsFound = false;
|
|
515
|
+
let uvSettings = {
|
|
516
|
+
uvXScale: 1,
|
|
517
|
+
uvYScale: 1,
|
|
518
|
+
uvXRotation: 0,
|
|
519
|
+
uvYRotation: 0,
|
|
520
|
+
uvZRotation: 0,
|
|
521
|
+
uvXOffset: 0,
|
|
522
|
+
uvYOffset: 0,
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
const userMaterials = getUserMaterials();
|
|
526
|
+
const material = userMaterials.find(mat => mat.id === materialId);
|
|
527
|
+
|
|
528
|
+
Object.keys(material)?.find?.(key => {
|
|
529
|
+
const validMaterialWithTexture = _.isObject(material[key]) && !_.isArray(material[key]) && key.endsWith('Texture');
|
|
530
|
+
const texture = material[key];
|
|
531
|
+
const isEnvironment = key.toLowerCase().includes('environment');
|
|
532
|
+
const hasAllKeys = texture && [ 'uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale' ]
|
|
533
|
+
.every(key => texture[key] !== undefined);
|
|
534
|
+
|
|
535
|
+
// NOTE: All UV's are adjusted globally, at the same time in canvasUpdateHelpers.js
|
|
536
|
+
// when **any** UV setting is changed. So we only need to find the first one to
|
|
537
|
+
// restore the UV settings.
|
|
538
|
+
if (!isEnvironment && validMaterialWithTexture && hasAllKeys && !settingsFound) {
|
|
539
|
+
settingsFound = true;
|
|
540
|
+
uvSettings = {
|
|
541
|
+
uvXScale: texture.uScale,
|
|
542
|
+
uvYScale: texture.vScale,
|
|
543
|
+
uvXRotation: texture.uAng,
|
|
544
|
+
uvYRotation: texture.wAng,
|
|
545
|
+
uvZRotation: texture.vAng,
|
|
546
|
+
uvXOffset: texture.uOffset,
|
|
547
|
+
uvYOffset: texture.vOffset,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
return uvSettings;
|
|
553
|
+
};
|
|
554
|
+
|
|
512
555
|
export const materialData = material => {
|
|
513
556
|
const meshesWithMaterial = getUserMeshes().map(mesh => {
|
|
514
557
|
if (mesh.material.name === material.id) return mesh;
|
|
@@ -561,6 +604,11 @@ export const materialData = material => {
|
|
|
561
604
|
url: getTextureUrl({ texture: material.bumpTexture, asDataUrl: true }),
|
|
562
605
|
},
|
|
563
606
|
|
|
607
|
+
// UV
|
|
608
|
+
uvSettings: {
|
|
609
|
+
...getExistingUVSettings({ materialId: material.id }),
|
|
610
|
+
},
|
|
611
|
+
|
|
564
612
|
// Advanced
|
|
565
613
|
clearCoatEnabled: material.clearCoat?.isEnabled || false,
|
|
566
614
|
clearCoatIntensity: material.clearCoat?.intensity,
|
|
@@ -635,9 +683,9 @@ export const takePreviewScreenshots = () => {
|
|
|
635
683
|
const yAxisMesh = scene.getMeshByName('yAxisMesh');
|
|
636
684
|
const zAxisMesh = scene.getMeshByName('zAxisMesh');
|
|
637
685
|
const hdrSkyBox = scene.getMeshByName('hdrSkyBox');
|
|
638
|
-
const axesVisible = xAxisMesh
|
|
639
|
-
const skyBoxVisible = hdrSkyBox
|
|
640
|
-
const frameVisible = outerFrame
|
|
686
|
+
const axesVisible = xAxisMesh?.isVisible;
|
|
687
|
+
const skyBoxVisible = hdrSkyBox?.isVisible;
|
|
688
|
+
const frameVisible = outerFrame?.isVisible;
|
|
641
689
|
const groundVisible = ground.isVisible;
|
|
642
690
|
const mirrorGroundVisible = mirrorGround.isVisible;
|
|
643
691
|
const {
|
package/src/scenes/App/App.js
CHANGED
|
@@ -15,10 +15,18 @@ const demoScene = false;
|
|
|
15
15
|
const shaderballGuid = '21-791A-0D8D-F8A0-63F7-5086-471F-69A7-7AB0-00';
|
|
16
16
|
|
|
17
17
|
const serializedResponseData = {
|
|
18
|
-
albedoColor: '#
|
|
18
|
+
albedoColor: '#FFFFFF',
|
|
19
19
|
albedoHasAlpha: false,
|
|
20
20
|
albedoTexture: {
|
|
21
21
|
name: 'Blender.png',
|
|
22
|
+
uvXScale: 1,
|
|
23
|
+
uvYScale: 1,
|
|
24
|
+
uvScaleLock: false,
|
|
25
|
+
uvXRotation: 0,
|
|
26
|
+
uvYRotation: 0,
|
|
27
|
+
uvZRotation: 0,
|
|
28
|
+
uvXOffset: 0,
|
|
29
|
+
uvYOffset: 0,
|
|
22
30
|
url: 'data:image/png;base64,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',
|
|
23
31
|
},
|
|
24
32
|
alpha: 1,
|
|
@@ -44,7 +52,7 @@ const serializedResponseData = {
|
|
|
44
52
|
type: 'custom',
|
|
45
53
|
userTargetTriangles: 76004,
|
|
46
54
|
},
|
|
47
|
-
metallic:
|
|
55
|
+
metallic: 0,
|
|
48
56
|
metallicTexture: { url: '' },
|
|
49
57
|
microSurfaceTexture: { url: '' },
|
|
50
58
|
name: 'material',
|
|
@@ -199,6 +207,25 @@ const App = () => {
|
|
|
199
207
|
Change material
|
|
200
208
|
</Button>
|
|
201
209
|
|
|
210
|
+
<Button
|
|
211
|
+
theme={theme}
|
|
212
|
+
$selectedTheme={selectedTheme}
|
|
213
|
+
onClick={() => {
|
|
214
|
+
const inboundData = {
|
|
215
|
+
payload: {
|
|
216
|
+
id: 'material',
|
|
217
|
+
uvYOffset: 0.25,
|
|
218
|
+
uvScaleLock: true,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
updateMaterial(inboundData);
|
|
223
|
+
console.log({ metadata: scene.metadata });
|
|
224
|
+
}}
|
|
225
|
+
>
|
|
226
|
+
UV Y Offset
|
|
227
|
+
</Button>
|
|
228
|
+
|
|
202
229
|
<Button
|
|
203
230
|
theme={theme}
|
|
204
231
|
$selectedTheme={selectedTheme}
|