Jump to content
  • Advertisement
Sign in to follow this  
ScottNCSU

FPS issues with drawing quads, code included in post

This topic is 4843 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

My FPS starts at about 1000 without vsync in my current engine when I'm only drawing one human. A human is comprised of 14 GL_TEXTURE_2D quads, representing his limbs. I've found that my FPS decreases by about 30 if I add one more human and draw all his limbs, but only decreases by about 4-5 if I add a human and draw only his body, not his limbs. This leads me to conclude that my FPS issues are drawings those 13 extra quads, and not the physics/collision detection that is pretty optimized at this point. Each limb has to be translated and rotated before being drawn, but I'm assuming thats not whats killing the FPS. Also worth noting, my textures are compressed TGAs with alpha channels.
void DrawTargets(void)											// Draws The Targets (Needs To Be Seperate)
{
    glDisable(GL_CULL_FACE);
	glLoadIdentity();											// Reset The Modelview Matrix
	glTranslatef(0.0f,0.0f,-10.0f);								// Move Into The Screen 20 Units
	for (int loop=0; loop<163; loop++)						// Loop Through 9 Objects
	{
        if(object[loop].alive==true){	
     //Draw humanoid
        			           				
	//arm1		
    glPushMatrix();											// Push The Modelview Matrix
	glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
	glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object
    glTranslatef((0.24f*size[object[loop].texid].w),(0.18f*size[object[loop].texid].h),0.0f);    
    glTranslatef(0.0f,(0.44f*size[bodypart[loop][0].texid].h),0.0f);
	glRotatef(bodypart[loop][0].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.44f*size[bodypart[loop][0].texid].h),0.0f);
	Object(size[bodypart[loop][0].texid].w,size[bodypart[loop][0].texid].h,bodypart[loop][0].texid);	// Draw The Object	
	//forearm1
	glTranslatef(0.0f,(-0.143f*size[bodypart[loop][1].texid].h),0.0f);
	glTranslatef((-0.03f*size[bodypart[loop][8].texid].w),(-0.5f*size[bodypart[loop][1].texid].h),0.0f);
	glRotatef(bodypart[loop][1].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.5f*size[bodypart[loop][8].texid].h),0.0f);	
	Object(size[bodypart[loop][1].texid].w,size[bodypart[loop][1].texid].h,bodypart[loop][1].texid);	// Draw The Object		
	//hand1		
	glTranslatef(0.0f,(-0.06f*size[bodypart[loop][2].texid].h),0.0f);
	glTranslatef(0.0f,(-0.76f*size[bodypart[loop][2].texid].h),0.0f);
	glRotatef(bodypart[loop][2].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.76f*size[bodypart[loop][2].texid].h),0.0f);	
	Object(size[bodypart[loop][2].texid].w,size[bodypart[loop][2].texid].h,bodypart[loop][2].texid);	// Draw The Object		
	glPopMatrix();	
    
	  //leg1    										
	glPushMatrix();											// Push The Modelview Matrix
    glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
    glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object   
    glTranslatef((0.32f*size[object[loop].texid].w),(-1.1f*size[object[loop].texid].h),0.0f);
    glTranslatef(0.0f,(0.62f*size[bodypart[loop][3].texid].h),0.0f);
	glRotatef(bodypart[loop][3].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.62f*size[bodypart[loop][3].texid].h),0.0f);
	Object(size[bodypart[loop][3].texid].w,size[bodypart[loop][3].texid].h,bodypart[loop][3].texid);	// Draw The Object
	//calf1
	glTranslatef(0.0f,(-0.64f*size[bodypart[loop][4].texid].h),0.0f);
	glRotatef(bodypart[loop][4].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.64f*size[bodypart[loop][4].texid].h),0.0f);	
	Object(size[bodypart[loop][4].texid].w,size[bodypart[loop][4].texid].h,bodypart[loop][4].texid);	// Draw The Object
    //foot1
	glTranslatef((0.45f*size[bodypart[loop][5].texid].w),(-0.58*size[bodypart[loop][5].texid].h),0.0f);
	glRotatef(bodypart[loop][5].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.58*size[bodypart[loop][5].texid].h),0.0f);	
	Object(size[bodypart[loop][5].texid].w,size[bodypart[loop][5].texid].h,bodypart[loop][5].texid);	// Draw The Object		
	glPopMatrix();	    
    	
    //body
    glPushMatrix();	
    glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
	glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	//glRotatef(180,0.0f,1.0f,0.0f);
	Object(size[object[loop].texid].w,size[object[loop].texid].h,object[loop].texid);	// Draw The Object
	glPopMatrix();		
	
	//head
	glPushMatrix();											// Push The Modelview Matrix
    glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
    glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object
    glTranslatef((0.098*size[object[loop].texid].w),(1.02f*size[object[loop].texid].h),0.0f);
    glTranslatef(0.0f,(-0.81*size[bodypart[loop][6].texid].h),0.0f);
	glRotatef(bodypart[loop][6].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(0.81*size[bodypart[loop][6].texid].h),0.0f);
	Object(size[bodypart[loop][6].texid].w,size[bodypart[loop][6].texid].h,bodypart[loop][6].texid);	// Draw The Object
	glPopMatrix();	
	
	  //leg2    										
	glPushMatrix();											// Push The Modelview Matrix
    glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
    glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object
    glTranslatef((0.09f*size[object[loop].texid].w),(-1.1f*size[object[loop].texid].h),0.0f);
    glTranslatef(0.0f,(0.62f*size[bodypart[loop][10].texid].h),0.0f);
	glRotatef(bodypart[loop][10].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.62f*size[bodypart[loop][10].texid].h),0.0f);
	Object(size[bodypart[loop][10].texid].w,size[bodypart[loop][10].texid].h,bodypart[loop][10].texid);	// Draw The Object
	//calf2
	glTranslatef(0.0f,(-0.64f*size[bodypart[loop][11].texid].h),0.0f);
	glRotatef(bodypart[loop][11].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.64f*size[bodypart[loop][11].texid].h),0.0f);	
	Object(size[bodypart[loop][11].texid].w,size[bodypart[loop][11].texid].h,bodypart[loop][11].texid);	// Draw The Object
    //foot2
	glTranslatef((0.45f*size[bodypart[loop][12].texid].w),(-0.58*size[bodypart[loop][12].texid].h),0.0f);
	glRotatef(bodypart[loop][12].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.58*size[bodypart[loop][12].texid].h),0.0f);	
	Object(size[bodypart[loop][12].texid].w,size[bodypart[loop][12].texid].h,bodypart[loop][12].texid);	// Draw The Object		
	glPopMatrix();	
    	
	//arm2		
    glPushMatrix();											// Push The Modelview Matrix
	glTranslatef(object[loop].x,object[loop].y,object[loop].z);		// Position The Object (x,y)
	glRotatef(object[loop].spin,0.0f,0.0f,1.0f);		// Rotate The Object
    glTranslatef((-0.3f*size[object[loop].texid].w),(0.22f*size[object[loop].texid].h),0.0f);    
    glTranslatef(0.0f,(0.44f*size[bodypart[loop][7].texid].h),0.0f);
	glRotatef(bodypart[loop][7].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.44f*size[bodypart[loop][7].texid].h),0.0f);
	Object(size[bodypart[loop][7].texid].w,size[bodypart[loop][7].texid].h,bodypart[loop][7].texid);	// Draw The Object	
	//forearm2
	glTranslatef(0.0f,(-0.143f*size[bodypart[loop][8].texid].h),0.0f);
	glTranslatef((-0.03f*size[bodypart[loop][8].texid].w),(-0.5f*size[bodypart[loop][8].texid].h),0.0f);
	glRotatef(bodypart[loop][8].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.5f*size[bodypart[loop][8].texid].h),0.0f);	
	Object(size[bodypart[loop][8].texid].w,size[bodypart[loop][8].texid].h,bodypart[loop][8].texid);	// Draw The Object		
	//hand2		
	glTranslatef(0.0f,(-0.06f*size[bodypart[loop][9].texid].h),0.0f);
	glTranslatef(0.0f,(-0.76f*size[bodypart[loop][9].texid].h),0.0f);
	glRotatef(bodypart[loop][9].spin,0.0f,0.0f,1.0f);		// Rotate The Object
	glTranslatef(0.0f,(-0.76f*size[bodypart[loop][9].texid].h),0.0f);	
	Object(size[bodypart[loop][9].texid].w,size[bodypart[loop][9].texid].h,bodypart[loop][9].texid);	// Draw The Object		
	glPopMatrix();	
    
    }
}

*draw projectiles/animations/backgrounds etc...*
}

And here is Object(), standard quad drawing code:
void Object(float width,float height,GLuint texid)				// Draw Object Using Requested Width, Height And Texture
{
     
	glBindTexture(GL_TEXTURE_2D, textures[texid].texID);		// Select The Correct Texture
	glBegin(GL_QUADS);											// Start Drawing A Quad
		glTexCoord2f(0.0f,0.0f); glVertex3f(-width,-height,0.0f);	// Bottom Left
		glTexCoord2f(1.0f,0.0f); glVertex3f( width,-height,0.0f);	// Bottom Right
		glTexCoord2f(1.0f,1.0f); glVertex3f( width, height,0.0f);	// Top Right
		glTexCoord2f(0.0f,1.0f); glVertex3f(-width, height,0.0f);	// Top Left
	glEnd();													// Done Drawing Quad
}

Is there a way to optimize my code?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by ScottNCSU
My FPS starts at about 1000 without vsync in my current engine . . . my FPS decreases by about 30 if I add one more human . . . but I'm assuming thats not whats killing the FPS . . .
Going from 1000fps to 970fps is nothing, I wouldn't call that "killing the FPS". Don't worry TOO much about optimization until you start dropping below 60fps.

EDIT: For comparison, 1000fps -> 970fps means one frame goes from taking 1ms to taking ~1.0309278350515463917525773195876ms to render. That's not much slower.

Share this post


Link to post
Share on other sites
With 20 humans on the screen, its something, and I have a pretty high end computer. The target audience is people with low end computers that have basic OpenGL drivers, which is why my only extension used so far is V-sync. Once I add in AI for humans, the FPS will drop pretty harshly for low end computers I'm sure, and I want the game as optimized as possible.

Share this post


Link to post
Share on other sites
Are your models animated? If not you could easily put your OpenGL calls in a display list, or use vertex arrays/VBOs.

And a 3% decrease isn't much, even on a low-end PC. How much of a performance hit do you get with 20 models?

Share this post


Link to post
Share on other sites
Basically, the way to to get the fastest OpenGL code possible is to use the least function calls possible. There are a lot of ways to optimize this code, I see at least 3 big ones.

First:
Get rid of rendering via glVertex, glTexcoord, etc. This is typically the slowest way to render in GL, only fit for debugging purposes. I suggest you look in to a simple optimization: Display Lists This way, you can pack all of those vertices, texcoords, and normals in to a list, and render it all in a single GL call.

Second:
Consider picking up a math library and combining those rotations and transformations each in to just one matrix. Thus, when it comes time to render, you just multiply the current modelview by your stored matrix, and then draw the display list.

Now we're down to about 2 OpenGL calls per object, instead of 20+ each.

Third:
glBindTexture() is actually a relatively heavyweight call. In your case, this probably isn't a source of slowdown, but binding a texture for each quad is usually bad. Now fixing this isn't necessarily easy, you must take these objects, and sort them by the texture they use. This way objects that use the same texture already bound won't make a redundant call.

Just my .02

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottNCSU
With 20 humans on the screen, its something, and I have a pretty high end computer. The target audience is people with low end computers that have basic OpenGL drivers, which is why my only extension used so far is V-sync. Once I add in AI for humans, the FPS will drop pretty harshly for low end computers I'm sure, and I want the game as optimized as possible.
Alright, fair enough but I would concentrate more on good, clear design and gameplay before optimizing. Just a couple comments...

1) It's generally a bad idea to have numbered constants thrown around in your code (ie: for (int loop=0; loop<163; loop++) and glTranslatef((0.24f*size[object[loop].texid].w),(0.18f*size[object[loop].texid].h),0.0f)).

2) With all those array accesses it's VERY difficult to see what's going on in that code.

3) Binding textures is a costly state change, so it's probably better to do something like this, assuming all the characters use the same textures...
Bind body texture
Render all bodies
Bind arm texture
Render all arms
etc.
Or even better is to put all textures for a person into one larger texture, so you just need to bind one texture to render all your characters. The usual term for this is a texture atlas, so search google for that. Again that assumes all your characters use the same textures, if not you will need a texture atlas for each type of character, or you may be able to stuff them all into one very large texture atlas if the graphics card has support for a large enough texture. You can find the maximum texture size for the graphics card by calling glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize).

EDIT: And the other optimizations The Rug and Optus posted while I was posting. [grin]

Share this post


Link to post
Share on other sites
Worst case scenario, lets say 40 humans on the screen (10 of which will account for any background images or projectiles/explosions etc), I'm at 350 FPS. Lets say I add in AI and other non-graphical code, its probably going to be down to 300 FPS. I have a 3.2 GHz P4 with 1GB of RAM and a ATI 800se. On my brother's computer, a 2.0 GHz(?) with a built in video card an plenty of RAM, aka a $400 emachine, I believe he said it was going at 100 FPS with 50 humans on the screen. On an older machine it would be dangerously close to 60, the magic number, and I don't want this to happen.

Is there a good beginner's tutorial on display lists that you know of off the top of your head? Also, I wasn't aware using vertex arrays rather than an array of structs would speed up the process of making calls to them. I thought vertex arrays were simply more flexible.

EDIT:
As far as the texture atlas goes, this is an action RPG where the characters will be wearing different types of armor on each limb.

Share this post


Link to post
Share on other sites
Thanks guys, and thanks Optus: display lists was what I was looking for and I didn't know it. I had heard display lists mentioned before but for some reason thought they were for 3D games, due to the context where I saw them.

And if I'm still not hitting a fantastic FPS on lower end machines by the time I integrate display lists, I will use your other suggestions that will certiainly be painful to implement ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottNCSU
Also, I wasn't aware using vertex arrays rather than an array of structs would speed up the process of making calls to them. I thought vertex arrays were simply more flexible.
I'm not sure if you fully understand what vertex arrays are in regards to OpenGL. They basically enable you to send all per-vertex data (vertex positions, colors, normals, texture coordinates, etc) to the graphics card at the same time instead of calling glColor, glNormal, glTexCoord, glVertex inside a glBegin/glEnd block for each vertex you send. Display lists will be faster though because they are (usually) stored in video memory, but they are very static in nature. If you need to change vertex positions or whatever vertex arrays (or dynamic VBOs, but don't worry about those just yet) are the way to go. For static geometry go with display lists or static VBOs.

To learn more about vertex arrays, read the chapter on drawing geometry in the Red Book for version 1.1 or greater. The online version that I know of is for 1.0 so it doesn't have vertex arrays in it.

Hrm, hope that helped clarify things a little. Sometimes I can be very bad at describing things.

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!