Search code examples
c++openglframe-rate

Building an FPS in OpenGL: My gun is being clipped agains the frustum


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.


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.