How to align two XYZ coordinates

Just lately I am engaged on handtracking ARs. To align 3D fashions to arms, I needed to match coordinates of 3D mannequin objects to a coordinate of a hand to make results like 3D fashions on a hand and so on.

It’s a bit difficult to align them, so let me clarify methods to do it right here.

For example we now have a goal coordinate XYZ (e.g. hand) and a coordinate xyz (e.g. 3D mannequin) to align. We already know the vectors of XYZ and xyz. X/Y/Z are orthogonal one another and normalized (the size is 1) and x/y/z are additionally. The purpose is to align the xyz vectors to XYZ.

Aligning the origin positions are usually not defined on this article as a result of we will do it simply by setting the XYZ origin place to xyz origin place.

Within the following steps, I align z/Z and x/X. Nonetheless, the order of operation doesn’t matter. Chances are you’ll align y/Y first and z/Z subsequent.

First, let’s align the z axis.

Image description

Calculate the cross vector z × Z and θ with the dot product and Arccosine which is used to rotate the coordinate across the cross vector. To attain the rotation, we will use a quaternion. Calculating quaternion by ourselves is a bit difficult and often 3D CG engine has built-in operate to calculate it from the axis to rotate round and the angle. When you actually need to implement by your self, it’s possible you’ll refer this article.

Image description

That is an instance pseudocode. Your programming language / 3D CG engine (e.g. Three.js / Unity / Unreal Engine) ought to have cross / dot / normalize / acos / fromAxisAngle.

Vec3 z = ... // Your z
Vec3 Z = ... // Your Z
Vec3 axisZ = normalize(cross(z, Z)); // Normalized cross vector.
float angleZ = acos(dot(z, Z)); // The angle between z and Z --> theta within the picture.
Quaternion qz = fromAxisAngle(axisZ, angleZ); // Later we are going to make different quaternions so let's title it qz.
Enter fullscreen mode

Exit fullscreen mode

Now we have got the quaternion qz to align z to Z axis.

By making use of the quaternion qz to your coordinate, it’s best to have x’/y’/z’ like the next picture.

Image description

Aligning x/X axes is mainly the identical course of as we did for z/Z. Nonetheless, please don’t forget apply the quaternion qz to the x vector. Let’s title the rotated x vector as x'.

Image description

Pseudocode ought to be like this. applyQuaternion is a operate to use a quaternion to a vector. Your programming language / 3D engine ought to have an equal.

Vec3 rotatedX = applyQuaternion(x, qz); // x'
Vec3 X = ... // Your X
Vec3 axisX = normalize(cross(rotatedX, X));
float angleX = acos(dot(rotatedX, X)); // The angle between x' and X --> phi within the picture
Quaternion qx = fromAxisAngle(axisX, angleX);
Enter fullscreen mode

Exit fullscreen mode

We have got the following quaternion qx.

Now we now have qz and qx. By combining the quaternions, we can have the ultimate quaternion we will notice our coordinate alignment.

multiplyQuaternions is a operate to mix two quaternions into one. Your programming language / 3D engine ought to have an equal. Please watch out that the order of qz and qx is vital.

Quaternion q = mltiplyQuaternions(qz, qx);
Enter fullscreen mode

Exit fullscreen mode

By making use of the quaternion q to x/y/z respectively, you will get vectors similar to X/Y/Z.

Image description

I confirmed pseudo code within the above. I additionally offer you guys an instance in Three.js.

// Your coordinates.
// x/y/z are vectors that will likely be aligned FROM.
const x = new Vector3(...);
const y = new Vector3(...);
const z = new Vector3(...); // <-- You don't want this really.

// X/Y/Z are vectors that will likely be aligned TO.
const X = new Vector3(...);
const Y = new Vector3(...);
const Z = new Vector3(...); // <-- You don't want this really.


const axisZ = z.clone().cross(Z).normalize();
const angleZ = Math.acos(z.dot(Z));
const qz = new Quaternion().setFromAxisAngle(axisZ, angleZ);

const rotatedX = x.clone().applyQuaternion(qz);
const axisX = rotatedX.clone().cross(X).normalize();
const angleX = Math.acos(rotatedX.dot(X));
const qx = new Quaternion().setFromAxisAngle(axisX, angleX);

// Remaining quaternion
const q = new Quaternion().multiplyQuaternions(qz, qx);

// You need to use q like this.
yourModel.rotation.setFromQuaternion(q)
Enter fullscreen mode

Exit fullscreen mode

Add a Comment

Your email address will not be published. Required fields are marked *