Search code examples
rotationthree.jsrotational-matricesquaternions

Clone rotation from child and assign it to another child of a different parent in THREE.JS


I have a parent Object containing a child Object

var parent1 = new THREE.Object3D();
parent1.rotation.set(1,2,3);
scene.add(parent1);

var child1= new THREE.Object3D();
child1.rotation.set(0.5,0.1,0.3);
parent.add(child1);

and another parent containing another child.

var parent2= new THREE.Object3D();
scene.add(parent2);

var child2= new THREE.Object3D();
childC2.rotation.set(3,1.15,2);
parent.add(child2);

Now I want to give child2 the same rotation as child1 by rotating it's parent2.

As mentioned here, I can get the world-rotation from my original child1 like this:

var quaternion = new THREE.Quaternion();
child1.matrixWorld.decompose( new THREE.Vector3(), quaternion, new THREE.Vector3() );

and apply it to my parent2 like this:

parent2.quaternion.copy( quaternion );

Now parent2 has the same rotation like the original child1, but I want it's child child2 to have have the same rotation like child1 (only by modifing parent2)

I think this can be done by getting the difference of the world-rotation from parent2 and child2 and substracting this from the world-rotation of child1, to correct the offset generated by the rotation of child2. But my knlowledge of quaternions and matrices is to bad to get it working.

Check out this fiddle, to understand my problem. enter image description here Thanks a lot.

UPDATE

I tried the approach of WestLangley. If my Objects are only rotated around x-axis it works like this (see fiddle)

//calculate the relative rotation of child2
THREE.SceneUtils.detach( child2, parent2, scene );
var rotX=parent2.rotation.x-child2.rotation.x;
var rotY=parent2.rotation.y-child2.rotation.y;
var rotZ=parent2.rotation.z-child2.rotation.z;
THREE.SceneUtils.attach( child2, scene, parent2 );

//combine the relative rotation of child2 and the 'world' rotation of child1
THREE.SceneUtils.detach( child1, parent1, scene );
rotX+=child1.rotation.x;
rotY+=child1.rotation.y;
rotZ+=child1.rotation.z;
THREE.SceneUtils.attach( child1, scene, parent1 );
parent2.rotation.set(rotX,rotY,rotZ);//assign it to parent2

If my Objects are rotated around x,y,z this is NOT working anymore (fiddle). Is this a problem with gimbal lock? Do I need to do the calculation with quaternions instead of Euler Objects?


Solution

  • So you want to rotate a parent object so that the parent's child has a particular orientation, and you want that particular orientation to match the orientation of a child object of a different parent. Whew!

    Here is one way to do that:

    // detach the children from their parents and add them to the scene
    THREE.SceneUtils.detach( child2, parent2, scene );
    THREE.SceneUtils.detach( child1, parent1, scene );
    
    // here is the tricky part: add the second parent as a child of its former child
    THREE.SceneUtils.attach( parent2, scene, child2 );
    
    // copy the first child's rotation, and make sure the matrix is updated   
    child2.rotation.copy( child1.rotation );
    child2.updateMatrixWorld( true );
    
    // detach the parent from the child and add it to the scene
    THREE.SceneUtils.detach( parent2, child2, scene );
    
    // put the children back where the were before   
    THREE.SceneUtils.attach( child2, scene, parent2 );
    THREE.SceneUtils.attach( child1, scene, parent1 );
    

    Here is a fiddle: http://jsfiddle.net/715v2hr1/

    three.js r.68