Rotating an object along its local x axis

I have two points in 3D space, with a mesh drawn between them. I want to be able to have free rotation of that inner mesh along it’s own x axis, but using ofRotate it throws the object far from it’s original position.

I have oscillating sine waves, and what I want to do is be able to rotate them to create a sort of braid.

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    mesh.addVertex(ofVec3f(ofGetWidth()/2-150,ofGetHeight()/2));
    mesh.addColor(ofColor(255));
    mesh.addVertex(ofVec3f(ofGetWidth()/2+150,ofGetHeight()/2));
    mesh.addColor(ofColor(255));
    
    mesh.addIndex(0);
    mesh.addIndex(1);
    
    mesh.setMode(OF_PRIMITIVE_POINTS);
    
    glEnable(GL_POINT_SMOOTH);
    glPointSize(3);
    
    activeWave = false;
}

//--------------------------------------------------------------
void ofApp::update(){
    if(activeWave){
        for(int i=0;i<oscNum;i++){
            updateWave(i);
        }
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofEnableDepthTest();
    ofBackgroundGradient(ofColor(50),ofColor(0));
    
    cam.begin();
        ofPushMatrix();
            ofTranslate(-ofGetWidth()/2,-ofGetHeight()/2,0);
                mesh.draw();
                for(int i=0;i<oscNum;i++){
                    ofRotateX(90);       //THE OFFENDING ROTATION
                    oscMesh[i].draw();
                }
        ofPopMatrix();
    cam.end();
    
    ofDrawBitmapString("OSCNUM: " + ofToString(oscNum),10,10);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    
    if(key=='p'){ //POINTS
        for(int i=0;i<oscNum;i++){
            oscMesh[i].setMode(OF_PRIMITIVE_POINTS);
        }
    }
    if(key=='l'){ //LINES
        for(int i=0;i<oscNum;i++){
            oscMesh[i].setMode(OF_PRIMITIVE_LINE_STRIP);
        }
    }
    if(key=='f'){ //FIRE
        sendWave(0,1);
        activeWave = TRUE;
    }
}

//--------------------------------------------------------------
void ofApp::sendWave(int index, int burst){
    
    ofVec3f firingPoint = mesh.getVertex(index);
    ofVec3f destPoint = mesh.getVertex(index+1);
    
    int res = 150;
    
    for(int i=0;i<burst;i++){
        oscNum++;
        oscMesh.resize(oscNum);
        
        for (float x=0;x<res;x++){
            float delta = x/res;

            ofVec3f signal = firingPoint.getInterpolated(destPoint, delta);
            
            oscMesh[i].addVertex(signal);
            oscMesh[i].addColor(ofColor(ofRandom(255),ofRandom(255),ofRandom(255)));
        }
        
        oscMesh[i].addVertex(destPoint);
        oscMesh[i].addColor(ofColor(ofRandom(255),ofRandom(255),ofRandom(255)));
        
        oscMesh[i].setupIndicesAuto();
        oscMesh[i].setMode(OF_PRIMITIVE_LINE_STRIP);
    }
    
}

//--------------------------------------------------------------
void ofApp::updateWave(int i){
    
    int speed = 5;
    int rotation = 90;
    float time = ofGetElapsedTimef()/speed;
    
    int res = oscMesh[i].getNumVertices(); //Resolution
    
    for (int x=1;x<res;x++){
        float delta = x/res;
        
        float amp = 10;       //Amplitude
        float f   = 10;       //Frequency
        float p   = x;        //Phase
        
        float oscillation = amp * sin(2 * pi * f * time + p);
        ofVec3f oscTemp = oscMesh[i].getVertex(x);
        oscTemp.z = oscillation;
        
        oscMesh[i].setVertex(x,oscTemp);
    }

}

Before Rotation:

After Rotation:

Hello again, the problem is your meshes are not aligned with x axis, so it will go away. You can get the notion by replacing ofRotateX(90) with ofRotateX(90 * ofGetElapsedTimef()).

An easy fix is replace the mesh setup to

mesh.addVertex(ofVec3f(-150,0));
mesh.addColor(ofColor(255));
mesh.addVertex(ofVec3f(+150,0));
mesh.addColor(ofColor(255));

and delete ofTranslate(...) in draw. ofEasyCam is placed a bit far from (0,0,0) and looking at (0,0,0) by default.

Btw, it’s hard to figure out ofApp variables by hand so next time please add ofApp.h too :smile:

Thanks micuat, and I’ll remember to include header file next time ;). That does fix it, but it doesn’t quite give me the flexibility of performing that rotation at any location in space. I’ve heard to check out ofQuaternion, so I’ll post back with my findings after that!

Hi, do you want to rotate the object or the camera? Essentially in both cases you have to set a pivot point.
To rotate the object using ofRotate: the pivot is originally placed at 0,0,0 so you need to translate it using ofTranslate before performing the rotation. This means if you want to rotate something around 100, 200, 0 by 50 degrees around X axis you should do the following.

    ofPushMatrix();//this saves the current transformations, so you can restore them later.
    ofTranslate(100,200);
    ofRotateX(50);
    ofTranslate(-100,-200); //note the negative sign. this is to bring back the drawing position to 0,0.
    //draw whatever you want but
ofPopMatrix();//this restores the transformations saved before so the transformations made in between push and pop matrix dont affect what's drawn after this. 

The other way is rotating the camera. As you are using an ofEasyCam you’ll be controlling it with the mouse.
Jus call. cam.setTarget(ofPoint…); Now the camera and will rotate around this point.

best!

Thanks roymacdonald, just trying to rotate the object (and particularly every new instance of oscMesh) this is working well too, and it allows for my vertices to exist anywhere. Trying to figure out a way to implement it so that I can include a value for rotation for each new oscMesh. ofRotate seems to break when I throw in an incrementing number.

the easiest way to apply transformations to an object is to use ofNode or even better of3dPrimitive, just create you mesh in a 3d primitive like:

//.h
of3dPrimitive primitive;

//.cpp
// setup
primitive.getMesh().addVertex(ofVec3f(...));
primitive.setPosition(x,y,z);
primitive.rotate...
// or tilt, pan, roll to rotate around local axis of the mesh, it's 0,0,0

//draw
primitive.draw();

take into account that when looking through a camera 0,0,0 is in the center of the screen not top left and try to generate the mesh so it’s center is at 0,0 that way it’ll make it really easy to apply transformations to it.

ofTranslate, rotate… are harder to think about because they somehow transform the whole coordinate system instead of the object itself. internally of3DPrimitive is doing more or less the same but the way it’s done makes it easier to reason about the transformations in 3D mostly if your object is centered in 0,0,0. Also the code is way cleaner and easy to understand later

1 Like

To use of3dPrimitive in this case, could I make a vector containing them? So that I can have multiple collections of mesh?

vector<of3dPrimitive> oscMesh;

for(int i=0;i<burst;i++){
oscMesh[i].getMesh().addVertex(ofVec3f(...));
oscMesh[i].rotate(...);
}

It works, but I am not sure if that is necessarily the best way of creating a collection of meshes. Ideally I would even like to have a multidimensional vector to also tie each one to a vertex in a point cloud, probably something like:

vector< vector<of3dPrimitive> > oscMeshes;

and that way I could have oscMeshes[i1][i2], with i1 referring to the index of its “parent” vertex, and i2 referring to the index of the individual mesh making up the “braid”.