Rotating PMatrix3D around axis

I wanted to make the black line to spin on a plane formed by 2 vectors (a2, b2) (and the origin). I am trying to rotate a matrix around the cross product btw a2 and b2 (green line) using the rotate (angle, v0, v1, v2) method, which I lack of some understanding.

Vector b2 (described as a blue line) initializes as (0,1,0) so things seem to be right. Until you press “space” so values get randomized. The black line spins out of what I expected it to be its axis ( green line ). Alternatively, holding x, y or z while moving the mouse will change values on a2. [edited] You can see axis angle changes and orbiting the camera its possible to see black line successfully passes over blue and red lines. Problem is just when changing values of b2.

The code below is a little long. But I would like to understand what I am missing.

[edited the code normalizing some vectors I had forgot]

/*
  space to randomize blue vector
  hold x, y or z to move red vector
*/

import peasy.*;

float i = 0;
PeasyCam cam;
PMatrix3D mat = new PMatrix3D();

PVector a2 = new PVector(0.4, 1, 0).normalize();
PVector b2 = new PVector(0,1,0).normalize();


PVector axis;

void setup() {
  size(300, 300, P3D);
  cam = new PeasyCam(this, 200);
}

void keyPressed(){
  if(key ==' ')  {
    b2 = PVector.random3D();
    b2.normalize();
  }
}

void draw() {
  background(100);
  if (keyPressed) moveVector();
  strokeWeight(2);
  stroke(#ff0000);
  drawVector(a2);

  stroke(#0000ff);
  drawVector(b2);

  stroke(#00ff00);
  axis = b2.cross(a2);
  axis.normalize();  //b2.copy().cross(a2.copy()).normalize();
  println(axis);
  drawVector(axis);

  
  pushMatrix();
  applyMatrix(updateMat());
  fill(-1, 100);
  box(20);
  stroke(0, 100);
  strokeWeight(4);
  line(0, 0, 0, 50);
  popMatrix();
}

PMatrix3D updateMat() {
  float angle = PVector.angleBetween(a2, b2); //to replace testing
  //reseting rotation before applying new aim
  mat.m00 = 1;
  mat.m01 = 0;
  mat.m02 = 0;
  mat.m10 = 0;
  mat.m11 = 1;
  mat.m12 = 0;
  mat.m20 = 0;
  mat.m21 = 0;
  mat.m22 = 1;
  float testing = radians( (frameCount) %360);
  mat.rotate( testing , axis.x, axis.y, axis.z ); 
  return mat;
}

void drawVector( PVector v ) {
  float scale = 50;
  PVector n = v.copy().mult(scale);
  beginShape(LINES);
  vertex(0, 0, 0);
  vertex( n.x, n.y, n.z );
  endShape();
}

void moveVector() {
  if (key == 'x') a2.x = map(mouseX, 0, width, -1f, 1f);
  if (key == 'y') a2.y = map(mouseX, 0, width, -1f, 1f);
  if (key == 'z') a2.z = map(mouseX, 0, width, -1f, 1f);
  a2.normalize();
}
1 Like

Can you tell us more about the 3 color vectors? You said b2 is blue, green is the axis of rotation, then red would be a2? what is the relationship between a2 and b2? Are they randomly oriented every time you pressed the spc bar? I can see they share the same origin and they have the same magnitude.
The axis of rotation (green line) would be the cross product between a2 and b2 (blue and red). Is that correct?

Kf

Thats correct. Currently I can alter the values on vector a2, and its possible to see the green line (cross product) changing the axis of matrix rotation so the black line (and a box) spins while passing thought both vectors a2(red) and b2(blue).

I observe however that that is true only when b2 == 0,1,0.
if I change b2 (space key press randomizes only b2), although the cross product (green line) is visually pointing the right direction, it seems I can’t plug the cross product on the PMatrix3D rotate method without some other calculation I am not aware of.


in this picture: the box and black line spins around the green axis, cross product between blue and red lines. (it is true that the box does not correctly aligns to green line. I might need to do something else here too)
Goal is to orient them (blue, red lines) randomly, having the matrix spinning correctly around their cross product axis.

1 Like

[SOLVED] Adapting a PMatrix3D “lookAt” solution from this very interesting source of information:

Code for reference:

/*
  space to randomize blue vector
 hold x, y or z to move red vector
 */

import peasy.*;

float i = 0;
PeasyCam cam;
PMatrix3D mat = new PMatrix3D();

PVector a2 = new PVector(0.4, 1, 0).normalize();
PVector b2 = new PVector(0, 1, 0).normalize();
PVector axis;

void setup() {
  size(300, 300, P3D);
  cam = new PeasyCam(this, 200);
}

void keyPressed() {
  if (key ==' ') {
    b2 = PVector.random3D();
    b2.normalize();
  }
}

void draw() {
  background(100);
  if (keyPressed) moveVector();
  strokeWeight(2);
  stroke(#ff0000);
  drawVector(a2);

  stroke(#0000ff);
  drawVector(b2);

  stroke(#00ff00);
  axis = b2.cross(a2);
  axis.normalize();
  drawVector(axis);

  pushMatrix();
  applyMatrix(updateMat());
  fill(-1, 100);
  box(20);
  stroke(0, 100);
  strokeWeight(4);
  rotateX((frameCount/10f) %360);
  line(0, 0, 0, 50);
  popMatrix();
}

PMatrix3D updateMat() {
  lookAt(a2, b2, mat);
  return mat;
}

void drawVector( PVector v ) {
  float scale = 50;
  PVector n = v.copy().mult(scale);
  beginShape(LINES);
  vertex(0, 0, 0);
  vertex( n.x, n.y, n.z );
  endShape();
}

void moveVector() {
  if (key == 'x') a2.x = map(mouseX, 0, width, -1f, 1f);
  if (key == 'y') a2.y = map(mouseX, 0, width, -1f, 1f);
  if (key == 'z') a2.z = map(mouseX, 0, width, -1f, 1f);
  a2.normalize();
}


PMatrix3D lookAt(PVector target, PVector up, PMatrix3D out) {
  PVector k = PVector.sub(target, new PVector());
  float m = k.magSq();
  if (m < EPSILON) {
    return out;
  }
  k.mult(1.0 / sqrt(m));

  PVector i = new PVector();
  PVector.cross(up, k, i);
  i.normalize();

  PVector j = new PVector();
  PVector.cross(k, i, j);
  j.normalize();

  out.set(i.x, j.x, k.x, 0.0, 
    i.y, j.y, k.y, 0.0, 
    i.z, j.z, k.z, 0.0, 
    0.0, 0.0, 0.0, 1.0);
  return out;
}
3 Likes

Thank you for sharing the solution to your problem.

Kf