Regarding instancedMesh translation issue [Solved]

Apologies for not posting a simple short code that demonstrates the issue as its part of a commercial project.

I am modeling a zipper with a SplineCurve and zipper elements on each side of spline. It works great with meshes but I realized using so many Meshes would invoke a lot of draw calls. So now i am moving to InstancedMesh but then i am confronted with a big issue. With mesh, I could easily use translateY to translate each mesh on the local Y axis and it produced the correct output as shown below.

With instancedMesh since i do not have translateY function (there is one but its to move all instances) for individual instance, i had to do something like this

element_instance.getMatrixAt(index, T);			

let position = new THREE.Vector3();
position.setFromMatrixPosition( T ); // extract position form transformationmatrix

position.y += delta;

T.setPosition( position ); // write new positon back
element_instance.setMatrixAt(index, T);
element_instance.instanceMatrix.needsUpdate = true;

but this code moves the instances relative to world Y axis instead of the local Y axis as shown below.

Can anyone share some insights as to why I dont get the same output as using translateY for mesh? Also please do share some good reference on this.

They called me a mad man :smiling_face_with_tear:

  1. To save yourself some trouble - consider using arithmetics of the same types. Ie. when you add numbers - add numbers. When you add vectors - add vectors of the same length (even if only one component would have value and rest would be 0.) It’s not crucial, but makes life easier when working with nested vectors.

  2. What you need to do is create a delta vector and transform it into the object-space of your object, before applying it as a transform. That way it’ll use local XYZ axes (similarly to what translate methods do) instead of world-space XYZ. Ex.:

const delta = Vector3(0.0, 2.0, 0.0); // NOTE Vectors are in world-space by default

myInstancedMesh.worldToLocal(delta); // NOTE This applies object transform to the vector, making it object-space

// NOTE Your code to read instance matrix and position here […]

instancePosition.add(delta);
2 Likes

Thanks for a prompt response. Ok I updated the code as you suggested.

element_instance.getMatrixAt(index, T);			

let position = new THREE.Vector3();
let delta = new THREE.Vector3(0,2,0);
position.setFromMatrixPosition( T ); // extract position form transformationmatrix

console.log(delta);
delta = element_instance.worldToLocal(delta);
console.log(delta);
console.log("==================");

position.add(delta);

T.setPosition( position ); // write new positon back
element_instance.setMatrixAt(index, T);
element_instance.instanceMatrix.needsUpdate = true;

But it still produces the same output. I logged the value of delta before and after worldToLocal and its the same which means that its not doing anything is there any function that is required to be called?

Ok I managed to solve the issue. I get the exact same output as with cloned meshes but now using instancing.

The call to worldToLocal works only when there is a parent mesh to which the instances are attached. For me this wasnt the case therefore, the worldToLocal was not doing anything. So then I tried to understand what was going on by converting all my translateY calls to position.set calls in my noninstanced code to manually understand what is needed to be done. So the crux is this (and this is when you do not have any parent attached to the instances).

element_instance.getMatrixAt(index, T);			
Trot.extractRotation(T); //get the rotation part of the transform bcos 
                                      //we will use that to transform our delta vector

let position = new THREE.Vector3();
position.setFromMatrixPosition( T ); // extract position form transformationmatrix

let deltaVec = new THREE.Vector4(0,2,0,0); //its imp since default applyMatrix4 assumes 1 in 4th comp
deltaVec.applyMatrix4(Trot);
let delta = new THREE.Vector3(deltaVec.x,deltaVec.y,deltaVec.z);

//modify position
position.add(delta);

T.setPosition( position ); // write new positon back
element_instance.setMatrixAt(index, T);
element_instance.instanceMatrix.needsUpdate = true;

It works and i get the exact same output. Thanks @mjurczyk for your comments that really helped me understand what was going on and what was required to be done.