Jump to content
  • Advertisement
Sign in to follow this  
mpledge52

Optimisation help

This topic is 3805 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all. I have a mighty favour to ask. Could someone have a look over my code and point out how and where I can optimise my code. It forms part of a project at uni so I'm working to a deadline so I didn't bother making efficient code at first as I needed something working initially, but now I have the majority of the code done I want to start improving performance. The program is basically a heightmap with the map data loaded from a text file, and then a few other things are drawn as well, such as place names and an aircraft for example. The code structure is basically as follows: 1- Load file 2- Import data into vertex array 3- Build colour array 4- Build index array 5- Enter display loop 6- Draw map 7- Draw other objects (plane, flightpath etc) 8- Check if we've gone out of bounds, if so, go back to step 1 9- Else, go back to step 5, continue until quit And here is the code:

void drawPlane(){

	glTranslatef(xPosPlane,yPosPlane,zPosPlane);
	glRotatef(xRotPlane, 0.0, 0.0, 1.0);
	glRotatef(yRotPlane, 1.0, 0.0, 0.0);

	//Draw Plane!
	glColor4f(1.0, 1.0, 1.0, 1.0);
	quadratic=gluNewQuadric();

	//Main part
	glPushMatrix();	 
	glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
	glRotatef(90.0,1.0,0.0,0.0); 
	gluCylinder(quadratic,700.0,700.0,5000.0,30,30);	
	glPopMatrix();

	//Back of plane
	glPushMatrix(); 
	glTranslatef(0.0, 3000.0, 0);
	glRotatef(90.0,0.0,1.0,0.0); 
	glRotatef(90.0,1.0,0.0,0.0); 
	gluCylinder(quadratic,50.0,700.0,3000.0,30,30);
	glPopMatrix();

	//Front of plane
	glPushMatrix(); 
	glTranslatef(0.0, -5000.0, 0);
	glRotatef(90.0,0.0,1.0,0.0); 
	glRotatef(90.0,1.0,0.0,0.0); 
	gluCylinder(quadratic,700.0,400.0,1300.0,30,30);
	glPopMatrix();

	//Nose of plane
	glPushMatrix(); 
	glTranslatef(0.0,-6210.0,0.0);
	gluSphere(quadratic,400.0,30,30);
	glPopMatrix();

	//Right Wing
	glPushMatrix();
	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); glVertex3f(7000.0, -1000.0, 0.0); 
	glTexCoord2f(0.0, 1.0); glVertex3f(7000.0, -1600.0, 0.0); 
	glTexCoord2f(1.0, 1.0); glVertex3f(700.0, -4000.0, 0.0); 
	glTexCoord2f(1.0, 0.0); glVertex3f(700.0, -1000.0, 0.0); 
	glEnd();
	glPopMatrix();

	//Left Wing
	glPushMatrix();	
	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); glVertex3f(-700.0, -1000.0, 0.0); 
	glTexCoord2f(0.0, 1.0); glVertex3f(-700.0, -4000.0, 0.0); 
	glTexCoord2f(1.0, 1.0); glVertex3f(-7000.0, -1600.0, 0.0); 
	glTexCoord2f(1.0, 0.0); glVertex3f(-7000.0, -1000.0, 0.0); 
	glEnd();
	glPopMatrix();

	//Right Engine
	glPushMatrix();	 
	glTranslatef(3500.0, -2000.0, 580);
	glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
	glRotatef(90.0,1.0,0.0,0.0); 
	gluCylinder(quadratic,500.0,500.0,1500.0,30,30);	
	glPopMatrix();

	//Left Engine
	glPushMatrix();	 
	glTranslatef(-3500.0, -2000.0, 580);
	glRotatef(90.0,0.0,1.0,0.0); //Rotate it to be parallel with ground
	glRotatef(90.0,1.0,0.0,0.0); 
	gluCylinder(quadratic,500.0,500.0,1500.0,30,30);	
	glPopMatrix();


}

void drawFlightPath(){

        //Loads of variables would be here

	y = getHeight(h, d, x);
	angle = atan((destLon-startLon)/(destLat-startLat));

	glColor4f(1.0, 1.0, 1.0, 0.6);
	for(int i=0; i<accuracy; i++){

		height = getHeight(h, d, (splitDistance*(i+1)));

		glPushMatrix();	
		glBegin(GL_QUADS);
		glTexCoord2f(0.0, 0.0); glVertex3f(startLon, startLat, currentHeight); 
		glTexCoord2f(0.0, 1.0); glVertex3f(startLon-2000, startLat, currentHeight); 
		glTexCoord2f(1.0, 1.0); glVertex3f(startLon-2000-(splitDistance*(tan(angle))), startLat-splitDistance, height); 
		glTexCoord2f(1.0, 0.0); glVertex3f(startLon-(splitDistance*(tan(angle))), startLat-splitDistance, height); 

	
		glEnd();
		glPopMatrix();

		startLon += -splitDistance*(tan(angle));
		startLat += -splitDistance;
		currentHeight = height;
	}

}


void fillArray(){

	FILE *filein;
	char oneline[255];
	char* c;
	float x, y, z;
	int j=0;
	int widthCount = 0;
	int heightCount = 0;


	filein = fopen(InFileTest, "rt");	

	while (heightCount < origMapHeight){
		if (heightCount%accuracyLevel==0){

			while (widthCount < origMapWidth){
				if (widthCount%accuracyLevel==0){

					c= fgets(oneline, 255, filein);
					sscanf(oneline, "%f, " "%f, " "%f, ", &x, &y, &z);

					vertices[j] = x;
					vertices[j+1] = y;
					vertices[j+2] = z;
					j +=3;
				}
				else
					c= fgets(oneline, 255, filein);
				
				widthCount++;
			}
			widthCount=0;
		}
		else{
			for (int i=0; i<origMapWidth; i++)  
				c= fgets(oneline, 255, filein);
		}
		heightCount++;
	}
	fclose(filein);
}


void setColors() {
	int j = 0;
	double ave = 0.0;
	int elev;

	for (int j = 0; j<HEIGHT; j++){
		for (int i = 0; i < WIDTH; i++){

			elev = vertices[((j*WIDTH+i)*3)+2];
                        if (elev == 0){ //Blue
				colors[(j*WIDTH+i)*3] = 0.000; //blue (sea)
				colors[((j*WIDTH+i)*3)+1] = 0.000;
				colors[((j*WIDTH+i)*3)+2] = 1.000;
			}
			if (0 < elev && elev <=50){
				colors[(j*WIDTH+i)*3] = 0.082; //v.dark green
				colors[((j*WIDTH+i)*3)+1] = 0.416;
				colors[((j*WIDTH+i)*3)+2] = 0.082;
			}
			if (50 < elev && elev <=100){
				colors[(j*WIDTH+i)*3] = 0.192; //dark green
				colors[((j*WIDTH+i)*3)+1] = 0.537;
				colors[((j*WIDTH+i)*3)+2] = 0.192;
			}
 .......etc
}


void makeIndex() {  

	
	int j = 0;
	int i = 0;

	for (int x =0; x < HEIGHT-1; x++){         
		for (int y=0; y < WIDTH-1; y++){ //Work left to right, move down a row, repeat        
			index = j; //First triangle in square
			index[i+1] = j+1;
			index[i+2] = j+(WIDTH)+1;

			index[i+3] = j;//Second triangle in square
			index[i+4] = j+(WIDTH);
			index[i+5] = j+(WIDTH)+1;                      

			i+=6;
			j++;
		}
		j++;
	}
}

void drawTicker(){

	int width = glutGet(GLUT_WINDOW_WIDTH);
	int height = glutGet(GLUT_WINDOW_HEIGHT);

	double xTick = width/10;
	double yTickBase = height/8.3; //Used to keep it in proportion
	double yTickTop = height/10;

	glColor4f(0.20, 0.20, 0.20, 1.0);
	glBegin(GL_QUADS);

	glTexCoord2f(0.0, 0.0); glVertex3f(-(width/xTick), -(height/yTickTop), -10.001); 
	glTexCoord2f(0.0, 1.0); glVertex3f(-(width/xTick), -(height/yTickBase), -10.001); 
	glTexCoord2f(1.0, 1.0); glVertex3f((width/xTick), -(height/yTickBase), -10.001); 
	glTexCoord2f(1.0, 0.0); glVertex3f((width/xTick), -(height/yTickTop), -10.001);

	glEnd();

	glColor4f(1.0, 1.0, 1.0, 1.0);
	glRasterPos3f(move, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , speedString);
	glRasterPos3f(move+8, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , altString);
	glRasterPos3f(move+17, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , distString);
	glRasterPos3f(move+31, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , tempString);
	glRasterPos3f(move+43, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , ETAString);
	glRasterPos3f(move+50, -9.2, -10);
	print_bitmap_string( GLUT_BITMAP_9_BY_15 , timeString);

	move = move -  0.05;
	if (move<=-59)
		move = 8;

}

void display (void){


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();

	if (loadCheck == 1){
		loadScreen();
		loadCheck = 0;
	}

	camera();

	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);
	glColorPointer(3, GL_FLOAT, 0, colors);
	glVertexPointer(3, GL_FLOAT, 0, vertices);
	glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_INT, index);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	drawLocations();
	drawFlightPath();

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	drawPlane();
	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);
	
        glLoadIdentity();
	drawTicker();

	glPopMatrix();
	glutSwapBuffers();
}


int main (int argc, char **argv)
{

	fillArray();
	setColors();
	scaleVertices();
	makeIndex();

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize(550, 550);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Testing");
	init();
	glutDisplayFunc(display);
	glutIdleFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc (keyboard);
	glutMainLoop();

	return 0;
}


There are quite a few functions that I've missed out so there may be a couple of things in there that may not make sense (variables not declared, unknown functions etc), but I think thats the main bulk of the code. I've put a couple of functions in like drawPlane() so you can see how I'm drawing things. I'm only really after anything that will give quite a large peroformance increase because I'm still working to a deadline so dont have that much time. I think I need to use VBO's or display lists but I really havent had chance to look at them in any depth. One final thing. The array sizes can be fairly large. I can have over 20 million points to draw so the vertex array is 60 million elements (the 3 dimensions of each point) so the colour array is also 60 million and the index array is 120 million, this is quite extreme though, normally I will be working with 1-5 million points. Thank you very much for any advice.

Share this post


Link to post
Share on other sites
Advertisement
You're rendering 1-5 million vertices each frame? That's quite a lot - and it seems like you really don't need that many - for any object. You might look into reducing this number if possible, for a couple of reasons:

1) At 1280 x 1024, that's as many vertices as there are pixels on your screen. The odds of more than one vertex mapping to any single pixel is very high - in other words, you have gone beyond the limit of what can be seen on the screen anyway.

2) If each vertex has position (3 floats), u-v coordinates (2 floats), normal (3 floats), and color (3 floats) - that's 44 bytes per vertex. Which means that 1 million vertices takes about 42MB of RAM. More importantly, you're copying 42MB of data into the video card every frame. Ugh.

What exactly are these arrays filled with, anyway? If most of it is terrain data, you might consider using a heightmap and texture instead. There are a few good algorithms (such as ROAM) to reduce the triangle count and give you a major performance boost.

[Edited by - klaymore142 on March 17, 2008 8:03:03 PM]

Share this post


Link to post
Share on other sites
Well the data I'm using is NASA's SRTM3 data. It looks like this:
-49.00041,-25.00041,898
-48.99708,-25.00041,920
-48.99375,-25.00041,933
-48.99042,-25.00041,954
-48.98709,-25.00041,975
-48.98376,-25.00041,964
-48.98043,-25.00041,969
-48.97710,-25.00041,1007

The first column is longitude, the second is latitude, the third is elevation (above sea level). I convert the longitude and latitude into metres and this gives me my 3D coordinates which I store in my vertex array. And yes each point has correspondeing values in the colour array and index array but I don't use a normal array.

Here is an example of the map zoomed in, the one on the left is full detail, and the one on the right is half detail, i.e. I take every other point from the file. As you can see there is quite a difference in the appearance, the lower detailed map looks far more 'blocky'.

image

You say I don't need that many points klaymore, so how do I reduce the number of vertices I'm drawing without recucing the quality like above?

Thanks.


Share this post


Link to post
Share on other sites
You appear to have large reasonably uniform areas on your map (same color and slope), where you don't actually need all these additional polygons. You can eliminate triangles using the following rule: if the common point of four connected quads is coplanar with the four adjacent vertices, then you can remove it.


+---+---+ +---+---+
| /|\ | | / \ |
| / | \ | | / \ |
|/ | \| |/ \|
+---+---+ ==> +-------+
|\ | /| |\ /|
| \ | / | | \ / |
| \|/ | | \ / |
+---+---+ +---+---+


Apply this method recursively to simplify your mesh. Also, google "GeoMipMapping".

Share this post


Link to post
Share on other sites
Thanks ToohrVyk, that makes sense, I do have lots of very similare terrain. This example is actually quite varied so other areas are almost entirley the same elevation (i.e. the sea) so I could represent the entire area with just 2 trangles.

The problem is I don't really know how I would actually implement this. I assume once you have loaded the points you iterate through the vertex array working out if a group of vertices are coplanar (not quite sure how you would do this), but the main thing is in the index array, because each row will have a different number of points in and therefore a sifferent number of triangles, e.g. one row might be able to be drawn using only 2 triangles but the next row may require 1000. How would you know where to draw the triangles??

Thanks.

Share this post


Link to post
Share on other sites
Thanks Klaymore, that's a very intersting read. Unfortunately I don't have anywhere enough time to start rewriting all my code. I would love to have a go at that when I have some spare time.

Is there anything else on a smaller, simpler scale that will improve my performance?

Thanks again.

Share this post


Link to post
Share on other sites
Here's an idea - use the color data to create an OpenGL texture, at full resolution. Then use only half or 1/4 of the vertices, but texture-mapped (instead of specifying a color for each vertex, specify texture coordinates). You can play with the resolution of the image and how many vertices you render, until you get a good balance.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!