18

I'm looking for the way to find rotation matrix between two defined vectors in THREE.js.

For Example

v1 = new THREE.Vector3(1, 1, 1) v2 = new THREE.Vector3(1, 1, -1)

I need this rotation matrix to rotate whole object in next step.

kriskodzi
  • 681
  • 2
  • 10
  • 18

2 Answers2

31

You can define a rotation from two unit-length vectors v1 and v2 like so:

var quaternion = new THREE.Quaternion(); // create one and reuse it

quaternion.setFromUnitVectors( v1, v2 );

In your case, you need to normalize your vectors first.

You can then apply that rotation to an object using the following pattern:

var matrix = new THREE.Matrix4(); // create one and reuse it

matrix.makeRotationFromQuaternion( quaternion );

object.applyMatrix4( matrix );

Alternatively, if you do not require the matrix, you can just apply the quaternion directly:

object.applyQuaternion( quaternion );

three.js r.152

WestLangley
  • 102,557
  • 10
  • 276
  • 276
  • Hi. Thanks, this seems to work. Would be great to have this solution without Quaternion dependency, though. – kriskodzi Aug 11 '14 at 21:08
  • 4
    three.js is quaternion-based. But if you insist, normalize you vectors first and set `axis.cross( v1, v2 ); angle = v1.angleTo( v2 ); matrix.makeRotationAxis( axis, angle ); object.applyMatrix( matrix );` – WestLangley Aug 11 '14 at 22:08
  • Yes, this is exactly what I'm looking for. I think you can add this to your answer, then I will mark it as accepted. – kriskodzi Aug 12 '14 at 21:34
  • 4
    The method I provided in my answer is the most numerically stable, and is the approach I recommend users use. ( As an aside, the second approach has axis-angle dependency -- an intermediary step is required in either case. The axis-angle is not well-defined if the two vectors are parallel.) – WestLangley Aug 12 '14 at 23:02
1

I don use quaternions instead I would do it like this (do not use THREE.js. either):

construct 4x4 transform matrix for first vector V1 (V1,V2 lays on its XY plane and V1 is X axis)

double V1[3],V2[3]; // input
double X[3],Y[3],Z[3],P[3]; // output
double m[16]; // OpenGL like transform matrix
X = V1;
Z = V1 x V2;
Y = X x Z;
X/=|X|;
Y/=|Y|;
Z/=|Z|;
P = (0,0,0);
m[ 0]=X[0];
m[ 1]=X[1];
m[ 2]=X[2];
m[ 3]=0;
m[ 4]=Y[0];
m[ 5]=Y[1];
m[ 6]=Y[2];
m[ 7]=0;
m[ 8]=Z[0];
m[ 9]=Z[1];
m[10]=Z[2];
m[11]=0;
m[12]=P[0];
m[13]=P[1];
m[14]=P[2];
m[15]=1;

now apply rotation transform matrix around Z axis on it

double angle = acos( (V1.v2)/(|V1|.|V2|) )
  • rotate around Z axis by +/- angle
  • the angle sign depends on the Y axis cross product operands order
  • not sure right now from the head but you will see
  • if you set it wrong the V2 will be on opposite side
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hi, thanks for your tip, I'm just testing it. What do you actually mean by _apply rotation transform matrix around Z axis on it_. You want me to apply the matrix to object and then rotate it around Z, so we will have to apply 2 rotations? – kriskodzi Aug 11 '14 at 19:30
  • 1
    @RecRoot m[] contains transformation matrix representing coordinate system of V1. you have to multiply matrix m by rotation matrix (around Z by angle) which rotates coordinate system from V1 to V2. It does not matter if you apply object*m*rotz or M=m*rotz and then obj*M the only difference is when you create M then you have less operations (just once multiply matrix by matrix not for every vertex of object ...) you can google how transformation matrix for rotation around Z looks like (it is basic and I think your framework it has natively in some function) – Spektre Aug 12 '14 at 07:09
  • @RecRoot btw look here: http://stackoverflow.com/a/25216549/2521214 for more info about transform matrix composition. – Spektre Aug 12 '14 at 08:06