I can remove the old mesh, and add a new Mesh using the new geometry. Isn’t this just as costly (or more) as the old setGeometry/setMaterial methods that there were before?
TLDR: Before you waste time reading further, it is easy to change the geometry or material of a Mesh (@mrdoob please confirm) :
// clean up the old geometry if you won't use it anymore
mesh.geometry.dispose()
mesh.geometry = new SomeGeometry(...)
// clean up the old material if you won't use it anymore
mesh.material.dispose()
mesh.material = new MeshSomeMaterial(...)
I thought it would be as easy as mesh.geometry = new SomeGeometry(...) or mesh.material = new MeshSomeMaterial(...).
I’m not sure if I did it right, but this is how a class of mine sets geometry:
// this class does surgery on a tree, replacing a Mesh object with another Mesh object:
// element is just an object that contains THREE stuff
setGeometry(element, geometry) {
console.log(' ###### GeometryBehavior setGeometry ')
element.geometry = geometry
const parent = element.threeObject3d.parent
const children = [...element.threeObject3d.children]
// remove the old Mesh
if (children.length) element.threeObject3d.remove(...children)
if (parent) parent.remove(element.threeObject3d)
// add the new Mesh
element.threeObject3d = new Mesh( geometry, element.material )
if (parent) parent.add(element.threeObject3d)
if (children.length) element.threeObject3d.add(...children)
}
This seems wasteful (both CPU and Memory). Have I missed the easier way to do it (from the outside, not monkey patching instance properties, only using public APIs)?
Hmmm, maybe doing it that way is leaky? Because I’m not calling a dispose method. This is a bit too complicated (or maybe I’m doing something wrong or missing something small, I should make a small example).
Alright, does this seem right, in order not to leak memory?
// we have to perform surgery on the scene ourselves? :(
// element is just an object that contains THREE stuff
setGeometry(element, newGeometry) {
console.log(' ###### GeometryBehavior setGeometry ')
const parent = element.threeObject3d.parent
const children = [...element.threeObject3d.children]
// remove the old mesh and geometry
if (children.length) element.threeObject3d.remove(...children)
if (parent) parent.remove(element.threeObject3d)
element.geometry.dispose()
// add the new mesh and geometry
element.geometry = newGeometry
element.threeObject3d = new Mesh( newGeometry, element.material )
if (parent) parent.add(element.threeObject3d)
if (children.length) element.threeObject3d.add(...children)
}
// we have to perform surgery on the scene ourselves? :(
// element is just an object that contains THREE stuff
setMaterial(element, newMaterial) {
console.log(' ###### MaterialBehavior setMaterial ')
const parent = element.threeObject3d.parent
const children = [...element.threeObject3d.children]
// remove the old mesh and material
if (children.length) element.threeObject3d.remove(...children)
if (parent) parent.remove(element.threeObject3d)
element.material.dispose()
// add the new mesh and material
element.material = newMaterial
element.threeObject3d = new Mesh( element.geometry, newMaterial )
if (parent) parent.add(element.threeObject3d)
if (children.length) element.threeObject3d.add(...children)
}
So, apparently I missed something very simple, and after complicating my code with the “surgery” then converting back to simple, it just works. hehe. SOLVED
This tells me I’m going to have problems animating the size of a handful of geometries this way.
My goal is to animate the size of any geometry in the scene graph without affecting children (meshes having children is useful). As a placeholder implementation for now I’ll create a new geometry for each new size, then I’ll revisit this later once I have the functionality I want.