6
\$\begingroup\$

I'm transitioning from OpenGL 2 to OpenGL 3.+ and to GLSL 1.5. I'm trying to avoid using the deprecated features.

My question how do we now generate the view or projection matrix. I was using the matrix stack to calculate the projection matrix for me;

GLfloat ptr[16]; 
gluPerspective(...);
glGetFloatv(GL_MODELVIEW_MATRIX, ptr); 
//then pass ptr via a uniform to the shader

But obviously the matrix stack is deprecated. So this approach is not the best an option going forward.

I have the 'Red Book', 7th ed, which covers 3.0 & 3.1 and it still uses the deprecated matrix functions in it's examples.

I could write some utility-code myself to generate the matrices. But I don't want to re-invent this particular wheel, especially when this functionality is required for every 3D graphics program.

What is the accepted way to generate world,view & projection matrices for OpenGL? Is there an emerging 'standard' library for this? Or is there some other hidden (to me) functionality in OpenGL/GLSL which I have overlooked?

\$\endgroup\$

4 Answers 4

1
\$\begingroup\$

Take a look at the Unofficial OpenGL Software Development Kit.

Not only does it include the GLM library, there's also a GL Util module which contains a replacement for the matrix stack.

You can also see this tutorial for an introduction to the library.

\$\endgroup\$
5
\$\begingroup\$

I'm sure somebody will write a whole novel on how to calculate the perspective projection and the view matrix, but that's just unnecessary. You'll find this information in any modern book on 3D graphics. If you don't have access to books like Real-Time Rendering then there are OpenGL Tutorials. Alternatively you can just use google. You're looking for common knowledge that's been answered dozens of times. If you don't care about the mathematics then libraries like GLM have functions to generate these matrices.

As for a commonly accepted way of doing this, the principle is always the same for both the view and perspective matrices. There are multiple ways of achieving both (f.e. you can calculate the view matrix as a camera transform and then invert it, or you can calculate it inverted already, the second being much faster), but if you know where to plug your variables then there isn't much difference. The thing you have to look out for is whether you're using the right or left hand coordinate system. Another thing to look out for is DirectX and OpenGL requiring different perspective projection matrices due to the way they define their clip spaces, so make sure that the perspective projection matrix you use is for OpenGL specifically.

\$\endgroup\$
22
  • \$\begingroup\$ I can generate the matrices by hand, no problem. I just don't want to have to write that code every time. Just wondering what every one else does, maybe its GLM? \$\endgroup\$
    – Ken
    Nov 23, 2012 at 12:07
  • \$\begingroup\$ @Ken well GLM is going to calculate the matrix each time aswell. just pack your logic into a function. your projection matrix should be calculated once, unless you change the aspect ratio of the screen, the camera matrix has to be calculated each frame. you should probably just pack both of those into a camera object that'll do things like rotate and move the camera and return the matrices when necessary. \$\endgroup\$
    – dreta
    Nov 23, 2012 at 12:18
  • 1
    \$\begingroup\$ by 'every time' in my comment above, I mean every time I start a graphics project. My main question is really about what utility or library is commonly for these purposes. Is there a replacement for gluPerspective, glRotate, glOrtho etc? The requirement for this functionality is so pervasive in graphics programming that I would be very surprised if everyone had to go and code their own solution. \$\endgroup\$
    – Ken
    Nov 23, 2012 at 12:31
  • \$\begingroup\$ @Ken well it's not really coding your own solution as much as it's writing a basic set of functions. it depends on a lot of things. if you don't want to deal with math then you can use GLM, lots of people do, it'll calculate transformations and do all the math for you. however if you're using a SIMD math library, like the one bullet has then it won't provide you with functions that create a rotation matrix or a perspective projection matrix and thus you'll have to do it yourself \$\endgroup\$
    – dreta
    Nov 23, 2012 at 12:54
  • \$\begingroup\$ @Ken your issue is weird one to have, because it's one of code re-usability. just pack your solution into a library and use it when you need it. if you don't want to write your own library then use some one else's like GLM. \$\endgroup\$
    – dreta
    Nov 23, 2012 at 12:58
3
\$\begingroup\$

For those looking for a copy/paste answer, or something a little more code like, here is an implementation for OpenGL. It supports a zoom feature to zoom in/out on the center of the view. I think the variable names are fairly self explanatory.

  • Camera is defined by it's position, direction it's looking and its up vector. The view matrix is made up of these values.

  • The "lens" you're using (I suppose it could be called?) describes the "cone" that represents what you're looking at in the world. It takes the view angle (how wide narrow the cone of view is) the size of your game window and the near and far cut offs for your view cone. These values make up the projection matrix.

The code below is working and taken from my game. I don't know if this is the most fashionable way to make the matrices, but it works for me and supports the older hardware the I'm targeting.

view = createView(getCameraPosition(), getCameraDirection(), getCameraUpVector());
projection = createProjection(cameraViewAngle * zoomFactor, (float) getWindowX() / (float) getWindowY(), nearPlane, farPlane);


Matrix4f createView(Vector3f position, Vector3f direction, Vector3f up) {
    Vector3f.cross(up, direction, getRightVector());
    setRightVector((Vector3f) getRightVector().normalise());

    result.m00 = getRightVector().x;
    result.m10 = getRightVector().y;
    result.m20 = getRightVector().z;
    result.m30 = -(Vector3f.dot(getRightVector(), position));

    result.m01 = up.x;
    result.m11 = up.y;
    result.m21 = up.z;
    result.m31 = -(Vector3f.dot(up, position));

    result.m02 = direction.x;
    result.m12 = direction.y;
    result.m22 = direction.z;
    result.m32 = -(Vector3f.dot(direction, position));

    return result;
}

Matrix4f createProjection(float fov, float aspect, float znear, float zfar) {

    float ymax, xmax;
    ymax = (float) (znear * Math.tan(fov * Math.PI / 360.0));
    xmax = ymax * aspectRatio;
    Matrix4f result = new Matrix4f();
    glhFrustumf2(result, -xmax, xmax, -ymax, ymax, znear, zfar);
    return result;
}

private Matrix4f glhFrustumf2(Matrix4f matrix, float left, float right, float bottom, float top, float znear, float zfar) {
    float twoZNear, deltaW, deltaH, deltaZ;
    twoZNear = 2.0f * znear;
    deltaW = right - left;
    deltaH = top - bottom;
    deltaZ= zfar - znear;
    matrix.m00 = twoZNear / deltaW;
    matrix.m01 = 0.0f;
    matrix.m02 = 0.0f;
    matrix.m03 = 0.0f;
    matrix.m10 = 0.0f;
    matrix.m11 = twoZNear / deltaH;
    matrix.m12 = 0.0f;
    matrix.m13 = 0.0f;
    matrix.m20 = (right + left) / deltaW;
    matrix.m21 = (top + bottom) / deltaH;
    matrix.m22 = (-zfar - znear) / deltaZ;
    matrix.m23 = -1.0f;
    matrix.m30 = 0.0f;
    matrix.m31 = 0.0f;
    matrix.m32 = (-twoZNear * zfar) / deltaZ;
    matrix.m33 = 0.0f;
    return matrix;
}
\$\endgroup\$
2
\$\begingroup\$

If you're using C++, the common answer is to use GLM. For C, you'll have to roll your own matrix math (which really isn't all that much code, a few hundred lines will get you everything you could possibly want). Look at the source code to Mesa or Blender if you want inspiration. Blender in particular has a nice set of matrix math functions. Beware of licensing issues if you intend to copy open source code to reuse though!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .