Sign in to follow this  
Darragh

OpenGL Matrices and the pipeline

Recommended Posts

Darragh    308
Hi, Well I'm after making some decent progress since I first took up learning OpenGL a few months ago. I can now use vertex arrays, vertex buffer objects, indexed geometry, texture mapping, fog, mipmapping, vertex/pixel shaders etc. etc.. However I feel as if I've skipped some of the basics, which I should really know inside out at this stage... My first question relates to the two matrices: the 'modelview' matrix and 'projection matrix'. In my 3D engine I only use the projection matrix to translate and rotate the map and all the game objects. This works fine, however I am unsure as why there is a second matrix (modelview) and what its purpose is. I have looked for some good explanations on the differences between the two matrices, but couldn't find anything decent to help explain them. So why do we need two transformation matrices ? What typical scenarios would you use each of the two matrices? Is the modelview matrix a transformation matrix used for transformations local to each object in a game (eg: monster / map item) and the projection matrix used for transforming the world (entire map geometry) ? Or is the modelview matrix simply an additional matrix which can recalled and used if needed ? Why use it? The second question regards the pipeline and viewing transforms. When I render each frame I first setup the projection matrix / rotations etc and then draw the map. I then push this matrix to save its status. The matrix is then transformed again by whatever position/rotation that each monster has, and the monster is then drawn. After drawing each monster I then pop the matrix to reload the previously saved state. Now.. If i remove the pop matrix line the entire world gets translated by whatever I translate the monster by. This brings me to some alarming conclusions.. When I am translating the monster, am I really translating everything else too? I thought once something was sent down the pipeline it stays in whatever position it was when it was first sent? Does this mean everytime I move a monster a whole bunch of unnecessary calculations are being peformed on the rest of the map? If so, how can I avoid such calculations? Thanks in advance for your help. I know this post is a bit of a pain [smile] but these are things I really need to get clear in my head before I go any further.

Share this post


Link to post
Share on other sites
jyk    2094
Hi,

Whether you know it or not, you are using the modelview matrix. Search through your code - somewhere I'm sure you'll find the line glMatrixMode(GL_MODELVIEW).

Ok, so on to what the two matrices do. The modelview matrix performs an affine transformation; more practically, it sets the position and orientation of your camera and of objects in the scene in 3d space, and applies other linear transformations such as scale, reflection, and shear.

The projection matrix performs a different function: it converts the 3d world into 2d information that can be displayed on the screen. Variables include field of view, aspect ratio, and near and far clipping planes.

I'm not exactly sure how OpenGL implements this internally, but in any case you don't have to worry about doing 'too much transformation'. That's why matrix concatenation is useful; no matter how many transformations you combine, it still comes down to a single matrix-vector multiplication per vertex.

Share this post


Link to post
Share on other sites
ff8    134
projection matirx for the frustum and ortho things.
modelview matrix for translating/rotatting/scaling for the objects
texture matrix same as modelview matrix but for the textures GL_TEXTURE_1D/2D/3D
for more details read the red book

Share this post


Link to post
Share on other sites
ff8    134
mmm i am not sure about your second question but every push you should pop it or you'll face problem, because the matrix stack has a limit and every loop in your main function you'll push till it gets full .
maybe i am wrong about this ..
bye

Share this post


Link to post
Share on other sites
Darragh    308
Ah yes- now it makes more sense.. I can see the relationship between the two more clearly now. Good reply..

Quote:
Original post by jyk
Whether you know it or not, you are using the modelview matrix. Search through your code - somewhere I'm sure you'll find the line glMatrixMode(GL_MODELVIEW).


Nope. All throughout my code the matrix used is GL_PROJECTION - even in my vertex shaders. I can see how it can be used to achieve the same effect though, since ultimately it controls how points are projected from world space onto the screen.

Ok, so that's one issue cleared up I think. Any more ideas on the other question?

Thanks again for your post.

Share this post


Link to post
Share on other sites
ParadigmShift    190
The answer to the second question is that, for rigid meshes, every vertex is transformed exactly once, with whatever matrix was loaded at the time the draw function is called. Basically, when you call glBegin() the driver makes a copy of the matrix at the top of the stack and sends that along with the vertices you specify, and whatever happens afterwards it preserves the illusion that the vertices are completely transformed & rendered with the current GL state before you go and muck with it.

So, the transformations are just numerical manipulations on the matrix only, and don't actually *move* anything until you draw something. It looks like a little crash-course in linear algebra would help you out a lot in understanding these concepts.

Tom

Share this post


Link to post
Share on other sites
ParadigmShift    190
Also, it is perfectly plausible to use the projection matrix only, as the two matrices are always concatenated prior to transformation. They are only separate because it can be handy to manipulate one and not the other. For instance:

You have a Projection matrix with the following transforms:
1. Frustum transform
2. Viewing (camera) transform

And a Model matrix with the following transforms:
3. World transform
4. Model transform
5. Sub-model transform (objects moving relative to parent objects, etc)

This is more or less the same as one Projection matrix with transforms 1-5, but say you wanted to draw mountains twice, once regularly and once reflected in water. To do the reflection, you want to flip the camera.

If you're using one matrix, you need to pop 5, 4, 3, and 2, specify a new camera transform, and then specify 3-5 again.

If you're using two matrices, you just pop 2 off the Projection and specify your new camera, and the Model matrix stays the same.

Tom

Share this post


Link to post
Share on other sites
Darragh    308
Quote:
Original post by ParadigmShift
The answer to the second question is that, for rigid meshes, every vertex is transformed exactly once, with whatever matrix was loaded at the time the draw function is called. Basically, when you call glBegin() the driver makes a copy of the matrix at the top of the stack and sends that along with the vertices you specify, and whatever happens afterwards it preserves the illusion that the vertices are completely transformed & rendered with the current GL state before you go and muck with it.


Excellent. That was just what I needed to know.. At least I can be sure now that everything is being transformed once, and once only.

Quote:
Original post by ParadigmShift
So, the transformations are just numerical manipulations on the matrix only, and don't actually *move* anything until you draw something. It looks like a little crash-course in linear algebra would help you out a lot in understanding these concepts.
Tom


I do a lot of stuff on algebra and matrices in college- just had my final year maths exam today in fact! [smile] Its not that I don't understand the maths involved in the rotations, I'm just unsure exactly what the hell OpenGL / display drivers are doing underneath the API to my geometry. However, you're post has helped clear that up so I am thankful for that.

Well thats great guys, I feel much more enlightened now! [wink] You have been most helpful so I think extra ratings are in order.

Cheers
-Darragh

Share this post


Link to post
Share on other sites
jyk    2094
Hm, guess I was wrong about having to use the modelview matrix :-| However, see here (section 8.030) and here for discussion of the way OpenGL intends for the matrices to be used and the reasons for following these guidelines.

Share this post


Link to post
Share on other sites
Darragh    308
Thanks for that. Those two articles are very informative- i'll keep them for future reference.

You've also managed to solve another long outstanding problem i had...

In the article about 'GL_PROJECTION' abuse (of which I am guilty [smile]), it also mentions the problems of using the projection matrix with fog. Now cast you're eye back to the thread which I started on that very subject.. I was unable to solve the problem (until now) and subsequently had to resort to learning GLSL and using pixel shaders in order to do my fogging. If only I had known about this back then!... [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By Kjell Andersson
      I'm trying to get some legacy OpenGL code to run with a shader pipeline,
      The legacy code uses glVertexPointer(), glColorPointer(), glNormalPointer() and glTexCoordPointer() to supply the vertex information.
      I know that it should be using setVertexAttribPointer() etc to clearly define the layout but that is not an option right now since the legacy code can't be modified to that extent.
      I've got a version 330 vertex shader to somewhat work:
      #version 330 uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; layout(location = 0) in vec4 Vertex; layout(location = 2) in vec4 Normal; // Velocity layout(location = 3) in vec3 TexCoord; // TODO: is this the right layout location? out VertexData { vec4 color; vec3 velocity; float size; } VertexOut; void main(void) { vec4 p0 = Vertex; vec4 p1 = Vertex + vec4(Normal.x, Normal.y, Normal.z, 0.0f); vec3 velocity = (osg_ModelViewProjectionMatrix * p1 - osg_ModelViewProjectionMatrix * p0).xyz; VertexOut.velocity = velocity; VertexOut.size = TexCoord.y; gl_Position = osg_ModelViewMatrix * Vertex; } What works is the Vertex and Normal information that the legacy C++ OpenGL code seem to provide in layout location 0 and 2. This is fine.
      What I'm not getting to work is the TexCoord information that is supplied by a glTexCoordPointer() call in C++.
      Question:
      What layout location is the old standard pipeline using for glTexCoordPointer()? Or is this undefined?
       
      Side note: I'm trying to get an OpenSceneGraph 3.4.0 particle system to use custom vertex, geometry and fragment shaders for rendering the particles.
    • By markshaw001
      Hi i am new to this forum  i wanted to ask for help from all of you i want to generate real time terrain using a 32 bit heightmap i am good at c++ and have started learning Opengl as i am very interested in making landscapes in opengl i have looked around the internet for help about this topic but i am not getting the hang of the concepts and what they are doing can some here suggests me some good resources for making terrain engine please for example like tutorials,books etc so that i can understand the whole concept of terrain generation.
       
    • By KarimIO
      Hey guys. I'm trying to get my application to work on my Nvidia GTX 970 desktop. It currently works on my Intel HD 3000 laptop, but on the desktop, every bind textures specifically from framebuffers, I get half a second of lag. This is done 4 times as I have three RGBA textures and one depth 32F buffer. I tried to use debugging software for the first time - RenderDoc only shows SwapBuffers() and no OGL calls, while Nvidia Nsight crashes upon execution, so neither are helpful. Without binding it runs regularly. This does not happen with non-framebuffer binds.
      GLFramebuffer::GLFramebuffer(FramebufferCreateInfo createInfo) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); textures = new GLuint[createInfo.numColorTargets]; glGenTextures(createInfo.numColorTargets, textures); GLenum *DrawBuffers = new GLenum[createInfo.numColorTargets]; for (uint32_t i = 0; i < createInfo.numColorTargets; i++) { glBindTexture(GL_TEXTURE_2D, textures[i]); GLint internalFormat; GLenum format; TranslateFormats(createInfo.colorFormats[i], format, internalFormat); // returns GL_RGBA and GL_RGBA glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, createInfo.width, createInfo.height, 0, format, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); DrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, textures[i], 0); } if (createInfo.depthFormat != FORMAT_DEPTH_NONE) { GLenum depthFormat; switch (createInfo.depthFormat) { case FORMAT_DEPTH_16: depthFormat = GL_DEPTH_COMPONENT16; break; case FORMAT_DEPTH_24: depthFormat = GL_DEPTH_COMPONENT24; break; case FORMAT_DEPTH_32: depthFormat = GL_DEPTH_COMPONENT32; break; case FORMAT_DEPTH_24_STENCIL_8: depthFormat = GL_DEPTH24_STENCIL8; break; case FORMAT_DEPTH_32_STENCIL_8: depthFormat = GL_DEPTH32F_STENCIL8; break; } glGenTextures(1, &depthrenderbuffer); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, createInfo.width, createInfo.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthrenderbuffer, 0); } if (createInfo.numColorTargets > 0) glDrawBuffers(createInfo.numColorTargets, DrawBuffers); else glDrawBuffer(GL_NONE); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "Framebuffer Incomplete\n"; glBindFramebuffer(GL_FRAMEBUFFER, 0); width = createInfo.width; height = createInfo.height; } // ... // FBO Creation FramebufferCreateInfo gbufferCI; gbufferCI.colorFormats = gbufferCFs.data(); gbufferCI.depthFormat = FORMAT_DEPTH_32; gbufferCI.numColorTargets = gbufferCFs.size(); gbufferCI.width = engine.settings.resolutionX; gbufferCI.height = engine.settings.resolutionY; gbufferCI.renderPass = nullptr; gbuffer = graphicsWrapper->CreateFramebuffer(gbufferCI); // Bind glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); // Draw here... // Bind to textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textures[1]); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textures[2]); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); Here is an extract of my code. I can't think of anything else to include. I've really been butting my head into a wall trying to think of a reason but I can think of none and all my research yields nothing. Thanks in advance!
    • By Adrianensis
      Hi everyone, I've shared my 2D Game Engine source code. It's the result of 4 years working on it (and I still continue improving features ) and I want to share with the community. You can see some videos on youtube and some demo gifs on my twitter account.
      This Engine has been developed as End-of-Degree Project and it is coded in Javascript, WebGL and GLSL. The engine is written from scratch.
      This is not a professional engine but it's for learning purposes, so anyone can review the code an learn basis about graphics, physics or game engine architecture. Source code on this GitHub repository.
      I'm available for a good conversation about Game Engine / Graphics Programming
    • By C0dR
      I would like to introduce the first version of my physically based camera rendering library, written in C++, called PhysiCam.
      Physicam is an open source OpenGL C++ library, which provides physically based camera rendering and parameters. It is based on OpenGL and designed to be used as either static library or dynamic library and can be integrated in existing applications.
       
      The following features are implemented:
      Physically based sensor and focal length calculation Autoexposure Manual exposure Lense distortion Bloom (influenced by ISO, Shutter Speed, Sensor type etc.) Bokeh (influenced by Aperture, Sensor type and focal length) Tonemapping  
      You can find the repository at https://github.com/0x2A/physicam
       
      I would be happy about feedback, suggestions or contributions.

  • Popular Now