3D Rotation of Objects with two Vectors

Hi Guys!
I have a dumb question, i know, they are a couple of solutions in this forum but i dont understand how it realy works…

lets say, i have

ofVec3f BoxUpVector (0,1,0);
ofVec3f BoxNormalVector(0,0,1);

some Object for ex.

ofDrawBox(bla bla bla);

and i have two others vectors

ofVec3f NewUpVector (-0.608556, 0.789434, 0.0803312);
ofVec3f NewNormalVector(0.20675, 0.060007, 0.976552);

The BoxUpVector and BoxNormalVector are Vectors that describe a rotation of the Box. How can i rotate my Box, so my BoxUpVector is aligned with NewUpVector and BoxNormalVector with NewNormalVector?

ive tryed this, but it does not works every time.

ofPushMatrix();
   
   // align Normal Vectors
   ofVec3f CrossNewBoxNormals = NewNormalVector.getCrossed(BoxNormalVector);
   float   AngleBetweenNewBox = NewNormalVector.angle(BoxNormalVector);
   ofRotate(AngleBetweenNewBox, CrossNewBoxNormals.x, CrossNewBoxNormals.y, CrossNewBoxNormals.z);

   // rotate BoxUpVector
   ofVec3f RotatedBoxUpVector = BoxUpVector.getRotated(AngleBetweenNewBox, CrossNewBoxNormals);
   
   // Align Up Vectors
   ofVec3f CrossUpVectors      = RotatedBoxUpVector.getCrossed(NewUpVector);
   int RotationDirection       = CrossUpVectors.angle(NewNormalVector) < 1? 1: -1;
   float AngleBetweenUpVectors = RotatedBoxUpVector.angle(NewUpVector) * RotationDirection;
   
   // Rotate
   ofRotateZ(AngleBetweenUpVectors);
   
   // Draw this sh...
   ofDrawBox (0,0,0,100,200,300);

ofPopMatrix();

any suggestions? :sunny:

This kind of complex transformations are easier if you use ofNode or of3dPrimitives instead of trying to figure it out with global transformations.

Something like:

//h
ofBoxPrimitive box;

//setup
box.set(size);

//update
ofQuaternion qNormal;
qNormal.makeRotate(boxNormal, newNormal);
ofQuaternion qUp;
qUp.makeRotate(boxUp, newUp);
box.setOrientation(qNormal * qUp);

//draw
box.draw();

also take a look at ofNode methods since it’s very probable that you won’t even need to calculate the rotations manually and you can just use lookAt to the new normal and up each frame:

//update
box.lookAt(box.getPosition() + normalVector, upVector);

Thank you for your reply!

But this box is only a simple example, that i made to explain what i mean…Between ofPushMatrix() and ofPopMatrix() I have a bunch of different types of Objects like ofTrueTypeFont, ofDrawSphere, ofLine… What would the complex way looks like?

My Example dont works in a little particular position, but it anyhow works… May be i have some logic error it overthere… If i do this:

ofMatrixPush();
    // align Normal Vectors
    ofVec3f CrossNewBoxNormals = NewNormalVector.getCrossed(BoxNormalVector);
    float   AngleBetweenNewBox = NewNormalVector.angle(BoxNormalVector);
    ofRotate(AngleBetweenNewBox, CrossNewBoxNormals.x, CrossNewBoxNormals.y, CrossNewBoxNormals.z);
ofMatrixPop();

than my Objects inside ofMatrixPop and Push is almoust aligned. The rest is to align his Up vector. If i try to get the angle between the new Up vector and the calculated old one, the system dont know, in which direction it should rotate the object because the angle is only til 180 and we are not in two dimensions… Therefore i make a cross vector and check if his direction is aligned with direction of the new normal vector… so simple but again ^^ works not every time

Here is some example with the box rotation. Just copy in your Project and if you will move your mouse, you will see that threre are a couple of spots, where the Up Vector of the Box is not aligned to the new one…

ofVec3f center (250, 250, 0);
float angleX, angleY;

//--------------------------------------------------------------
void ofApp::draw() {
    
    ofEnableDepthTest();
    
    // VECTORs THAT DESCRIPE A NEW ROTATION OF THE BOX
    ofVec3f newNormal   (0,0,1000);
    ofVec3f newUp       (0,-1000,0);
    
    // ROTATE NEW VECTORS WITH THE MOUSE
    newNormal.rotate(angleX, ofVec3f(0,-1,0));
    newNormal.rotate(angleY, ofVec3f(-1,0,0));
    
    newUp.rotate(angleX, ofVec3f(0,-1,0));
    newUp.rotate(angleY, ofVec3f(-1,0,0));
    
    // REFERENCE VECTORS OF THE BOX
    ofVec3f boxNormal(0,0,1);
    ofVec3f boxUp    (0,-1,0);
    
    // GET ANGLE AND ROTATION AXIS OF NEW AND BOX NORMALS
    ofVec3f crossBoxNewNormal = boxNormal.getCrossed(newNormal);
    float   angleBoxNewNormal = boxNormal.angle(newNormal);
    
    // ROTATE UP VECTOR OF THE BOX, GET CROSSED WITH THE NEW UP VECTOR, GET ANGLE AND ROTATION DIRECTION
    ofVec3f rotatedBoxUp      = boxUp.getRotated(angleBoxNewNormal, crossBoxNewNormal);
    ofVec3f crossBoxNewUp     = rotatedBoxUp.getCrossed(newUp);
    int     direction         = crossBoxNewUp.angle(newNormal) < 1? 1: -1;
    float   angleBoxNewUp     = rotatedBoxUp.angle(newUp) * direction;
    
    // DRAW NEW NORMAL
    ofSetLineWidth(1);
    ofSetColor(255, 0, 0);
    ofLine(center, center + newNormal);
    
    // DRAW NEW UP
    ofSetColor(0, 255, 0);
    ofLine(center, center + newUp);
    
    // DRAW ROTATED UP BOX VECTOR
    ofSetLineWidth(3);
    ofSetColor(0, 255, 255);
    ofLine(center, center + rotatedBoxUp.scale(170));

    ofPushMatrix();

        ofTranslate(center);
    
        // ALIGN NORMALS
        ofRotate (angleBoxNewNormal, crossBoxNewNormal.x, crossBoxNewNormal.y, crossBoxNewNormal.z);
    
        // ALIGN UP VECTORS
        ofRotateZ(angleBoxNewUp);
    
        // DRAW DA BOX
        ofSetColor(0, 0, 255);
        ofDrawBox(0, 0, 0, 100, 150, 200);
    
        // DRAW NORMAL OF THE BOX
        ofSetLineWidth(10);
        ofSetColor(255, 0, 0);
        ofLine(ofVec3f(0), ofVec3f(0,0,150));
    
        // DRAW UP VECTOR OF THE BOX
        ofSetColor(0, 255, 0);
        ofLine(ofVec3f(0), ofVec3f(0,-150,0));
    
    ofPopMatrix();
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){
    
    angleX = x / 500. * 300;
    angleY = y / 500. * 300;
}