0
votes

So, here is a vector, matrix, rotation, quaternion question for the three.js masters!

I have a parent object at position(0,0,275) with direction(0,0,-1), +y up and rotation(0,0,0).

Attached to the parent is a child object with relation:

 rel_position(.5, 0, 0)
 rel_rotation(0, 0, 0)

I also have a target in the scene:

 position(0, 100, 0)

Consider a ship(parent) with pitch, yaw and roll. It has a turret(child) with pitch and yaw. The turret needs to track the target at a given rotational speed (rad/s).

I have spent 5 days trying to get a proper tracking algorithm. The best I can do is remove the matrixAutoUpdate feature on the parent and child updating the matrix manually. Then use the child.matrixWorld to create rotation matrices or quaternions for the current child rotation. Then I can create a secondary Object3D which looks at the target from the child position. I can take the difference between the child and the secondary Object3D and slerp the quaternion on a rad/s basis. However, when I add roll to the parent or the target is rotated outside of octant (+, +, +) the child rotation (or quaternion) calculations crash causing wild rotations.

Any direction on a tracking algorithm for a child Object3D would be immensely appreciated. Your efforts will be cited in my upcoming project.

Thank you for your time!

2

2 Answers

3
votes

So here is the answer! @Stemkoski, thanks for the direction. I took a similar approach for a final solution that came to light yesterday. It is a bit a costly in computational power due to inverting a matrix, but it works well. First, create a new matrix as follows:

var m = new THREE.Matrix4().getInverse(parent.matrix).multiply(target.matrix);  

This rotates the reference frame of the XYZ axis to new coordinates X'Y'Z' based on the rotation of the parent object. The result is an Object3D matrix of the target in the reference frame of X'Y'Z'. Now by creating a new Vector3 from the matrix 'm' we can get a relative position using:

var rel_pos = new THREE.Vector3().getPositionFromMatrix(m, 'XYZ');

Now create a Faux object to look directly at target from the position of the child(turret)

var child_faux = new THREE.Object3D();  //can be created outside the loop
child_faux.position.copy(child.position);   //copy the child local position
child_faux.lookAt(rel_pos);     //look at the target 
child_faux.updateMatrix();     //Update the Matrix4 element for use in a second

Finally, by setting the child_fuax to lookAt an object we have automatically set the child_faux.rotation. We can obtain the relative rotation between the current child.rotation and the child_faux.rotation using the following:

var diff = turret_target.rotation.sub(turret.rotation);

From here we can set an easy algorithm to rotate the turret (+ or -)(x and y) until the diff (x and y) goes to 0.

var trackrate = .2 * delta;
var diff = turret_target.rotation.sub(turret.rotation);
turret.rotation.x += diff.x/Math.abs(diff.x) * trackrate;
turret.rotation.y += diff.y / Math.abs(diff.y) * trackrate;
turret.updateMatrix();

There we have it...A target tracking algorithm for a child object rotated in a parent group! Thanks for reading!

1
votes

Perhaps some combination of the lookAt and worldToLocal methods would work? Since you need to convert the position of the target object into local coordinates for the turret, and then change the rotation of the turret accordingly, how about this:

turret.lookAt(  turret.worldToLocal( target.position.clone() )  )