Search code examples
openglgraphics3dmatrix-multiplicationperspectivecamera

in opengl why do we have to do gluPerspective before gluLookAt?


so under GL_PROJECTION I did

    glu.gluPerspective(90,aspect,1,10);
    glu.gluLookAt(0,0,3,0,0,0,0,1,0);

this works fine but when I switch the order I don't get any object on my screen, I rotated my camera and theres nothing.

I know that switching the two changes the order of matrix multiplication but I want to know why the first case works but the second doesn't. Thanks


Solution

  • To see an object on screen you need it to fall within the canonical view volume, which is, for OpenGL, [−1, 1] in all three dimensions. To transform an object, you roughly do

    P' = Projection × View × Model × P

    where P' is the final point which needs to be in the canonical view volume and P is the initial point in model space. P is transformed by the model matrix followed by view and then projection.

    The order I've followed is column vector based, where each further transform is pre/left-multiplied. Another way to read the same formula is to read it from left-to-right where instead of transforming the point, the coordinate system is transformed and interpreting P in the transformed system spatially represents P' in the original system. This is just another way to see it, the result is the same in both; both numerically and spatially.

    why do we have to do gluPerspective before gluLookAt?

    The older, fixed-function pipeline OpenGL post/right-multiplies and thus the order needs to be reversed to get the same effect. So when we need LookAt first and Perspective next, we do the reverse to get the expected result.

    Giving the two in right order leads to

    P' = View × Projection × Model × P

    since matrix multiplication is anti-commutative, you don't get the right P' which falls within the canonical view volume and hence black screen.

    See the Chapter 3, Red Book, under the section General-Purpose Transformation Commands which explains the order followed by OpenGL. Excerpt:

    Note: All matrix multiplication with OpenGL occurs as follows: Suppose the current matrix is C and the matrix specified with glMultMatrix*() or any of the transformation commands is M. After multiplication, the final matrix is always CM. Since matrix multiplication isn't generally commutative, the order makes a difference.


    I want to know why the first case works but the second doesn't.

    To know what really happens with the matrix formed of incorrect order, lets do a small workout in 2D. Lets say the canonical view region is [−100, 100] in both X and Y; anything outside this is clipped out. The origin of this imaginary square screen is at the centre, X goes right, Y goes up. When no transform is applied calling DrawImage draws the image at the origin. You've an image which is 1 × 1; its model matrix is scaling by 200 so that it becomes a 200 × 200 image; one that fills the entire screen. Since origin is at centre of the screen, to draw the image such that it fills the screen, we need a view matrix that translates (moves) the image by (−100, −100). Formulating this

    P' = View × Model = Translate−100, −100 × Scale200, 200

    [ 200,  0,  −100 ]
    [  0,  200, −100 ]
    [  0,   0,   1   ]
    

    However, the result of

    Model × View = S200, 200 × T−100, −100

    [ 200,  0,  −20000 ]
    [  0,  200, −20000 ]
    [  0,   0,    1    ]
    

    Multiplying the former matrix with points (0, 0) and (1, 1) would result in (−100, −100) and (100, 100) as expected. The image corners would be aligned to the screen corners. However, multiplying the latter matrix with them would result in (−20000, −20000) and (−19800, −19800); well outside the viewable region. This is because, geometrically, the latter matrix first translates and then scales as opposed to scaling and then translating. The translated scale leads to a point that is completely off.