First person view model rendering

In a first-person game, the player’s hand or weapon is often represented by a model called the “view model” in the terminology established by first-person shooters. One important consideration is that this view model does not intersect the world geometry when the player is close to a wall. It’s not always possible to limit the player’s movement so that this doesn’t happen, so special rendering methods are used to draw the view model.

The most obvious method is to draw the world first, clear the z-buffer and then draw the view model. This has a few disadvantages. The biggest one is that at end of the drawing process you don’t have a single z-buffer describing the entire scene.

This is important if you are using a deferred rendering process where the light volumes will need to be tested against the z-buffer. This method also requires an additional clear of the z-buffer and doesn’t take advantage of any early z-rejection for pixels blocked by the view model.

Fortunately there’s a different method which is very simple and avoids these problems. By manipulating the projection matrix, we can map the view model and the world into mutually exclusive parts of the z-buffer. First a little refresher on projection and the z-buffer (assuming Direct3D conventions, OpenGL is slightly different):

The result of transforming a point (x, y, z, 1) by the projection matrix is a homogenous vector (x’, y’, z’, w’). The z-buffer stores the value z’/w’, which is in the range 0 to 1 after clipping. For your run of the mill projection matrix, w’ = z, which is what you’re probably saving to the G-buffer if you’re doing deferred rendering. Our manipulation of the projection matrix should not affect x’, y’ or w’ so that everything else should continue to work properly.

To map to a sub-region of the z-buffer, we we want to apply another transformation to remap z’/w’ from the range [a, b] instead of [0, 1]:

z''/w'' = z'/w' \cdot (b - a) + a

or, since we require that w” = w’:

z'' = z' \cdot (b - a) + w' \cdot a

Finally, this can be easily expressed as a matrix multiplication:

  \left[ {\begin{array}{c}   x'' \\   y'' \\   z'' \\   w'' \\  \end{array} } \right]  =  \left[ {\begin{array}{c}   x' \\   y' \\   z' \cdot (b - a) + w' \cdot a \\   w' \\  \end{array} } \right]  =  \left[ {\begin{array}{cccc}   1 & 0 & 0 & 0  \\   0 & 1 & 0 & 0  \\   0 & 0 & b - a & a  \\   0 & 0 & 0 & 1  \\  \end{array} } \right]  \times  \left[ {\begin{array}{c}   x' \\   y' \\   z' \\   w' \\  \end{array} } \right]

To compute the final projection matrix, just pre-multiply the original projection matrix P with this adjustment matrix M:

  \left[ {\begin{array}{c}   x'' \\   y'' \\   z'' \\   w'' \\  \end{array} } \right]  =  M \times  \left[ {\begin{array}{c}   x' \\   y' \\   z' \\   w' \\  \end{array} } \right]  =  M \times P \times  \left[ {\begin{array}{c}   x \\   y \\   z \\   1 \\  \end{array} } \right]

Using a matrix that maps to [0, ε] for the view model and a matrix that maps to [ε, 1] for the world allows you to ensure they never overlap each other. Just keep in mind that you will be reducing the precision of your z-buffer this way, so try to make ε as small as possible.

4 Responses to “First person view model rendering”

  1. free fps games said:

    Apr 16, 13 at 9:57 pm

    Hi, this weekend is pleasant in favor of me, because this time i am reading this impressive educational paragraph here at my residence.

  2. Louie said:

    Apr 18, 13 at 3:37 am

    Everything is very open with a precise description of the issues.

    It was definitely informative. Your site is extremely
    helpful. Thanks for sharing!

  3. photography website said:

    Apr 18, 13 at 1:18 pm

    My relatives all the time say that I am wasting my time here at net, however I know I am getting familiarity everyday
    by reading such good content.

  4. crear facebook said:

    Jun 04, 13 at 9:28 am

    When some one searches for his vital thing, thus he/she wants to be available that in detail, so
    that thing is maintained over here.

Leave a Reply