How to calculate quaternion from world position of 3 points on a plane

2022-11-22_111336

As in the picture, within the parent plane there are 3 points, red, green and blue. The purple and gold represents two objects between these 3 points. Assume I’ve observed the world positions of the 3 points before and after the rotation of the plane. How can I calculate the quaternion/euler angles based on the positions of the 3 points for the plane? Further more, assume there are only the purple and gold objects and the 3 points. How to calculate the translation and quaternions for the two objects based on the positions of the 3 points?

Let’s say you have matrix Ai like:

⌈ red xi green xi blue xi 0 ⌉
  red yi green yi blue yi 0
  red zi green zi blue zi 0
⌊      0        0       0 1 ⌋

Now you want matrix B that maps from 1st set of coords to 2nd set:
A2 = B * A1
This is now a very complex math problem that requires advanced skills to arrive at the solution:
B = A2 * inverse of A1
Once you have B, you can invoke 3js built-in magic to retrieve the quaternion, translation and scale.

Forgive me if I miss understood, what exactly do you mean by “advanced skills”. Based on your reply, looks like I only need to calculate the inverse of A1. And after I’ve got B, I can transfer the matrix to quaternions/euler, translation.

Actually 3js does that for you too.

All right, I’ll try to write the code follow your instruction, is there any mathmetical explanation behind this Matrix?

⌈ red xi green xi blue xi 0 ⌉
  red yi green yi blue yi 0
  red zi green zi blue zi 0
⌊      0        0       0 1 ⌋

Yes. Unfortunately the explanation is too long to write down here, but the most of it boils down to Quaternion’s setFromRotationMatrix method taking Matrix4 as an argument, which means you have to take your actual 3x3 matrices and pad them with random 0s and 1s to make it work.

It doesn’t work. I don’t know where I did wrong. I build A1 and A2 by .makeBasis(v1, v2, v3). v1, v2, v3 are the coordinates of the 3 points before and after the rotation. And calculated A1.invert(), and B = A2.multiply(A1.invert()). Finally quaternion Q.setFromRotationMatrix(B). It gives me a rotation that isn’t the same as the target.

there is .premultiply, maybe try that

If you have three points, you can easily determine three basis vectors using the cross product.
From the base you calculate the quaternion.

See also from the Collection of examples from discourse.threejs.org
https://hofk.de/main/discourse.threejs/2021/CarRacing/FlightRouteQuaternion.html

Maybe you can get further with this?

It worked, there was a silly mistake from my side, I updated the jsfiddle Plane rotation - JSFiddle - Code Playground

And piece of my code

function matrixFromPoints(a, b, c) {
  const axis1 = new THREE.Vector3(a.x - b.x, a.y - b.y, a.z-b.z).normalize()
  const axis2 = new THREE.Vector3(c.x - b.x, c.y - b.y, c.z-b.z).normalize()

  const axis3 = new THREE.Vector3().crossVectors(axis1, axis2).normalize();

  return new THREE.Matrix4().makeBasis(axis1, axis2, axis3);
}

function applyquaternionFromPositions() {
  const matrix1 = matrixFromPoints(a1, b1, c1);
  const matrix1i = matrix1.invert();

  const matrix2 = matrixFromPoints(a2, b2, c2);

  const B = matrix2.multiply(matrix1i);

  const Q = new THREE.Quaternion();
  
  Q.setFromRotationMatrix(B);
  
  p1.applyQuaternion(Q);
  
  renderer.render(scene, camera);
}

@hofk Thanks for the info, if I understand it correctly, I still need to transfer the original Quaternion to Matrix in order to find the invert of it, even though I can get the original Quaternion by setFromBasis. Is that correct?

I think no.

My goal was just to eliminate the many operations with matrices and to limit myself to the quaternion for the orientation in space and to .position.set( ) for the position.

view source of FlightRouteQuaternion


THREE.Quaternion.prototype.setFromBasis = function( e1, e2, e3 ) { ...
------

// points and corresponding basis in arrrays
const points = curve.getPoints( ls );
...
// bases in arrays, not in a matrix
 t = .. ; // tangents array
 n = .. ; // normals array
 b = .. ; // binormals array

----------

// set orientation and position in each case
shuttle.quaternion.setFromBasis( t[ iShuttle ], b[ iShuttle ], n[ iShuttle ] );            //orientation in space
shuttle.position.set( points[ iShuttle ].x , points[ iShuttle ].y, points[ iShuttle ].z ); // position

iShuttle ++; // next point

But maybe I’m missing a different requirement in your problem?

Try to see if you can get further with the shuttle approach.

Welp, this is basically a matrix without creating Matrix4 instance. But yes, with your approach OP could probably do 2 quaternions and then calculate the rotation between them with .conjugate() + .multiply()

1 Like

Of course, extracting the components of the basis vectors into constant values is equivalent to a matrix. But this also within the function. One saves the creation of the matrix in the application code. With the quaternion it seems clearer to myself.

For ‘historical’ reasons I also like to work component-wise with vectors and matrices.
There are hardly any in my
Addon. Produces almost infinite many time-varying geometries with functions
THREEf.js/THREEf.js at cc28a353fe8e3a6e98956dc299d1762b178ad452 · hofk/THREEf.js · GitHub

A little more in other addons.