Optimizing Terrain Drawing?
is there any way to optomize this, and no it doesnt take into account the different textures or y positions yet. It just seems to draw to slowly on larger maps
Code:
- (void) compileGround
{
int i,j;
glDeleteLists( groundCallList, 1 ); // Clearing Ground From Previous Game
groundCallList = glGenLists( 1 ); // Generating New List
glNewList( groundCallList, GL_COMPILE ); // Telling OpenGL To Compile The List
glEnable( GL_CULL_FACE ); // Enable Cull Facings
glCullFace( GL_FRONT ); // Telling OpenGL We Want To Draw The Fronts Of The Objects
glPolygonMode( GL_FRONT, GL_FILL ); // Drawing And Filling Only The Front Of The Polygons
glEnable( GL_TEXTURE_2D ); // Enabling Textures
glEnable( GL_DEPTH_TEST ); // Enableing Depth Testing
glColor3d( 1.0, 1.0, 1.0 ); // Setting It So That No Color Displacment Is Caused
// Terrain
glBindTexture( GL_TEXTURE_2D, terrainTextures[ 0 ].texID );
for( i = 0; i < map.width; i++ )
{
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( 0, 1 );
glVertex3d( i*0.5, 0, 0 );
glTexCoord2f( 1, 1 );
glVertex3d( (i+1)*0.5, 0, 0 );
for( j = 0; j < map.depth; j++ )
{
glTexCoord2f( i, j );
glVertex3d( i*0.5, 0, (j+1)*0.5 );
glTexCoord2f( i+1, j );
glVertex3d( (i+1)*0.5, 0, (j+1)*0.5 );
}
glEnd();
}
glDisable( GL_CULL_FACE ); // Disableing Cull Facings
glEndList(); // Telling OpenGL We Are Done With The List
}
Random guess: could you put the glBegin and glEnd outside the for loop so that you send the vertices in one big batch?
Do you really need the double precision?
Switching from vertex3d() to vertex3f() calls should be somewhat faster, since all the memory accesses would be split in half. Also, in my personnal experience, unless you want really realistic physics ( or unless you terrain is ridiculously large ), doubles are completly overkill.
HTH.
Switching from vertex3d() to vertex3f() calls should be somewhat faster, since all the memory accesses would be split in half. Also, in my personnal experience, unless you want really realistic physics ( or unless you terrain is ridiculously large ), doubles are completly overkill.
HTH.
Slightly OT:
If you want to see this in action, take a look at the Yoink source code. There's a preprocessor switch which swaps between using single and double precision, but it runs at the same speed in either case.
Remember, measure before you optimise!
Sohta Wrote:Switching from vertex3d() to vertex3f() calls should be somewhat faster, since all the memory accesses would be split in half.Logically, you might expect that to be the case. In practice I've always found that it makes no appreciable difference when there's any other time consuming operation in the loop (such as rendering).
If you want to see this in action, take a look at the Yoink source code. There's a preprocessor switch which swaps between using single and double precision, but it runs at the same speed in either case.
Remember, measure before you optimise!
True.
But the main problem ( on BIG maps ) are the shear number of polys ( already 32768 for a 128 * 128 map ), and there's not much going around that.
What you CAN do is: when you compile the display list, you find wich adjacent polys are coplanar. These polygons can then be rendered as one single polygon. So a flat surface wouldn't uselessly use polygons in that case. Compiling the display list would be longer, since you would have to pass at least two times trough the whole terrain matrix, but the rendering of the terrain would ( should, there might be exceptions ) be faster.
In my opinion, that's a lot of trouble, but it would be a nice optimisation.
Come to think of it, you can also split your terrain in multiple small terrains, and then do some frustrum culling ( i.e. not draw a terrain that is behind the camera ).
Good Luck!
But the main problem ( on BIG maps ) are the shear number of polys ( already 32768 for a 128 * 128 map ), and there's not much going around that.
What you CAN do is: when you compile the display list, you find wich adjacent polys are coplanar. These polygons can then be rendered as one single polygon. So a flat surface wouldn't uselessly use polygons in that case. Compiling the display list would be longer, since you would have to pass at least two times trough the whole terrain matrix, but the rendering of the terrain would ( should, there might be exceptions ) be faster.
In my opinion, that's a lot of trouble, but it would be a nice optimisation.
Come to think of it, you can also split your terrain in multiple small terrains, and then do some frustrum culling ( i.e. not draw a terrain that is behind the camera ).
Good Luck!
okay ive optomized the code a bit, it now will now combine the like polygons along the z axis, any idea on how i may do the x axis?
Code:
- (void) compileGround
{
int i,j,currentType,count;
float currentYPos[ 2 ];
glDeleteLists( groundCallList, 1 ); // Clearing Ground From Previous Game
groundCallList = glGenLists( 1 ); // Generating New List
glNewList( groundCallList, GL_COMPILE ); // Telling OpenGL To Compile The List
glEnable( GL_CULL_FACE ); // Enable Cull Facings
glCullFace( GL_FRONT ); // Telling OpenGL We Want To Draw The Fronts Of The Objects
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); // Drawing And Filling Only The Front Of The Polygons
glEnable( GL_TEXTURE_2D ); // Enabling Textures
glEnable( GL_DEPTH_TEST ); // Enableing Depth Testing
glColor3d( 1.0, 1.0, 1.0 ); // Setting It So That No Color Displacment Is Caused
// Terrain
glBindTexture( GL_TEXTURE_2D, terrainTextures[ 0 ].texID );
for( i = 0; i < map.width; i++ )
{
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( i, 0 );
glVertex3f( i*0.5, map.yPositions[ i ][ 0 ], 0 );
glTexCoord2f( i+1, 0 );
glVertex3f( (i+1)*0.5, map.yPositions[ i+1 ][ 0 ], 0 );
currentYPos[ 0 ] = map.yPositions[ i ][ 0 ]; // Settings Up New CurrentY
currentYPos[ 1 ] = map.yPositions[ i+1 ][ 0 ]; // Settings Up New CurrentY
currentType = map.tilesType[ i ][ 0 ]; // Setting Up Current Type Type
for( j = 0; j < map.depth; j++ )
{
if( !(map.yPositions[ i ][ j+1 ] == currentYPos[ 0 ]) || !(map.yPositions[ i+1 ][ j+1 ] == currentYPos[ 1 ]) || !(map.tilesType[ i ][ j+1 ] == currentType) || j == map.depth-1 )
{
glTexCoord2f( i, -j );
glVertex3f( i*0.5, map.yPositions[ i ][ j+1 ], (j+1)*0.5 );
glTexCoord2f( i+1, -j );
glVertex3f( (i+1)*0.5, map.yPositions[ i+1 ][ j+1 ], (j+1)*0.5 );
currentYPos[ 0 ] = map.yPositions[ i ][ j+1 ]; // Settings Up New CurrentY
currentYPos[ 1 ] = map.yPositions[ i+1 ][ j+1 ]; // Settings Up New CurrentY
currentType = map.tilesType[ i ][ j+1 ]; // Setting Up Current Type Type
count +=1;
}
}
glEnd();
}
NSLog( @"Polygons:%d",count );
glDisable( GL_CULL_FACE ); // Disableing Cull Facings
glEndList(); // Telling OpenGL We Are Done With The List
}
Well, the first thing I would do is get rid of triangle strips, just use gltriangles. It's not the fastest path on a lot of hardware. Use a display list for static terrain, a form of vertex array for dynamic terrain. Should give a nice speed boost.
DoG Wrote:Well, the first thing I would do is get rid of triangle strips, just use gltriangles. It's not the fastest path on a lot of hardware. Use a display list for static terrain, a form of vertex array for dynamic terrain. Should give a nice speed boost.
how could GL_TRIANGLES be faster than GL_TRIANGLE_STRIP when GL_TRIANGLES costs 3n (n = number of verticies) and GL_TRIANGLE_STRIP costs n+2?
'cos Q3A uses GL_TRIANGLES for everything 
It's also a bit easier for the display list optimizer, I believe.
Also remember that a strip longer than 65535 triangles falls back into slow mode, even in a display list, on all versions of Mac OS X so far...

It's also a bit easier for the display list optimizer, I believe.
Also remember that a strip longer than 65535 triangles falls back into slow mode, even in a display list, on all versions of Mac OS X so far...
okay now i got it to where it is quite quick by drawing only the tiles that are on the screen. Now if i could somehow check the x axis vertexs as well
Code:
- (void) drawBackground
{
int i,j,currentType;
float currentYPos[ 2 ],light;
glEnable( GL_LIGHTING ); // Enable Lighting
glEnable( GL_LIGHT0 ); // Enable Light 0
/*
* Dealing With Daylight
if( countUp )
daytime += 0.005;
else
daytime -= 0.005;
if( daytime >= 2.0 )
countUp = FALSE;
if( daytime <= -1.0 )
countUp = TRUE;
light = daytime;
if( daytime < 0 )
light = 0;
if( daytime > 1 )
light = 1;
*/
light = 0.5;
float ambientLight[] = { light, light, light, 0.5f };
glLightfv( GL_LIGHT0, GL_AMBIENT, ambientLight ); // Turning Lighting On
glEnable( GL_CULL_FACE ); // Enable Cull Facings
glCullFace( GL_FRONT ); // Telling OpenGL We Want To Draw The Fronts Of The Objects
glPolygonMode( GL_FRONT, GL_FILL ); // Drawing And Filling Only The Front Of The Polygons
glEnable( GL_TEXTURE_2D ); // Enabling Textures
glEnable( GL_DEPTH_TEST ); // Enableing Depth Testing
glColor3d( 1.0, 1.0, 1.0 ); // Setting It So That No Color Displacment Is Caused
// Terrain
glBindTexture( GL_TEXTURE_2D, terrainTextures[ 0 ].texID );
for( i = [ self max:0 p2:(camera.x*2)-18 ]; i < [ self min:map.width p2:(camera.x*2)+18 ]; i++ )
{
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( i, 0 );
glVertex3f( i*0.5, map.yPositions[ i ][ 0 ], 0 );
glTexCoord2f( i+1, 0 );
glVertex3f( (i+1)*0.5, map.yPositions[ i+1 ][ 0 ], 0 );
currentYPos[ 0 ] = map.yPositions[ i ][ 0 ]; // Settings Up New CurrentY
currentYPos[ 1 ] = map.yPositions[ i+1 ][ 0 ]; // Settings Up New CurrentY
currentType = map.tilesType[ i ][ 0 ]; // Setting Up Current Type Type
for( j = [ self max:0 p2:(camera.z*2)-26 ]; j < [ self min:map.depth p2:(camera.z*2)-2 ]; j++ )
{
if( !(map.yPositions[ i ][ j+1 ] == currentYPos[ 0 ]) || !(map.yPositions[ i+1 ][ j+1 ] == currentYPos[ 1 ]) || !(map.tilesType[ i ][ j+1 ] == currentType) || j == [ self min:map.depth p2:(camera.z*2)-2 ]-1 )
{
glTexCoord2f( i, -j );
glVertex3f( i*0.5, map.yPositions[ i ][ j+1 ], (j+1)*0.5 );
glTexCoord2f( i+1, -j );
glVertex3f( (i+1)*0.5, map.yPositions[ i+1 ][ j+1 ], (j+1)*0.5 );
currentYPos[ 0 ] = map.yPositions[ i ][ j+1 ]; // Settings Up New CurrentY
currentYPos[ 1 ] = map.yPositions[ i+1 ][ j+1 ]; // Settings Up New CurrentY
currentType = map.tilesType[ i ][ j+1 ]; // Setting Up Current Type Type
}
}
glEnd();
}
glDisable( GL_CULL_FACE ); // Disableing Cull Facings
glDisable( GL_LIGHTING );
glDisable( GL_LIGHT0 );
}
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Optimizing CGLFlushDrawable | Nick | 3 | 3,294 |
Nov 27, 2006 06:48 PM Last Post: OneSadCookie |
|
| Optimizing rendering. | jorgemonti | 15 | 5,420 |
Apr 6, 2005 04:05 AM Last Post: jorgemonti |
|
| Optimizing for OpenGL on OS X | aaronsullivan | 3 | 3,113 |
Mar 22, 2005 02:36 PM Last Post: Puzzler183 |
|
| optimizing dynamic geometry | arekkusu | 15 | 6,748 |
Nov 27, 2003 12:29 PM Last Post: OneSadCookie |
|
| optimizing OpenGL | ghettotek | 20 | 7,608 |
Feb 25, 2003 05:47 PM Last Post: henryj |
|

).
