OpenGL global matrices

Started by
17 comments, last by pulpfist 18 years, 4 months ago
I have made a Vector3 object to support jyk's namespace

class Vector3
{
    union {
        float v[3];
        struct { float x, y, z; } p;
    };

public:

    Vector3() { p.x = p.y = p.z = 0; }
    Vector3(const Vector3 &rhs) { p.x = rhs.p.x; p.y = rhs.p.y; p.z = rhs.p.z;}
    Vector3(float new_x, float new_y, float new_z) { Set(new_x, new_y, new_z); }
    virtual ~Vector3() {}

    void Set(float new_x, float new_y, float new_z) { p.x = new_x; p.y = new_y; p.z = new_z; }
    const float& operator[] (int offset) const { return v[offset]; }
    Vector3 operator * (float rhs) { return Vector3(p.x * rhs, p.y * rhs, p.z * rhs); }
    friend Vector3 operator * (float lhs, const Vector3 &rhs);
    Vector3 operator + (const Vector3 &rhs) { return Vector3(p.x + rhs.p.x, p.y + rhs.p.y, p.z + rhs.p.z); }
    Vector3 operator - (const Vector3 &rhs) const { return Vector3(p.x - rhs.p.x, p.y - rhs.p.y, p.z - rhs.p.z); }
    void operator += (const Vector3 &rhs) { *this = *this + rhs; }
    Vector3& operator = (const Vector3 &rhs) {
        if(this == &rhs)
            return *this;
        p.x = rhs.p.x;
        p.y = rhs.p.y;
        p.z = rhs.p.z;
        return *this;
    }
    Vector3 Cross(const Vector3 &rhs) const {
        return Vector3(p.y * rhs.p.z - rhs.p.y * p.z, p.z * rhs.p.x - rhs.p.z * p.x, p.x * rhs.p.y - rhs.p.x * p.y);
    }
    float Dot(const Vector3 &rhs) const {
        return (p.x * rhs.p.x) + (p.y * rhs.p.y) + (p.z * rhs.p.z);
    }
    void NormalizeSelf() {
        double t = std::sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
        p.x /= t;
        p.y /= t;
        p.z /= t;
    }
};

// implementation of the friend:
Vector3 operator * (float lhs, const Vector3 &rhs)
{
    return Vector3(lhs * rhs.p.x, lhs * rhs.p.y, lhs * rhs.p.z);
}




My initialization code looks like this

...
    oglManager glm;
    Vector3 cam_pos, cam_target, cam_up;
    MSG msg;
    BOOL bQuit = FALSE;

    glm.move_window(0, 0);
    glm.size_window(640, 640);
    glm.init(hInstance, hPrevInstance, lpCmdLine, iCmdShow, msg_pump, render_screen);

    cam_pos.Set(0.0f, 0.0f, 0.0f);
    cam_target.Set(0.0f, 0.0f, 1.0f);
    cam_up.Set(0.0f, 1.0f, 0.0f);

    glObj.SetMode(OpenGLObject::MODE_6DOF);
    //glObj.SetPos(cam_pos);
    glObj.LookAt(cam_pos, cam_target, cam_up);

    while(!bQuit) {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
    ...






glm is an instance of my openGL manager object, and glObj is an instance of jyk's OpenGLObject. the render function...

int render_screen()
{
    //static float theta = 0.0f;

    glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
    glClear (GL_COLOR_BUFFER_BIT);

    glPushMatrix();
    //glRotatef(theta, 0.0f, 0.0f, 1.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);   glVertex2f (0.0f, 1.0f);
    glColor3f(0.0f, 1.0f, 0.0f);   glVertex2f (0.87f, -0.5f);
    glColor3f(0.0f, 0.0f, 1.0f);   glVertex2f (-0.87f, -0.5f);
    glEnd();
    glPopMatrix();

    //theta += 1.0f;

    glObj.ApplyRoll(3);
    glObj.SetOpenGLModelMatrix(); // Should this be called only once, in the init section?
    glObj.SetOpenGLViewMatrix();  // How about this?

    Sleep(1);

    return 0;
}






My guess is that my camera need to set GL's global view matrix for every render, but what is the model matrix good for? and do I need to set this for each render? jyk's namespace also introduce the

void MultOpenGLModelMatrix();
void MultOpenGLViewMatrix();
Where and why does these come in to play? PS. Some of the code (typically the Sleep(1)) is just some remains from the default Code::Blocks opengl project that I am extending. (I have no idea why someone would sleep for 1 ms. at the end of a render routine, could it be an attempt to yield the CPU?) EDIT: Any tips on how to make the Vector3 object more efficient would be appreciated aswell, like if any of the operators REALY need to be outlined? Thanks [Edited by - pulpfist on December 5, 2005 11:52:30 AM]
Advertisement
Hi,

I'll take a look at this later today or this evening - I can probably give you some tips on how to use the OpenGLObject class.
Just so you know, the plural of matrix is matrices, not matrixes ;-)
Quote:
ust so you know, the plural of matrix is matrices, not matrixes ;-)

Could have fooled me ^^

Quote:
I can probably give you some tips on how to use the OpenGLObject class.


Thats great

As you can see Im a bit cunfused when it comes to movement :D
Any tips or good links to info would be great.

So far, the rotation works smooth, side/up slide works, but not smooth (moving way too far between each render), and forward/backward movement has a similar side effect aswell
You've asked for some optimization for Vector3 class, and actually I have some suggestions:

Using initialization lists should be preferred to assigning the member fields later. So it is better to use
class Vector3{    Vector3() : p.x(0), p.y(0), p.z(0) {}    Vector3(const Vector3 &rhs) : p.x(rhs.p.x), p.y(rhs.p.y), p.z(rhs.p.z) {}    // ...

(Unfortunately I don't remember where I've read this.)

In the following assignment I personally would drop the internal if clause. I assume it will happen very seldom that "rhs" and "this" is the same, so that most time the if clause causes (little) costs only.
Vector3& operator = (const Vector3 &rhs) {        if(this == &rhs)            return *this;        p.x = rhs.p.x;        p.y = rhs.p.y;        p.z = rhs.p.z;        return *this;    }


Using divisions is still costly. It would be better to replace them by multiplications if applying it often.
    void NormalizeSelf() {        double t = 1.0f/std::sqrt(p.x * p.x + p.y * p.y + p.z * p.z);        p.x *= t;        p.y *= t;        p.z *= t;    }

However, maybe you have an inverse sqrt function at hand? I personally use an approximation to sqrt that computes 1/sqrt in fact (it simply drops the last step of the standard sqrt approximation routine). So you are able to drop 2 divisions from the routine above.

The remaining seems me ok.
Additionally, I could give some general hints to the question about matrices. I don't know jyk's class in detail, but the explanations should hold in general. Hopefully I don't tell too much in advance of jyk's announced explanation :-)


You may have to deal with 4 usages of matrices:

(1) The matrix for projection, i.e. mainly the mapping of the 3D world to the 2D display by handling the "depth". This matrix describes the well known perspective or orthogonal projection (other are possible but seldomly used). OpenGL provides this matrix by its matrix mode GL_PROJECTION.

(2) The view matrix defines which part of the scene is displayed: where in the world the camera is placed, where does it look at. It could be understood to transform the entire world so that the camera's location becomes the origin, and the camera's orientation the basis. It is in fact the inverse of the model matrix (see below) of the camera if the camera is implemented as an object. If you look into the GetModelMatrix and GetViewMatrix routines you'll see this interrelation.

In OpenGL there is no view matrix support on its own, but in combination with the model matrix in the so-called MODELVIEW matrix mode. This is often a cause of confusion. It requires (in conjunction with OpenGL's matrix definitions) to supply the view matrix to OpenGL _before_ supplying any model matrix.

(3) A model matrix defines how a model (e.g. a mesh) is located and oriented (and perhaps also scaled) w.r.t. a reference co-ordinate system. Often the reference system is "the world", but need not. E.g. you may use a scene graph to model spatial dependencies, so you may have 4 wheels, each one with an own model matrix w.r.t. the car, what itself has a model matrix w.r.t. the world. So this kind of matrix is also called "local transformation matrix" or similar. Due to some reasons, the particular vertices of a model are usually not given w.r.t. the world but the local matrix of the model. So the rendering needs to know the current model matrix.

(4) A texture matrix. That is surely out of scope here.

So in general you set-up OpenGL's projection matrix once at start-up, its view matrix once per rendering the scene, but typically will provide model matrices as many times as models are available for rendering.


Coming to the MultOpenGLXyzMatrix() routines: Looking back to the explanation of the model matrices above, you see that matrices may need to be concatenated to describe an overall transformation (e.g. you may need to multiply the model matrix of the left front wheel by those of the car to yield in the transformation of the wheel w.r.t. the world). But be aware that matrix multiplications are not commutative, so that the order of invoking the Mult routines plays a role.

[Edited by - haegarr on December 5, 2005 9:05:54 AM]
Thanks haegarr

That was enlightening
Exactly what I was confused about

By the way, I think I had some compiler errors when I used an initializer list, but Ill try it again. It could be my compiler MingW beeing picky
Quote:Original post by Anonymous Poster
Just so you know, the plural of matrix is matrices, not matrixes ;-)

Oh? Check your sources.
Quote: from Merriam-Webster
Inflected Form(s): plural ma-tri-ces /'mA-tr&-"sEz, 'ma-/; or ma-trix-es /'mA-trik-s&z/
...and while we are on the subject:
Quote: from Merriam-Webster
Inflected Form(s): plural ver-ti-ces /'v&r-t&-"sEz/; also ver-tex-es
Inflected Form(s): plural in-dex-es or in-di-ces /-d&-"sEz/
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Cool, didn't know that about the alternate plurals :)

@pulpfist: I think most of the basic concepts were covered in the previous posts, but in summary:

1. Unless you're incorporating zoom or doing something else unusual, the projection matrix is commonly set at the beginning of the simulation and left alone. The OpenGLObject class doesn't deal with the projection matrix in any way.

2. The view matrix is typically set once at the beginning of each frame. In my class this is done through SetOpenGLViewMatrix(). The function loads the matrix straight into OpenGL, so you don't have to call glLoadIdentity() first.

3. After that you can render anything you like by using MultOpenGLModelMatrix() to concatenate a model transform with the current matrix. If you want to render more than one object, or render a hierarchy of objects, it will probably be easiest to use glPushMatrix() and glPopMatrix().

4. Remember that in OpenGL, the view and model matrices are combined; the difference between a view matrix and a model matrix in OpenGL is really only conceptual.
Quote:As you can see Im a bit cunfused when it comes to movement :D
Any tips or good links to info would be great.

So far, the rotation works smooth, side/up slide works, but not smooth (moving way too far between each render), and forward/backward movement has a similar side effect aswell.
Moving too far between frames sounds like a problem outside of the OpenGLObject code. If you can describe the behavior in more detail, and/or perhaps post the code where you're moving the object, I'll certainly try to spot the problem if I can.
Thanks
I have a better grasp of how thing is supposed to work, but doing it in code is still a bit confusing.

Here is what I got so far

Init code:
void InitOpenGL (void){	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	glClearDepth(1.0f);	glEnable(GL_DEPTH_TEST);	glDepthFunc(GL_LEQUAL);	glShadeModel(GL_SMOOTH);	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);	// Set up initial position/orientation using LookAt	cam_pos.Set(0.0f, 0.0f, 0.0f);	cam_target.Set(0.0f, 0.0f, 3.0f);	cam_up.Set(0.0f, 1.0f, 0.0f);      // glo = OpenGLObject instance	glo.SetMode(OpenGLObject::MODE_6DOF);	glo.LookAt(cam_pos, cam_target, cam_up);      // Feed camera position/orientation into the modelview matrix	glo.SetOpenGLViewMatrix();	glo.SetOpenGLModelMatrix();}

and here is the render:
void RenderFrame (void){    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);    glo.SetOpenGLViewMatrix();    glo.ApplyPitch(rot_pitch);    glo.MoveAlongForwardAxis(move_frwd);    glo.SetOpenGLModelMatrix();    // this makes things happen    //glo.MultOpenGLModelMatrix(); // this makes everything disappear    // draw rectangle    glTranslatef(0.0f, 0.0f, -8.0f);    //glRotatef(angle, 0.0f, 0.0f, 1.0f);    DrawTriangle();}

DrawRectangle just draws a simple rectangle.

When the rendering starts, I am positioned at 0,0,0 and have the rectangle right in front of me.
If I press the up-key, the rectangle start to rotate around me, which is good, but if I move myself(camera) away from 0,0,0, first, and then start to rotate, the rectange still rotate around 0,0,0, and not around me.
How do I make everything rotate around me and not around 0,0,0?

(Strictly speaking, I want to be the one rotating, but if I understand correct, its more common to have the world, and everything in it, rotate instead)

Im I supposed to reset(identity) all the matrices before every object I render?
The way its set up now, I never use any kind of Identity functions except at program init.

By the way, the projection matrix is set equal to the identity matrix at startup, is this correct?

This topic is closed to new replies.

Advertisement