52852.fb2 A Monkeys Guide to Matrices - читать онлайн бесплатно полную версию книги . Страница 2

A Monkeys Guide to Matrices - читать онлайн бесплатно полную версию книги . Страница 2

Using matrices for transformations

In the sample app, each object has its own matrix which represents its placement in the scene relative to the origin. When the model draws, it first pushes the current gl matrix, then draws itself, then pops the matrix to restore things to how they were before it drew. (This isolates the effects of its drawing commands to the scope of the Push/Pop operations.) To draw, the model multiplies the current gl matrix by its own matrix, then draws itself, then draws the axis icon. The effect is that all primitives which the model draws are transformed by the cumulative matrix. This is exactly equivalent to issueing a series of glTranslate, glScale, and glRotate commands.

Public Matrix As CMatrix

Public Sub Draw()

 glPushMatrix

  Matrix.Apply 'call glMultMatrix

  glCallList ListID 'draw the model

  Matrix.Draw 'draw the axes

 glPopMatrix

End Sub

The camera drawing is a bit more complex, because it has 2 ways to draw – it can either 'draw' itself as the 'active camera' (i.e. as the viewing transform) or it can draw an icon of itself in the scene (when we are actually viewing from somewhere else). Let's look at the more typical case – drawing itself as the active camera – since this is what a camera is for.

The following code is (a somewhat edited version of) the main drawing routine in the 'CXXX' class:

Public Sub Draw()

Dim m!(0 To 15)

 glPushMatrix

  'draw camera

  Camera.Draw

  'draw grids

  With gCtl

   If m_Grids Then .DrawGrids

  End With

  'draw model

  Model.Draw

 glPopMatrix

 CheckError

End Sub

The camera matrix will provide the viewing transformation by multiplying the current gl matrix (which at this point happens to be the identity matrix) by its own matrix. This operation is equivalent to calling gluLookAt. If you look at the source for gluLookAt in the Mesa library, you will see that gluLookAt builds a transformation matrix m and then calls glMultMatrixd(m), which is exactly what our camera will do.

The values in the matrix, however, represent the position and orientation of the camera (because we are using the same matrix as the model). These values are the same values as the eye, center, and up values which would be used in a call to gluLookAt. If we were drawing the camera as an object in the scene, we would use this matrix. But we are trying to set the viewing transform, which is the inverse of a modeling transform (see pg. 100 in the Red Book for a discussion). So before we can use the matrix we must invert it. (The Push/Pop stuff is how the Matrix saves and restores its current matrix when making temporary changes to it.)

Public Sub Draw()

 Matrix.Push

 Matrix.Invert

 Matrix.Apply

 Matrix.Pop

End Sub

The effect of this is to transform the entire scene (all subsequent commands) by the opposite of the camera position. For example, if we are starting from 0,0,0, and we want the camera to be at 0,0,10, we move the entire scene by 0,0,-10. (The 'camera' is a fiction which just describes this matrix which is placed on the stack before the scene is drawn.)

The camera has a second drawing routine which it uses when it is not active. In this case, it behaves like the model except that its orientation must be reversed to reflect the viewing characteristics of the camera. I did this by just rotating 180 degrees. (This has the side-effect of reversing the sense of the keys, perhaps the Matrix class needs 'reflect' routine for this.)

Public Sub DrawIcon()

 glPushMatrix

  Matrix.Apply

  'draw the box for the camera

  glRotatef 180, 0, 1, 0

  glCallList ListID

  'draw the axes

  Matrix.Draw

 glPopMatrix

End Sub

In order to be able to see the camera in the scene as an object, the main drawing has a switch to choose between using gluLookAt or the camera to set the viewing transform:

If m_Free Then

 gluLookAt 0, 0, 10, _

  0, 0, 0, _

  0, 1, 0

Else

 Camera.Draw

End If