Question

I am writing a terrain engine that has a lot of large textures draped over a heightmap. These textures are generated by rendering a bunch of stuff and then using the glCopyTexSubImage2D command a few times.

All fine and well (on speed and quality fronts), but when I make a lot of them (>45 1Mpixel) my framerate takes a nosedive from 60 to about 2. My first thought is that, well something (GPU or CPU) has to be pulling all million pixels per texture each time it is rendered which would definitely slow it down, so I tried what I thought was the solution: to implement mipmapping.

So I pull all the rgb values into an array and repass it into gluBuild2DMipmaps. (Is this not wasteful? I ask for some data and then give it right back? Is there a better way to do this with what I have (see below)).

Now, the mid-distant textures look terrible and bland and I am no better on the speed front.

Is there some way to get more detail on the further out textures while speeding up my rendering? Bear in mind that I am using freeglut and so am rather limited to opengl 2.

[EDIT: some code samples]

The generation of the texture:

//Only executes once as then the texture is defined.
if (TextureNumber == -1)
{
    glGenTextures (1, &TextureNumber); 
    glBindTexture(GL_TEXTURE_2D, TextureNumber);

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    // ... Other not directly related stuff
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
}
//The texture is built up a little bit at a time, over a number of calls.

// Do some rendering
// ...
glBindTexture(GL_TEXTURE_2D, TextureNumber);
//And copy it into the big texture
glCopyTexSubImage2D (GL_TEXTURE_2D, 0, texX * _patch_size, texY * _patch_size, 0, 0, _patch_size, _patch_size);

Finally, this is run once:

unsigned char* dat = new unsigned char [TEXTURE_SIZE*TEXTURE_SIZE*3];
glBindTexture(GL_TEXTURE_2D, TextureNumber);
glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,dat);
gluBuild2DMipmaps(GL_TEXTURE_2D,3,TEXTURE_SIZE,TEXTURE_SIZE,GL_RGB,GL_UNSIGNED_BYTE,dat);
finishedTexture = true;
delete[] dat;

The rendering:

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor3f(1,1,1);
glVertexPointer( 3, GL_FLOAT, 0, VertexData);   
glTexCoordPointer(2, GL_FLOAT, 0, TextureData);
glBindTexture(GL_TEXTURE_2D, TextureNumber);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glDrawElements( GL_TRIANGLES, //mode
              numTri[detail],  //count, ie. how many indices
              GL_UNSIGNED_INT, //type of the index array
              TriangleData[detail]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
Was it helpful?

Solution

First way to speed up that code is to get rid of all functions that are from 20 years ago and convert it to shaders. Fixed pipeline can be very unoptimal on modern hardware, and constant sending data to GPU is also probably killing the performance.

Bear in mind that I am using freeglut and so am rather limited to opengl 2.

No, that's not true. Freeglut is concerned mostly with window and context creation, and you can still use GLLoad or GLEW to get OGL 3.x or 4.x functions.

A quick list of things I see:

  • Fixed pipeline state used glColor
  • No VBO used / combined with deprecated glVertexPointer
  • Perhaps FBO should be used to fill the textures initially?
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top