@archvisioninc/canvas 2.7.6 → 2.8.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/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
@@ -1,3 +1,4 @@
1
+ /* eslint-disable */
1
2
  import { getUserMeshes, resetSelectedMeshes, addNewMesh, scene, mirrorGround, ground, newVector, newColor, newScreenshot, serializeScene, newMetaDataEntry, selectedMeshes, singleMeshTNode, toRadians, toDegrees, multiMeshTNode, handleMousePointerTap, prepareCamera, buildMaterialsArray, buildMeshPositionsArray, createBoundingMesh, attachToSelectMeshesNode, newTexture, getUserMaterials, buildSelectedMaterialArray, buildMeshIdArray, refreshHighlight, guiTexture, getBoundingMeshData, getScaleFactor, gizmoManager } from '../helpers';
2
3
  import { toggleSafeFrame, toggleOrthographicViews, toggleBoundingBoxWidget, resetManagerGizmos, modelToOrigin, focusCamera } from '../actions';
3
4
  import { GLTF2 } from 'babylonjs-loaders';
@@ -114,6 +115,31 @@ const performTransform = args => {
114
115
  updateNode();
115
116
  newMetaDataEntry('meshChangeTracking', newTrackingData(newTransforms));
116
117
  };
118
+ const applyUVSettings = args => {
119
+ const {
120
+ texture,
121
+ material
122
+ } = args || {};
123
+ if (!_.isEmpty(texture) && !_.isEmpty(material)) {
124
+ const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === material.id);
125
+ const {
126
+ uvXScale,
127
+ uvYScale,
128
+ uvXRotation,
129
+ uvYRotation,
130
+ uvZRotation,
131
+ uvXOffset,
132
+ uvYOffset
133
+ } = workingMaterial?.uvSettings || {};
134
+ texture.uAng = uvXRotation;
135
+ texture.wAng = uvYRotation;
136
+ texture.vAng = uvZRotation;
137
+ texture.uOffset = uvXOffset;
138
+ texture.vOffset = uvYOffset;
139
+ texture.uScale = uvXScale;
140
+ texture.vScale = uvYScale;
141
+ }
142
+ };
117
143
  export const updateMaterial = inboundData => {
118
144
  const {
119
145
  payload
@@ -151,7 +177,15 @@ export const updateMaterial = inboundData => {
151
177
  opacityTexture,
152
178
  newSelectedMaterial,
153
179
  albedoHasAlpha,
154
- clearTextureChannels
180
+ clearTextureChannels,
181
+ uvXScale,
182
+ uvYScale,
183
+ uvScaleLock,
184
+ uvXRotation,
185
+ uvYRotation,
186
+ uvZRotation,
187
+ uvXOffset,
188
+ uvYOffset
155
189
  } = payload;
156
190
  const material = scene?.getMaterialByName?.(id, true);
157
191
  if (material) {
@@ -219,6 +253,10 @@ export const updateMaterial = inboundData => {
219
253
  if (!_.isEmpty(albedoTexture?.src || albedoTexture?.url)) {
220
254
  material.albedoTexture = newTexture(albedoTexture?.src || albedoTexture?.url);
221
255
  material.albedoTexture.name = albedoTexture.name;
256
+ applyUVSettings({
257
+ texture: material.albedoTexture,
258
+ material
259
+ });
222
260
  }
223
261
 
224
262
  // Metallic
@@ -226,6 +264,10 @@ export const updateMaterial = inboundData => {
226
264
  if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
227
265
  material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
228
266
  material.metallicTexture.name = metallicTexture.name;
267
+ applyUVSettings({
268
+ texture: material.metallicTexture,
269
+ material
270
+ });
229
271
  }
230
272
 
231
273
  // Roughness
@@ -233,6 +275,10 @@ export const updateMaterial = inboundData => {
233
275
  if (!_.isEmpty(microSurfaceTexture?.src || microSurfaceTexture?.url)) {
234
276
  material.microSurfaceTexture = newTexture(microSurfaceTexture?.src || microSurfaceTexture?.url);
235
277
  material.microSurfaceTexture.name = microSurfaceTexture.name;
278
+ applyUVSettings({
279
+ texture: material.microSurfaceTexture,
280
+ material
281
+ });
236
282
  }
237
283
 
238
284
  // Emissive
@@ -241,6 +287,10 @@ export const updateMaterial = inboundData => {
241
287
  if (!_.isEmpty(emissiveTexture?.src || emissiveTexture?.url)) {
242
288
  material.emissiveTexture = newTexture(emissiveTexture?.src || emissiveTexture?.url);
243
289
  material.emissiveTexture.name = emissiveTexture.name;
290
+ applyUVSettings({
291
+ texture: material.emissiveTexture,
292
+ material
293
+ });
244
294
  }
245
295
 
246
296
  // Normal/Bump
@@ -250,6 +300,10 @@ export const updateMaterial = inboundData => {
250
300
  if (!_.isEmpty(bumpTexture?.src || bumpTexture?.url)) {
251
301
  material.bumpTexture = newTexture(bumpTexture?.src || bumpTexture?.url);
252
302
  material.bumpTexture.name = bumpTexture.name;
303
+ applyUVSettings({
304
+ texture: material.bumpTexture,
305
+ material
306
+ });
253
307
  }
254
308
 
255
309
  // Clear coat
@@ -282,6 +336,10 @@ export const updateMaterial = inboundData => {
282
336
  if (!_.isEmpty(opacityTexture?.src || opacityTexture?.url)) {
283
337
  material.opacityTexture = newTexture(opacityTexture?.src || opacityTexture?.url);
284
338
  material.opacityTexture.name = opacityTexture.name;
339
+ applyUVSettings({
340
+ texture: material.opacityTexture,
341
+ material
342
+ });
285
343
  }
286
344
  if (transparencyType) {
287
345
  material.transparencyType = _.toLower(transparencyType);
@@ -294,6 +352,39 @@ export const updateMaterial = inboundData => {
294
352
  if (sssRefractionIntensity !== undefined) material.subSurface.refractionIntensity = sssRefractionIntensity ?? 1;
295
353
  if (sssIOR !== undefined) material.subSurface.indexOfRefraction = sssIOR ?? 1.52;
296
354
  }
355
+
356
+ // UV scale, rotation and offset
357
+ const xScaleReq = uvXScale !== undefined;
358
+ const yScaleReq = uvYScale !== undefined;
359
+ const xRotationReq = uvXRotation !== undefined;
360
+ const yRotationReq = uvYRotation !== undefined;
361
+ const zRotationReq = uvZRotation !== undefined;
362
+ const xOffsetReq = uvXOffset !== undefined;
363
+ const yOffsetReq = uvYOffset !== undefined;
364
+ const uvChangeRequest = xScaleReq || yScaleReq || xRotationReq || yRotationReq || zRotationReq || xOffsetReq || yOffsetReq;
365
+ if (uvChangeRequest) {
366
+ const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === id) || {};
367
+ Object.keys(workingMaterial)?.forEach(key => {
368
+ const validMaterialWithTexture = _.isObject(material[key]) && !_.isArray(material[key]) && key.endsWith('Texture');
369
+ const texture = material[key];
370
+ const hasAllKeys = texture && ['uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale'].every(key => texture[key] !== undefined);
371
+ if (validMaterialWithTexture && hasAllKeys) {
372
+ if (xRotationReq) texture.uAng = uvXRotation;
373
+ if (yRotationReq) texture.wAng = uvYRotation;
374
+ if (zRotationReq) texture.vAng = uvZRotation;
375
+ if (xOffsetReq) texture.uOffset = uvXOffset;
376
+ if (yOffsetReq) texture.vOffset = uvYOffset;
377
+ if ((xScaleReq || yScaleReq) && uvScaleLock) {
378
+ texture.uScale = uvXScale ?? uvYScale;
379
+ texture.vScale = uvXScale ?? uvYScale;
380
+ return;
381
+ }
382
+ if (xScaleReq) texture.uScale = uvXScale;
383
+ if (yScaleReq) texture.vScale = uvYScale;
384
+ if (uvScaleLock !== undefined) newMetaDataEntry('uvScaleLock', uvScaleLock);
385
+ }
386
+ });
387
+ }
297
388
  newMetaDataEntry('materials', buildMaterialsArray());
298
389
  newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
299
390
  }
@@ -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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archvisioninc/canvas",
3
- "version": "2.7.6",
3
+ "version": "2.8.0",
4
4
  "private": false,
5
5
  "main": "dist/Canvas.js",
6
6
  "module": "dist/Canvas.js",
@@ -1,3 +1,4 @@
1
+ /* eslint-disable */
1
2
  import {
2
3
  getUserMeshes,
3
4
  resetSelectedMeshes,
@@ -152,6 +153,23 @@ const performTransform = args => {
152
153
  newMetaDataEntry('meshChangeTracking', newTrackingData(newTransforms));
153
154
  };
154
155
 
156
+ const applyUVSettings = args => {
157
+ const { texture, material } = args || {};
158
+
159
+ if (!_.isEmpty(texture) && !_.isEmpty(material)) {
160
+ const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === material.id);
161
+ const { uvXScale, uvYScale, uvXRotation, uvYRotation, uvZRotation, uvXOffset, uvYOffset } = workingMaterial?.uvSettings || {};
162
+
163
+ texture.uAng = uvXRotation;
164
+ texture.wAng = uvYRotation;
165
+ texture.vAng = uvZRotation;
166
+ texture.uOffset = uvXOffset;
167
+ texture.vOffset = uvYOffset;
168
+ texture.uScale = uvXScale;
169
+ texture.vScale = uvYScale;
170
+ }
171
+ };
172
+
155
173
  export const updateMaterial = inboundData => {
156
174
  const { payload } = inboundData;
157
175
  const {
@@ -188,6 +206,14 @@ export const updateMaterial = inboundData => {
188
206
  newSelectedMaterial,
189
207
  albedoHasAlpha,
190
208
  clearTextureChannels,
209
+ uvXScale,
210
+ uvYScale,
211
+ uvScaleLock,
212
+ uvXRotation,
213
+ uvYRotation,
214
+ uvZRotation,
215
+ uvXOffset,
216
+ uvYOffset,
191
217
  } = payload;
192
218
 
193
219
  const material = scene?.getMaterialByName?.(id, true);
@@ -253,6 +279,8 @@ export const updateMaterial = inboundData => {
253
279
  if (!_.isEmpty(albedoTexture?.src || albedoTexture?.url)) {
254
280
  material.albedoTexture = newTexture(albedoTexture?.src || albedoTexture?.url);
255
281
  material.albedoTexture.name = albedoTexture.name;
282
+
283
+ applyUVSettings({ texture: material.albedoTexture, material });
256
284
  }
257
285
 
258
286
  // Metallic
@@ -260,6 +288,8 @@ export const updateMaterial = inboundData => {
260
288
  if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
261
289
  material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
262
290
  material.metallicTexture.name = metallicTexture.name;
291
+
292
+ applyUVSettings({ texture: material.metallicTexture, material });
263
293
  }
264
294
 
265
295
  // Roughness
@@ -267,6 +297,8 @@ export const updateMaterial = inboundData => {
267
297
  if (!_.isEmpty(microSurfaceTexture?.src || microSurfaceTexture?.url)) {
268
298
  material.microSurfaceTexture = newTexture(microSurfaceTexture?.src || microSurfaceTexture?.url);
269
299
  material.microSurfaceTexture.name = microSurfaceTexture.name;
300
+
301
+ applyUVSettings({ texture: material.microSurfaceTexture, material });
270
302
  }
271
303
 
272
304
  // Emissive
@@ -275,6 +307,8 @@ export const updateMaterial = inboundData => {
275
307
  if (!_.isEmpty(emissiveTexture?.src || emissiveTexture?.url)) {
276
308
  material.emissiveTexture = newTexture(emissiveTexture?.src || emissiveTexture?.url);
277
309
  material.emissiveTexture.name = emissiveTexture.name;
310
+
311
+ applyUVSettings({ texture: material.emissiveTexture, material });
278
312
  }
279
313
 
280
314
  // Normal/Bump
@@ -285,6 +319,8 @@ export const updateMaterial = inboundData => {
285
319
  if (!_.isEmpty(bumpTexture?.src || bumpTexture?.url)) {
286
320
  material.bumpTexture = newTexture(bumpTexture?.src || bumpTexture?.url);
287
321
  material.bumpTexture.name = bumpTexture.name;
322
+
323
+ applyUVSettings({ texture: material.bumpTexture, material });
288
324
  }
289
325
 
290
326
  // Clear coat
@@ -322,6 +358,8 @@ export const updateMaterial = inboundData => {
322
358
  if (!_.isEmpty(opacityTexture?.src || opacityTexture?.url)) {
323
359
  material.opacityTexture = newTexture(opacityTexture?.src || opacityTexture?.url);
324
360
  material.opacityTexture.name = opacityTexture.name;
361
+
362
+ applyUVSettings({ texture: material.opacityTexture, material });
325
363
  }
326
364
 
327
365
  if (transparencyType) {
@@ -339,6 +377,47 @@ export const updateMaterial = inboundData => {
339
377
  if (sssIOR !== undefined) material.subSurface.indexOfRefraction = sssIOR ?? 1.52;
340
378
  }
341
379
 
380
+ // UV scale, rotation and offset
381
+ const xScaleReq = uvXScale !== undefined;
382
+ const yScaleReq = uvYScale !== undefined;
383
+ const xRotationReq = uvXRotation !== undefined;
384
+ const yRotationReq = uvYRotation !== undefined;
385
+ const zRotationReq = uvZRotation !== undefined;
386
+ const xOffsetReq = uvXOffset !== undefined;
387
+ const yOffsetReq = uvYOffset !== undefined;
388
+ const uvChangeRequest = xScaleReq || yScaleReq || xRotationReq || yRotationReq || zRotationReq || xOffsetReq || yOffsetReq;
389
+
390
+ if (uvChangeRequest) {
391
+ const workingMaterial = scene.metadata.materials.find(mat => mat.materialId === id) || {};
392
+
393
+ Object.keys(workingMaterial)?.forEach(key => {
394
+ const validMaterialWithTexture = _.isObject(material[key]) && !_.isArray(material[key]) && key.endsWith('Texture');
395
+ const texture = material[key];
396
+ const hasAllKeys = texture && [ 'uAng', 'wAng', 'vAng', 'uOffset', 'vOffset', 'uScale', 'vScale' ]
397
+ .every(key => texture[key] !== undefined);
398
+
399
+ if (validMaterialWithTexture && hasAllKeys) {
400
+ if (xRotationReq) texture.uAng = uvXRotation;
401
+ if (yRotationReq) texture.wAng = uvYRotation;
402
+ if (zRotationReq) texture.vAng = uvZRotation;
403
+
404
+ if (xOffsetReq) texture.uOffset = uvXOffset;
405
+ if (yOffsetReq) texture.vOffset = uvYOffset;
406
+
407
+ if ((xScaleReq || yScaleReq) && uvScaleLock) {
408
+ texture.uScale = uvXScale ?? uvYScale;
409
+ texture.vScale = uvXScale ?? uvYScale;
410
+ return;
411
+ }
412
+
413
+ if (xScaleReq) texture.uScale = uvXScale;
414
+ if (yScaleReq) texture.vScale = uvYScale;
415
+
416
+ if (uvScaleLock !== undefined) newMetaDataEntry('uvScaleLock', uvScaleLock);
417
+ }
418
+ });
419
+ }
420
+
342
421
  newMetaDataEntry('materials', buildMaterialsArray());
343
422
  newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
344
423
  }
@@ -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,
@@ -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: '#004BA6',
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: 1,
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}