Question

I'm building a first person shooter using OpenGL, and I'm trying to get a gun model to float in front of the camera. I've ripped a model from Fallout 3 using a resource decompiler (converted to .obj and loaded in).

However, this is what it looks like on the screen:

Screenshot

Half the gun's triangles are clipped to what appears to be the frustum.

I put it in front of my camera like this:

glPushMatrix();
    glLoadIdentity();

    glTranslatef(m_GunPos.x, m_GunPos.y, m_GunPos.z);
    glRotatef(m_GunRot.x, 1, 0, 0);
    glRotatef(m_GunRot.y, 0, 1, 0);
    glRotatef(m_GunRot.z, 0, 0, 1);
    glScalef(m_GunScale.x, m_GunScale.y, m_GunScale.z);

    m_Gun->Render(NULL);
glPopMatrix();

So I save the original GL_MODELVIEW matrix, load the identity matrix, translate my gun to be slightly to the right of my camera and render it. This is my render routine for a SceneNode:

glPushMatrix();
    if (m_Model) { m_Model->Render(&final); }

    if (m_Children.size() > 0)
    {
        for (std::vector<SceneNode*>::iterator i = m_Children.begin(); i != m_Children.end(); ++i)
        {
            (*i)->Render(&final);
        }
    }
glPopMatrix();

So it renders its own model and any child SceneNode's. Finally, the actual mesh rendering looks like this:

if (m_Material)
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, m_Material->m_TexDiffuse);
}

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glVertexPointer(3, GL_FLOAT, sizeof(Vec3), &m_Vertex[0]);
glNormalPointer(GL_FLOAT, sizeof(Vec3), &m_Normal[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &m_UV[0]);

glDrawArrays(GL_TRIANGLES, 0, m_Vertex.size());

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

Is there any way to turn off clipping for just the gun? How do other games do this?

Thanks in advance.

Was it helpful?

Solution

From the perspective (no pun intended) of OpenGL, the frustrum is just another matrix. You should be able to push the projection matrix, call gluPerspective (or glFrustrum, if you're adventurous) to set znear to a very small value, draw the gun, then pop the projection matrix and draw the rest of the scene (beware, however, that the projection matrix stack is often pretty shallow -- it can be as little as two levels).

One caveat: I've never really thought through how this should affect z-fighting. It might not do any real good -- it could work out the same as if you had the smaller znear value while drawing the whole scene.

OTHER TIPS

The problem is caused by the near-clipping plane.

Reduce the znear value you've used to calculate your projection matrix. Only make it as low as needed though. The lower it is, the more problems with z-fighting you will get.

Did you try pushing your gun further into the scene (ie: away from the camera)? When you do so, are the polygon still clipped? If no, then, as suggested your model is being clipped by the near clipping place (set in your projection matrix). If you still have artifacts, the problem could be anything else from render states, model loading, etc, etc.

Have you seen the entire model in some viewer? Maybe that's how the model looks and the poly count was optimized because you need see those polys in the game

Why not just push the gun farther into the scene and scale it up so that it doesn't clip against the near plane?

You have to specify a different near-far clip plane when you render close objects, such as a weapon hold by a character. This would cause the window-space depth values of the fragments to be invalid with respect to your other scene elements, so you have also have to modify the target depth range by calling glDepthRange. This will give you increase precision in camera near objects.

As you have mentioned, only modifying the near-far planes of your general scene frustum is not a solution, nor moving the gun forwards/backwards, since they introduce z-fighting issues.

"Layering" with different projection matrix can be dangerous if you're not careful since the depth values between the different layers aren't in the same "space". What I'm calling a layer here is a group of objects rendered with a given projection matrix. There are usually 2 solutions to this:

  1. Render your different layers (with all the objects on them) starting from the furthest away and clearing the depth buffer between each renders.
  2. Partition the depth buffer between your layers using glDepthRange.

Note that using any of these techniques will allow you so fix potential issues with objects from different layers fighting together but there some drawbacks:

  1. It prevent objects from intersecting one another (near layers will always appear on top of further layers - they'll never intersect). Sometimes it's something that you wish to achieve anyway with fps where the gun is always on top of everything
  2. Your depth buffer will be unusable for stuff like postfx (depth of field, etc) or deferred rendering.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top