From 22389ca15e7a86b7723df7af6c4043ee25592ae9 Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Wed, 1 Jan 2025 15:44:16 -0800 Subject: [PATCH 1/9] custom color component stub --- src/components/custom-colors.js | 7 +++++++ src/index.js | 1 + 2 files changed, 8 insertions(+) create mode 100644 src/components/custom-colors.js diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js new file mode 100644 index 000000000..4e1da81d4 --- /dev/null +++ b/src/components/custom-colors.js @@ -0,0 +1,7 @@ +/* global AFRAME */ + +AFRAME.registerComponent('custom-colors', { + schema: { + type: 'string' + } +}); diff --git a/src/index.js b/src/index.js index a217dd5be..fa4d29abb 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ require('./components/svg-extruder.js'); require('./lib/animation-mixer.js'); require('./lib/aframe-gaussian-splatting-component.min.js'); require('./assets.js'); +require('./components/custom-colors.js'); require('./components/notify.js'); require('./components/create-from-json'); require('./components/screentock.js'); From 61a07034751a0afcc1c192da98e93f2f8088100b Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Wed, 1 Jan 2025 15:44:31 -0800 Subject: [PATCH 2/9] Custom color widget on material --- .../components/components/CommonComponents.js | 9 +- .../components/CustomizeColorWidget/index.js | 137 ++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/editor/components/components/CustomizeColorWidget/index.js diff --git a/src/editor/components/components/CommonComponents.js b/src/editor/components/components/CommonComponents.js index eca100e97..597b99573 100644 --- a/src/editor/components/components/CommonComponents.js +++ b/src/editor/components/components/CommonComponents.js @@ -6,6 +6,7 @@ import { getEntityClipboardRepresentation } from '../../lib/entity'; import Events from '../../lib/Events'; import Clipboard from 'clipboard'; import { saveBlob } from '../../lib/utils'; +import CustomizeColorWidget from './CustomizeColorWidget'; export default class CommonComponents extends React.Component { static propTypes = { @@ -46,7 +47,7 @@ export default class CommonComponents extends React.Component { renderCommonAttributes() { const entity = this.props.entity; // return ['position', 'rotation', 'scale', 'visible'] - return ['position', 'rotation', 'scale'].map((componentName) => { + const rows = ['position', 'rotation', 'scale'].map((componentName) => { const schema = AFRAME.components[componentName].schema; var data = entity.object3D[componentName]; if (componentName === 'rotation') { @@ -68,6 +69,12 @@ export default class CommonComponents extends React.Component { /> ); }); + + console.log(this.props.entity); + + rows.push(); + + return rows; } exportToGLTF() { diff --git a/src/editor/components/components/CustomizeColorWidget/index.js b/src/editor/components/components/CustomizeColorWidget/index.js new file mode 100644 index 000000000..1ce3f4594 --- /dev/null +++ b/src/editor/components/components/CustomizeColorWidget/index.js @@ -0,0 +1,137 @@ +import { useMemo, useState } from 'react'; +import { Button } from '../Button'; +import BooleanWidget from '../../widgets/BooleanWidget'; +import ColorWidget from '../../widgets/ColorWidget'; +import SelectWidget from '../../widgets/SelectWidget'; + +export const getMaterials = (object3D) => { + const materials = new Set(); + object3D.traverse((c) => c.material && materials.add(c.material)); + return Array.from(materials); +}; + +const CustomizeColorContent = ({ entity }) => { + const customColorData = entity.getAttribute('custom-colors') ?? ''; + // Convert the string data of `materialName:color;...` to a mapping of color overrides: { [materialName]: color } + const baseColorMapping = useMemo(() => { + if (!customColorData) return {}; + const mapping = {}; + customColorData + .replaceAll(' ', '') + .split(';') + .forEach((entry) => { + // Skip unnamed + if (entry === '') return; + const [mat, color] = entry.split(':'); + mapping[mat] = color; + }); + return mapping; + }, [customColorData]); + const [colorMapping, setColorMapping] = useState(baseColorMapping); + + // Retrieve materials from the entity + const materials = useMemo(() => getMaterials(entity.object3D), [entity]); + const [selectedMaterial, setSelectedMaterial] = useState(); + + const setMaterialColor = (material, color) => { + const newColorMapping = { ...colorMapping, [material]: color }; + setColorMapping(newColorMapping); + + const newColorsString = Object.entries(newColorMapping) + .map(([mat, color]) => `${mat}:${color}`) + .join(';'); + + AFRAME.INSPECTOR.execute('entityupdate', { + entity: entity, + component: 'custom-colors', + value: newColorsString + }); + }; + + const handleToggleOverride = (_, v) => { + if (v) { + setMaterialColor(selectedMaterial, '#FF0000'); + } else { + setMaterialColor(selectedMaterial, undefined); + } + }; + + const handleColorChange = (_, v) => { + setMaterialColor(selectedMaterial, v); + }; + + return ( +
+
+ + { + setSelectedMaterial(v); + }} + options={materials.map((m) => m.name)} + /> +
+ {selectedMaterial && ( + <> +
+ + +
+
+ + +
+ + )} +
+ ); +}; + +const CustomizeColorWrapper = ({ entity }) => { + const [hasCustomColorComponent, setHasCustomColorComponent] = useState( + Boolean(entity.getAttribute('custom-colors')) + ); + + const toggleCustomColors = () => { + if (!hasCustomColorComponent) { + AFRAME.INSPECTOR.execute('componentadd', { + entity, + component: 'custom-colors', + value: '' + }); + setHasCustomColorComponent(true); + return; + } + AFRAME.INSPECTOR.execute('componentremove', { + entity, + component: 'custom-colors' + }); + setHasCustomColorComponent(false); + }; + + return ( +
+
+ + +
+ {hasCustomColorComponent && } +
+ ); +}; + +export default CustomizeColorWrapper; From 9221018630301a46eef24c726bdaab35732fe013 Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Wed, 1 Jan 2025 16:37:10 -0800 Subject: [PATCH 3/9] Add color component and cleanup --- src/components/custom-colors.js | 40 +++++++++++++++++++ .../components/components/CommonComponents.js | 4 +- .../components/CustomizeColorWidget/index.js | 31 +++++++++++--- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js index 4e1da81d4..a1aaa1d69 100644 --- a/src/components/custom-colors.js +++ b/src/components/custom-colors.js @@ -1,7 +1,47 @@ /* global AFRAME */ +import { getMaterials } from '../editor/components/components/CustomizeColorWidget'; + AFRAME.registerComponent('custom-colors', { schema: { type: 'string' + }, + update() { + const materials = getMaterials(this.el.object3D); + const customColorMapping = {}; + this.data + .replaceAll(' ', '') + .split(';') + .forEach((entry) => { + // Skip unnamed + if (entry === '') return; + const [mat, color] = entry.split(':'); + customColorMapping[mat] = color; + }); + + materials.forEach((material) => { + if (customColorMapping[material.name] !== undefined) { + material.color.set(customColorMapping[material.name]); + } else { + // Reset to default, no tint + material.color.set(material.userData.origColor); + } + }); + }, + init() { + if (this.el.getObject3D('mesh')) { + this.update(); + } else { + this.el.addEventListener('model-loaded', () => { + this.update(); + }); + } + }, + remove() { + const materials = getMaterials(this.el.object3D); + materials.forEach((material) => { + // Reset to default, no tint + material.color.set(material.userData.origColor); + }); } }); diff --git a/src/editor/components/components/CommonComponents.js b/src/editor/components/components/CommonComponents.js index 597b99573..047adf935 100644 --- a/src/editor/components/components/CommonComponents.js +++ b/src/editor/components/components/CommonComponents.js @@ -70,9 +70,7 @@ export default class CommonComponents extends React.Component { ); }); - console.log(this.props.entity); - - rows.push(); + rows.push(); return rows; } diff --git a/src/editor/components/components/CustomizeColorWidget/index.js b/src/editor/components/components/CustomizeColorWidget/index.js index 1ce3f4594..67e038820 100644 --- a/src/editor/components/components/CustomizeColorWidget/index.js +++ b/src/editor/components/components/CustomizeColorWidget/index.js @@ -10,7 +10,7 @@ export const getMaterials = (object3D) => { return Array.from(materials); }; -const CustomizeColorContent = ({ entity }) => { +const CustomizeColorContent = ({ materials, entity }) => { const customColorData = entity.getAttribute('custom-colors') ?? ''; // Convert the string data of `materialName:color;...` to a mapping of color overrides: { [materialName]: color } const baseColorMapping = useMemo(() => { @@ -28,13 +28,11 @@ const CustomizeColorContent = ({ entity }) => { return mapping; }, [customColorData]); const [colorMapping, setColorMapping] = useState(baseColorMapping); - - // Retrieve materials from the entity - const materials = useMemo(() => getMaterials(entity.object3D), [entity]); const [selectedMaterial, setSelectedMaterial] = useState(); const setMaterialColor = (material, color) => { const newColorMapping = { ...colorMapping, [material]: color }; + if (color === undefined) delete newColorMapping[material]; setColorMapping(newColorMapping); const newColorsString = Object.entries(newColorMapping) @@ -50,7 +48,7 @@ const CustomizeColorContent = ({ entity }) => { const handleToggleOverride = (_, v) => { if (v) { - setMaterialColor(selectedMaterial, '#FF0000'); + setMaterialColor(selectedMaterial, '#FFFFFF'); } else { setMaterialColor(selectedMaterial, undefined); } @@ -121,6 +119,21 @@ const CustomizeColorWrapper = ({ entity }) => { setHasCustomColorComponent(false); }; + const materials = useMemo(() => { + // Save the original material color values + const materials = getMaterials(entity.object3D); + materials.forEach((material) => { + material.userData.origColor = material.color.clone(); + }); + + return getMaterials(entity.object3D); + }, [entity.object3D]); + + // No materials to customize, don't add the widget + if (materials.length === 0) { + return <>; + } + return (
@@ -129,7 +142,13 @@ const CustomizeColorWrapper = ({ entity }) => { {hasCustomColorComponent ? 'Remove' : 'Add'} Custom Colors
- {hasCustomColorComponent && } + {hasCustomColorComponent && ( + + )}
); }; From 66c86e9909d7a2a5e82a2328a82b59228470a2a2 Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Wed, 1 Jan 2025 17:01:40 -0800 Subject: [PATCH 4/9] Fix material loading timing --- .../components/components/CommonComponents.js | 2 -- .../components/CustomizeColorWidget/index.js | 25 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/editor/components/components/CommonComponents.js b/src/editor/components/components/CommonComponents.js index 047adf935..6454f1d32 100644 --- a/src/editor/components/components/CommonComponents.js +++ b/src/editor/components/components/CommonComponents.js @@ -69,9 +69,7 @@ export default class CommonComponents extends React.Component { /> ); }); - rows.push(); - return rows; } diff --git a/src/editor/components/components/CustomizeColorWidget/index.js b/src/editor/components/components/CustomizeColorWidget/index.js index 67e038820..d375979c7 100644 --- a/src/editor/components/components/CustomizeColorWidget/index.js +++ b/src/editor/components/components/CustomizeColorWidget/index.js @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react'; +import { useMemo, useState, useEffect, useCallback } from 'react'; import { Button } from '../Button'; import BooleanWidget from '../../widgets/BooleanWidget'; import ColorWidget from '../../widgets/ColorWidget'; @@ -119,16 +119,29 @@ const CustomizeColorWrapper = ({ entity }) => { setHasCustomColorComponent(false); }; - const materials = useMemo(() => { + const [materials, setMaterials] = useState([]); + + const updateMaterials = useCallback(() => { // Save the original material color values - const materials = getMaterials(entity.object3D); - materials.forEach((material) => { + const newMaterials = getMaterials(entity.object3D); + newMaterials.forEach((material) => { material.userData.origColor = material.color.clone(); }); - - return getMaterials(entity.object3D); + setMaterials(newMaterials); }, [entity.object3D]); + // We need to dynamically get the materials from the mesh in case the + // model is not loaded when the pane is loaded + useEffect(() => { + if (entity.getObject3D('mesh')) { + updateMaterials(); + } else { + entity.addEventListener('model-loaded', () => { + updateMaterials(); + }); + } + }, [updateMaterials, entity.id, entity]); + // No materials to customize, don't add the widget if (materials.length === 0) { return <>; From cbdabf041fb10c506bab89af1ec08e9a0ee80971 Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Wed, 1 Jan 2025 21:54:10 -0800 Subject: [PATCH 5/9] Exclude intersections etc from custom color --- src/editor/components/components/CommonComponents.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/editor/components/components/CommonComponents.js b/src/editor/components/components/CommonComponents.js index 6454f1d32..42316c47c 100644 --- a/src/editor/components/components/CommonComponents.js +++ b/src/editor/components/components/CommonComponents.js @@ -69,7 +69,11 @@ export default class CommonComponents extends React.Component { /> ); }); - rows.push(); + + // Custom colors are only applicable to entities, not things like intersections or groups. + if (entity.hasAttribute('mixin')) { + rows.push(); + } return rows; } From cb37ee5d1a606a4db9f167c9e1c67f031103517f Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Thu, 2 Jan 2025 18:37:40 -0800 Subject: [PATCH 6/9] use styleparser and update event order; change saving or original color to component --- src/components/custom-colors.js | 47 +++++++++++-------- .../components/CustomizeColorWidget/index.js | 39 +++------------ 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js index a1aaa1d69..b9a236b6e 100644 --- a/src/components/custom-colors.js +++ b/src/components/custom-colors.js @@ -1,47 +1,56 @@ /* global AFRAME */ - import { getMaterials } from '../editor/components/components/CustomizeColorWidget'; +const styleParser = AFRAME.utils.styleParser; AFRAME.registerComponent('custom-colors', { schema: { - type: 'string' + type: 'string', + parse: styleParser.parse, + stringify: styleParser.stringify }, update() { - const materials = getMaterials(this.el.object3D); - const customColorMapping = {}; - this.data - .replaceAll(' ', '') - .split(';') - .forEach((entry) => { - // Skip unnamed - if (entry === '') return; - const [mat, color] = entry.split(':'); - customColorMapping[mat] = color; + // Save the original color values if not done already + if (this.origMaterialMap.size === 0) { + this.el.object3D.traverse((node) => { + if (node.material) { + this.origMaterialMap.set( + node.material.uuid, + node.material.color.clone() + ); + } }); + } + const materials = getMaterials(this.el.object3D); + console.log(this.el, materials); materials.forEach((material) => { - if (customColorMapping[material.name] !== undefined) { - material.color.set(customColorMapping[material.name]); + if (this.data[material.name] !== undefined) { + material.color.set(this.data[material.name]); } else { // Reset to default, no tint - material.color.set(material.userData.origColor); + material.color.set(this.origMaterialMap.get(material.uuid)); } }); }, + updateMaterials() { + this.update(); + }, init() { + this.origMaterialMap = new Map(); + this.updateMaterials = this.updateMaterials.bind(this); if (this.el.getObject3D('mesh')) { this.update(); } else { - this.el.addEventListener('model-loaded', () => { - this.update(); - }); + this.el.addEventListener('model-loaded', this.updateMaterials); } }, remove() { + console.log('component removed'); + this.el.removeEventListener('model-loaded', this.updateMaterials); const materials = getMaterials(this.el.object3D); materials.forEach((material) => { // Reset to default, no tint - material.color.set(material.userData.origColor); + material.color.set(this.origMaterialMap.get(material.uuid)); }); } }); diff --git a/src/editor/components/components/CustomizeColorWidget/index.js b/src/editor/components/components/CustomizeColorWidget/index.js index d375979c7..94abf012d 100644 --- a/src/editor/components/components/CustomizeColorWidget/index.js +++ b/src/editor/components/components/CustomizeColorWidget/index.js @@ -1,4 +1,4 @@ -import { useMemo, useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { Button } from '../Button'; import BooleanWidget from '../../widgets/BooleanWidget'; import ColorWidget from '../../widgets/ColorWidget'; @@ -11,47 +11,24 @@ export const getMaterials = (object3D) => { }; const CustomizeColorContent = ({ materials, entity }) => { - const customColorData = entity.getAttribute('custom-colors') ?? ''; - // Convert the string data of `materialName:color;...` to a mapping of color overrides: { [materialName]: color } - const baseColorMapping = useMemo(() => { - if (!customColorData) return {}; - const mapping = {}; - customColorData - .replaceAll(' ', '') - .split(';') - .forEach((entry) => { - // Skip unnamed - if (entry === '') return; - const [mat, color] = entry.split(':'); - mapping[mat] = color; - }); - return mapping; - }, [customColorData]); - const [colorMapping, setColorMapping] = useState(baseColorMapping); + const [colorMapping, setColorMapping] = useState( + entity.getAttribute('custom-colors') ?? {} + ); const [selectedMaterial, setSelectedMaterial] = useState(); const setMaterialColor = (material, color) => { const newColorMapping = { ...colorMapping, [material]: color }; if (color === undefined) delete newColorMapping[material]; setColorMapping(newColorMapping); - - const newColorsString = Object.entries(newColorMapping) - .map(([mat, color]) => `${mat}:${color}`) - .join(';'); - AFRAME.INSPECTOR.execute('entityupdate', { entity: entity, component: 'custom-colors', - value: newColorsString + value: newColorMapping }); }; const handleToggleOverride = (_, v) => { - if (v) { - setMaterialColor(selectedMaterial, '#FFFFFF'); - } else { - setMaterialColor(selectedMaterial, undefined); - } + setMaterialColor(selectedMaterial, v ? '#ffffff' : undefined); }; const handleColorChange = (_, v) => { @@ -136,9 +113,7 @@ const CustomizeColorWrapper = ({ entity }) => { if (entity.getObject3D('mesh')) { updateMaterials(); } else { - entity.addEventListener('model-loaded', () => { - updateMaterials(); - }); + entity.addEventListener('model-loaded', updateMaterials, { once: true }); } }, [updateMaterials, entity.id, entity]); From b28fe73742abfda6f369b6d8a2f2d70a46579b5b Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Thu, 2 Jan 2025 20:27:33 -0800 Subject: [PATCH 7/9] Fix entity updating when model is changed --- src/components/custom-colors.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js index b9a236b6e..46b2c9542 100644 --- a/src/components/custom-colors.js +++ b/src/components/custom-colors.js @@ -11,8 +11,15 @@ AFRAME.registerComponent('custom-colors', { update() { // Save the original color values if not done already if (this.origMaterialMap.size === 0) { + const materialMap = new Map(); this.el.object3D.traverse((node) => { if (node.material) { + // Duplicate the materials to avoid sharing references across entities + if (!materialMap.has(node.material.uuid)) { + materialMap.set(node.material.uuid, node.material.clone()); + } + node.material = materialMap.get(node.material.uuid); + this.origMaterialMap.set( node.material.uuid, node.material.color.clone() @@ -22,7 +29,6 @@ AFRAME.registerComponent('custom-colors', { } const materials = getMaterials(this.el.object3D); - console.log(this.el, materials); materials.forEach((material) => { if (this.data[material.name] !== undefined) { material.color.set(this.data[material.name]); @@ -35,18 +41,29 @@ AFRAME.registerComponent('custom-colors', { updateMaterials() { this.update(); }, + resetAndUpdateMaterials() { + this.origMaterialMap.clear(); + this.updateMaterials(); + }, init() { this.origMaterialMap = new Map(); - this.updateMaterials = this.updateMaterials.bind(this); + this.resetAndUpdateMaterials = this.resetAndUpdateMaterials.bind(this); + + // Models that are components of larger models trigger this event instead of model-loaded. + // This also will fire when the selected model is changed. + this.el.addEventListener('object3dset', this.resetAndUpdateMaterials); + if (this.el.getObject3D('mesh')) { this.update(); } else { - this.el.addEventListener('model-loaded', this.updateMaterials); + this.updateMaterials = this.updateMaterials.bind(this); + this.el.addEventListener('model-loaded', this.updateMaterials, { + once: true + }); } }, remove() { - console.log('component removed'); - this.el.removeEventListener('model-loaded', this.updateMaterials); + this.el.removeEventListener('object3dset', this.resetAndUpdateMaterials); const materials = getMaterials(this.el.object3D); materials.forEach((material) => { // Reset to default, no tint From 6a4f778143a4a8f49e3bb34b6e281842e6cc5fbd Mon Sep 17 00:00:00 2001 From: Edward Wei Date: Fri, 3 Jan 2025 00:41:06 -0800 Subject: [PATCH 8/9] Cleanup unused --- src/components/custom-colors.js | 28 +++++++++---------- .../components/CustomizeColorWidget/index.js | 11 +++++--- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js index 46b2c9542..bfcb3e64e 100644 --- a/src/components/custom-colors.js +++ b/src/components/custom-colors.js @@ -9,32 +9,31 @@ AFRAME.registerComponent('custom-colors', { stringify: styleParser.stringify }, update() { - // Save the original color values if not done already - if (this.origMaterialMap.size === 0) { + // If the mesh has not been traversed, duplicate the materials so that we can avoid + // accidental shared references, i.e. changing one material changes materials across multiple entities + if (!this.hasOrigColor) { const materialMap = new Map(); this.el.object3D.traverse((node) => { if (node.material) { - // Duplicate the materials to avoid sharing references across entities if (!materialMap.has(node.material.uuid)) { materialMap.set(node.material.uuid, node.material.clone()); } node.material = materialMap.get(node.material.uuid); - - this.origMaterialMap.set( - node.material.uuid, - node.material.color.clone() - ); } }); } const materials = getMaterials(this.el.object3D); materials.forEach((material) => { + if (!material.userData.origColor) { + material.userData.origColor = material.color.clone(); + this.hasOrigColor = true; + } if (this.data[material.name] !== undefined) { material.color.set(this.data[material.name]); } else { - // Reset to default, no tint - material.color.set(this.origMaterialMap.get(material.uuid)); + // Reset to original + material.color.set(material.userData.origColor); } }); }, @@ -42,17 +41,16 @@ AFRAME.registerComponent('custom-colors', { this.update(); }, resetAndUpdateMaterials() { - this.origMaterialMap.clear(); + this.hasOrigColor = false; this.updateMaterials(); }, init() { - this.origMaterialMap = new Map(); + this.hasOrigColor = false; this.resetAndUpdateMaterials = this.resetAndUpdateMaterials.bind(this); // Models that are components of larger models trigger this event instead of model-loaded. // This also will fire when the selected model is changed. this.el.addEventListener('object3dset', this.resetAndUpdateMaterials); - if (this.el.getObject3D('mesh')) { this.update(); } else { @@ -66,8 +64,8 @@ AFRAME.registerComponent('custom-colors', { this.el.removeEventListener('object3dset', this.resetAndUpdateMaterials); const materials = getMaterials(this.el.object3D); materials.forEach((material) => { - // Reset to default, no tint - material.color.set(this.origMaterialMap.get(material.uuid)); + // Reset to original + material.color.set(material.userData.origColor); }); } }); diff --git a/src/editor/components/components/CustomizeColorWidget/index.js b/src/editor/components/components/CustomizeColorWidget/index.js index 94abf012d..74fffcd19 100644 --- a/src/editor/components/components/CustomizeColorWidget/index.js +++ b/src/editor/components/components/CustomizeColorWidget/index.js @@ -101,20 +101,23 @@ const CustomizeColorWrapper = ({ entity }) => { const updateMaterials = useCallback(() => { // Save the original material color values const newMaterials = getMaterials(entity.object3D); - newMaterials.forEach((material) => { - material.userData.origColor = material.color.clone(); - }); setMaterials(newMaterials); }, [entity.object3D]); // We need to dynamically get the materials from the mesh in case the // model is not loaded when the pane is loaded useEffect(() => { + entity.addEventListener('object3dset', updateMaterials); if (entity.getObject3D('mesh')) { updateMaterials(); } else { - entity.addEventListener('model-loaded', updateMaterials, { once: true }); + entity.addEventListener('model-loaded', updateMaterials, { + once: true + }); } + return () => { + entity.removeEventListener('object3dset', updateMaterials); + }; }, [updateMaterials, entity.id, entity]); // No materials to customize, don't add the widget From bf3c468841759a215bb6e42dec9784ca9ad38779 Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Sun, 19 Jan 2025 20:55:37 -0800 Subject: [PATCH 9/9] remove unneeded check from vincent's feedback --- src/components/custom-colors.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/custom-colors.js b/src/components/custom-colors.js index bfcb3e64e..f053a4424 100644 --- a/src/components/custom-colors.js +++ b/src/components/custom-colors.js @@ -53,11 +53,6 @@ AFRAME.registerComponent('custom-colors', { this.el.addEventListener('object3dset', this.resetAndUpdateMaterials); if (this.el.getObject3D('mesh')) { this.update(); - } else { - this.updateMaterials = this.updateMaterials.bind(this); - this.el.addEventListener('model-loaded', this.updateMaterials, { - once: true - }); } }, remove() {