I have had this problem for a while now and I've searched everywhere for an answer to no avail. Maybe I'm terrible at using Google, enlighten me if you please. Anyway, on with the problem.
Basically, I have a really low polygon house, which is rendered as triangles using glDrawElements(). It is actually drawn with two glDrawElements() calls, since the model is split into two different parts to draw the brick and slate textures on the seperate parts of the house. The textures used are 256 x 256 in size, as shown below:
http://img716.imageshack.us/img716/1228/brick.png
http://img97.imageshack.us/img97/570/slate.png
Quick PC spec:
Windows 7
2.4GHz Intel Q6600 Quad Core
NVidia GeForce 9600GT 512MB GDDR3
3GB Memory
Compiler:
Visual C++ 2008 Express
The application renders really smoothly when the house is at a distance, such as in the screenshot below:
http://img30.imageshack.us/img30/6469/housesmall.png
However, once the house gets closer, and the triangles take up more of the screen, the application runs slower and slower until the triangles fill the window, in which it starts running at about 10fps. The screenshot below ran at about 12.5fps:
http://img41.imageshack.us/img41/4859/houselarge.png
When textures are enabled, this problem really slows the application down. There is a very small slow down in the close up situation with no textures, but it is a lot smaller.
Also, I should note that if part of the window is placed part way off the screen while the house is really close, the application speeds up to almost full speed. Therefore, there is something wrong with SDL_GL_SwapBuffers() when OpenGL is required to render pixels that take up most of the window.
Below is a quick profile result (Time units are milliseconds):
http://img203.imageshack.us/img203/1290/profilem.png
Disregard the large 'new'/'delete' count, they are done during calling reserve() on a vector in setupLighting(), which is a function that makes no difference to the problem (I have tried removing it during certain tests).
The highlighted row is the SDL_GL_SwapBuffers() command, which is executing at an average of 81 milliseconds, or 12.5fps. Of course, I wouldn't believe SDL_GL_SwapBuffers() is the problem, it will be somewhere in my own code, but I can't think for my life what it is. Maybe blazingly obvious, who knows, heres some code anyway, see what you can find. All classes I have created have the 'cge' prefix, just for the record.
Here is my window creation member function, which simply sets up the SDL window ready for OpenGL rendering
void cgeRenderWindow::initialize()
{
if(SDL_Init(SDL_INIT_EVERYTHING) != CGE_SDL_INIT_SUCCESSFUL)
exit(0);
GLuint renderFlags;
if(mWindowMode == CGE_WINDOWED)
renderFlags = SDL_OPENGL;
else
renderFlags = SDL_OPENGL | SDL_FULLSCREEN;
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, CGE_DOUBLE_BUFFERING_ENABLE);
mRenderSurface = SDL_SetVideoMode(mWindowWidth, mWindowHeight, mWindowMode, renderFlags);
}
cgeScene::initialize() sets up OpenGL as follows.
void cgeScene::initialize() const
{
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glFrontFace(GL_CW);
glShadeModel(GL_SMOOTH);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClearColor(mClearColor.mRed, mClearColor.mGreen, mClearColor.mBlue, mClearColor.mAlpha);
disableAllLights();
mCamera.initialize();
}
Commenting out glEnable(GL_TEXTURE_2D) here vastly improves the speed of the close up geometry, though it still runs slower than at a distance.
mCamera.initialize() calls cgeCamera::initialize(), which sets up the viewport. It uses a rectangle class I made which returns floats, that explains the casts made, though that matters not.
void cgeCamera::initialize() const
{
// Rectangle coordinates are floats, glViewport takes ints (GLsizei = int), convert appropriately
glViewport(static_cast<GLint>(mViewportBoundary.mBottomLeftCorner.mX), static_cast<GLint>(mViewportBoundary.mBottomLeftCorner.mY), static_cast<GLint>(mViewportBoundary.getWidth()), static_cast<GLint>(mViewportBoundary.getHeight()));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Division by 0 avoidance
GLfloat aspectRatio(mViewportBoundary.getWidth() / (mViewportBoundary.getHeight() == 0 ? 1 : mViewportBoundary.getHeight()));
// Creates a projection matrix using the corresponding parameter values
gluPerspective(mFieldOfView, aspectRatio, mNearPlane, mFarPlane);
glMatrixMode(GL_MODELVIEW);
}
The main rendering function. Called once per loop of the infinite loop in main.
void cgeScene::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
cgeMatrix cameraTranslationMatrix;
cameraTranslationMatrix.setTranslation(-mCamera.mPosition);
glMultMatrixf((cameraTranslationMatrix * mCamera.mRotationMatrix).mMatrix);
for(GLuint modelInstance = 0; modelInstance < mModelInstances.size(); modelInstance++)
{
glPushMatrix();
//setupLighting(mModelInstances[modelInstance].mPosition);
mModelInstances[modelInstance].draw();
glPopMatrix();
}
SDL_GL_SwapBuffers();
}
setupLighting() makes a very small difference to the speed, but I commented it out just to make sure. All matrix multiplications make very little difference, I have tried commenting those out also in previous tests.
That leaves cgeModelInstances::draw(). Only one model instance is drawn, which is the house shown. The model parts contain triangle information used in the glPointer() functions, each model part corresponding to a certain material (in this case, this is 2 model parts for the 2 textures). Here is cgeModelInstances::draw().
void cgeModelInstance::draw()
{
cgeMatrix modelTranslationMatrix;
modelTranslationMatrix.setTranslation(mPosition);
glMultMatrixf((modelTranslationMatrix * mRotationMatrix).mMatrix);
// Draw each model part
for(GLuint i = 0; i < mModel->getModelParts().size(); i++)
{
glVertexPointer(CGE_VERTEX_DIMENSIONS, GL_FLOAT, 0, &(mModel->getModelParts().getVertecies()[0]));
glNormalPointer(GL_FLOAT, 0, &(mModel->getModelParts().getNormals()[0]));
glTexCoordPointer(CGE_TEXTURE_DIMENSIONS, GL_FLOAT, 0, &(mModel->getModelParts().getTextureCoordinates()[0]));
//glColor4f(mColor.mRed, mColor.mGreen, mColor.mBlue, mColor.mAlpha);
// If there is no texture, unbind
if(!mModel->getModelParts().mTexture)
glBindTexture(GL_TEXTURE_2D, CGE_NO_TEXTURE);
else
glBindTexture(GL_TEXTURE_2D, mModel->getModelParts().mTexture->getIdentifier());
glDrawElements(GL_TRIANGLES, mModel->getModelParts().getIndecies().size(), GL_UNSIGNED_INT, &(mModel->getModelParts().getIndecies()[0]));
}
}
Again, the matrix multiplication makes very little difference to the speed.
My textures are created as follows.
// Generate a new texture object and bind to it
glGenTextures(1, &mIdentifier);
glBindTexture(GL_TEXTURE_2D, mIdentifier);
// Create the texture from the pixel data (located at the address of pixelData[0])
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, &pixelData[0]);
// Set the parameters for this new texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Note that I have used the 256 constant here to make sure they are 256 x 256 textures, though they are anyway, so this shouldn't make any difference.
I was wondering if anyone else has had this close up texture problem before, whether it's a common problem or if it's my code. If you need more information, feel free to ask.
[Edited by - thekilla1234 on March 16, 2010 9:31:49 AM]