Introduction
So I have this really large model (cant share) which has a tree structure and lots of instance but also multi-materials and since I import from GLTF I the multi-materials end up as separate meshes and I don’t like that.
Idea
- I take all meshes
- Find the sources that are primitive meshes
- For each source I merge the all meshes of its parent (don’t dispose)
- For each instance related to the source create a new Instance based on the merged version
- I position it accordingly to the last old instance’s position
- And finally I dispose of the old primitive meshes
The problem
1 through 4 EASY …6 EASSY
5…
At this point I have no clue how to approach it differently so I will just list all the problems:
- Instances usually don’t have a parent, except mine do.
- This parent for some reason has a transform position of (e.g. (1948498432, 91269192, -1519829376))
- I am using a primitive mesh as a position reference so what I really want is to position the new instance on it’s parent’s place (the new instance is pretty is the primitive’s parent but all of it’s meshes merged)
- I want the new instance to have the parent of the parent as its parent
- No matter what I do the new instances always seem to:
– Have the exact same position as the source mesh
– Dissapear (a bounding box of 0)
– Go millions in every direction
– Be at least slightly off
– At least some of them are slightly off
– All of them stacking in a seemingly unrelated place
Here is the code that works
node.getChildMeshes().forEach(mesh => {
if(mesh instanceof Mesh && (mesh.id.includes("primitive0") || mesh.id.includes("primitive 0"))){
//merge
let newMesh = Mesh.MergeMeshes(
mesh.parent.getChildMeshes(),
false, //dispose source
true, //32 bits?
undefined,
false,
true
)
if(mesh.instances.length > 0){
//create instances
mesh.instances.forEach(instance => {
let newParent = instance.parent.parent;
let newInstance = newMesh.createInstance(instance.parent.id + "instance");
//position newInstance where instance is while newParent is the parent of newInstance
})
}
positionMergedMesh(newMesh,mesh.parent)
mesh.parent.getChildMeshes().forEach(primitive => {
primitive.dispose();
})
}
})
For the merged mesh positioning I used GPT generated code which I am afraid to touch
function positionMergedMesh(newMesh,source){
if (newMesh.isWorldMatrixFrozen) {
newMesh.unfreezeWorldMatrix();
}
newMesh.parent=null;
newMesh.computeWorldMatrix(true);
newMesh.refreshBoundingInfo();
//
newMesh.rotationQuaternion = source.rotationQuaternion ? source.rotationQuaternion.clone() : null;
newMesh.rotation.copyFrom(source.rotation);
newMesh.scaling.copyFrom(source.scaling);
//Step 1: Save world transform
const worldMatrix = newMesh.getWorldMatrix().clone();
// Step 2: Set new parent
newMesh.setParent(source.parent);
// 3. Decompose world matrix into global transform
const worldPosition = new Vector3();
const worldRotation = new Quaternion();
const worldScaling = new Vector3();
worldMatrix.decompose(worldScaling, worldRotation, worldPosition);
// 4. Compute the inverse of the new parent's world matrix
const parentWorldMatrix = source.parent.getWorldMatrix().clone();
const invParentWorldMatrix = Matrix.Invert(parentWorldMatrix);
// 5. Apply the inverse transform to get local transform
const localMatrix = worldMatrix.multiply(invParentWorldMatrix);
const localPosition = new Vector3();
const localRotation = new Quaternion();
const localScaling = new Vector3();
localMatrix.decompose(localScaling, localRotation, localPosition);
// 6. Assign local transform
newMesh.position = localPosition;
newMesh.rotationQuaternion = localRotation;
newMesh.scaling = localScaling;
}
Why bother?
- Still uses instances so no performance lost
- Less meshes less draw calls performance up
- Less clutter when I want to show the tree structure
- Less process time when I operate with the meshes