Simple camera positioning and lookat

Hi all!

I’m just starting out with oF and I’m trying to figure out how to move the camera. What I want is:

  • to have the camera looking at the origin where a model is placed, but as I understand there is no ‘origin’ in how oF’s 3d space is set up? I’m fixing this by getting ofGetWidth()/2 and ofGetHeight()/2, and setting z to 0. Is this correct?

  • I want to have the camera at a certain height moving around in a circle around the object, looking at the center

  • The camera rolls around its z-axis. (for which I use cam.roll(amount)) (where cam is an instance of ofEasyCam)

How can I do this? I’m sure I have a wrong understanding of how things work (also cam.begin() and cam.end() ) so if anyone can point me in the right direction that would be great!

Hi B,

nice to see you here.

In an empty OF program (using the project generator) (0,0,0) is on the top left, running bottom right to (window width, window height, 0).

When using ofEasyCam, the necessary matrices are automatically generated so that the middle of the screen is at (0,0,0), the viewport is as big as you set at main.cpp or using ofSetWindowShape(w,h), and the camera exactly far away so that the viewport is as big as your window.

An interesting concept in this regard is the ofNode class. You can see this as a 3D object that holds transformation data. So, an object that you want to control in 3D, is best to be paired with a node. The node holds all the scaling, orientation and positioning.

In OF, every camera is deriving from the ofNode class. As such, you can transform a camera using all the built in functions of ofNodes. Check link

A starting point for your problem could be the following for instance. Note that I’m using ofCamera instead of ofEasycam.

ofApp.h

    ofCamera cam;
    ofBoxPrimitive box;
    float angle;
    ofLight light;
    bool bOrbit, bRoll;
    float angleH, roll, distance;

ofApp.cpp

 //--------------------------------------------------------------
    void ofApp::setup(){
    
    ofSetVerticalSync(true);
    ofEnableDepthTest();
    
    box.set(100);
    
    light.enable();
    
    bOrbit = bRoll = false;
    angleH = roll = 0.0f;
    distance = 500.f;
}

//--------------------------------------------------------------
void ofApp::update(){
    if (bOrbit) angleH += 1.f;
    if (bRoll) roll += 0.5f;

    // here's where the transformation happens, using the orbit and roll member functions of the ofNode class, 
    // since angleH and distance are initialised to 0 and 500, we start up as how we want it
    cam.orbit(angleH, 0, distance);
    cam.roll(roll);

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetBackgroundColor(128);
    
    // use our camera matrices: translate to center of camera viewport and draw scene seen from transformed cam
    cam.begin();
    
    ofSetColor(200, 100, 0);
    box.draw();
    box.drawAxes(200);
    
    cam.end();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == 'h') {
        bOrbit = !bOrbit;
    }
    else if (key == 'r') {
        bRoll = !bRoll;
    }
    else if (key == OF_KEY_UP) {
        distance = MIN( (distance += 2.5f), 1000);
        cout << distance << endl;
        
    }
    else if (key == OF_KEY_DOWN) {
        distance = MAX( (distance -= 2.5f), 150);
        cout << distance << endl;

    }
}

Hey V!

Well… I’m trying to wrap my head around the way things work, so thank you for the example!
I’ve been trying to alter it so that the camera is actually looking down on the cube (at an angle of 45º; I’ve also added a plane, as ‘floor’ on which the cube is resting.) and this is the thing that is not working.
Changing my camera position, changing its lookAt, making an ofNode and move that around to use as lookAt for the camera… doesn’t alter anything in the scene.

So, basically, changing the second float of cam.orbit brings the camera up, but the units seem to be different than those of the distance (is this different than z?). If I bring this second value up to the same amount as the distance, the angle of view on the object positioned at 0. 0. 0. should be 45º… but that is not the case.

I know, so many questions! So much to process at once, especially since coming from another paradigm. :slight_smile:

Hello @Autofasurer,

what you do a lot when working in OF is checking function type signatures.
Doing this for the orbit member function, we get the following:

/// \brief Orbit object around target at radius
void orbit(float longitude, float latitude, float radius, const ofVec3f& centerPoint = ofVec3f(0, 0, 0));

You see that the function take lon and lat values, a radius and a centerpoint. The centerpoint is defaulted at the origin, so you don’t nee to provide the paramater (as in my example) but you can.

Updated example, using latitude:

Best,
V

ofApp.h

ofCamera cam;
ofBoxPrimitive box;
ofSpherePrimitive sphere;
float angle;
ofLight light;
bool bOrbit, bRoll;
float angleH, angleV, roll, distance;

ofApp.cpp

//--------------------------------------------------------------
void ofApp::setup(){
    
    ofSetVerticalSync(true);
    ofEnableDepthTest();
    
    box.set(100);
    sphere.set(20, 10);
    
    light.enable();
    
    bOrbit = bRoll = true;
    angleH = roll = 0.0f;
    distance = 500.f;
    
    cam.setPosition(0, 0, 1000);
}

//--------------------------------------------------------------
void ofApp::update(){
    if (bOrbit) {
        angleH += 1.f;
        if (angleH > 360.f) angleH = 0.f;
        
        angleV += 0.25f;
        if (angleV > 360.f) angleV = 0.;
    }
    if (bRoll) roll += 0.5f;
    
    // convert angleV to range [-90,90] for latitude
    float vFac = sin(angleV * M_PI / 180.f) * 90.f;
    sphere.orbit(angleH, vFac, distance);
    sphere.roll(roll);

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetBackgroundColor(128);
    //ofEnableAlphaBlending();

    
    // translate to center of camera viewport and draw scene
    cam.begin();
    
    ofSetColor(200, 100, 0, 255);
    box.draw();
    box.drawAxes(200);
    
    ofSetColor(100, 200, 0, 255);
    sphere.draw();
    sphere.drawAxes(200);
    
    cam.end();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == 'h') {
        bOrbit = !bOrbit;
    }
    else if (key == 'r') {
        bRoll = !bRoll;
    }
    else if (key == OF_KEY_UP) {
        distance = MIN( (distance += 2.5f), 1000);
    }
    else if (key == OF_KEY_DOWN) {
        distance = MAX( (distance -= 2.5f), 150);
    }
}