Archived

This topic is now archived and is closed to further replies.

Low FPS and texture problems

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

Hi folks, I'm currently developing some sort of human animation and i'm using old Quake 2 animation style. (based on keyframes and linear interpolating between them). The problem is that when I only render the animated model i'm getting only 15 fps on a Geforce 4 MX440. Then i started to draw some other models like table, lamps, couch...but then the frame rate dropped to 9. I've applied a TGA texture to the floor and backwalls and so my fps is now 1-2 !!! My model is a hi-poly one, it has kind of 15000 verts and about 24000-25000 faces...Below is the code how I'm drawing the models.
void CSMFModel::RenderModel()
{

	float t;

	CSMFFrame *pCurrentFrame; /// this holds the current frame of the animation

	CSMFFrame *pNextFrame;	/// this holds the next frame (the one we will interpolate to)


	/// gets next frame of animation

	int nextFrame = (this->currentFrame + 1) % this->numOfFrames;

	/// gets the current frame

	pCurrentFrame = &(this->pFrames[this->currentFrame]);
	/// gets next frame (the one we will interpolate to)

	pNextFrame	  = &(this->pFrames[nextFrame]);

	t = ReturnCurrentTime(nextFrame);	

	/// iterate through all the nodes rendering its triangles

	for (int n=0; n<pCurrentFrame->numOfNodes; n++)
	{

		/// tests to see if the node list isn't empty

		if (pCurrentFrame->pNodes.size() <= 0) break;

		/// gets the current node

		CSMFNode *pCurrentNode = &pCurrentFrame->pNodes[n];
		CSMFNode *pNextNode = &pNextFrame->pNodes[n];

		/// go through all the faces rendering its associated vertices

		for (int j=0; j<pCurrentNode->numOfFaces; j++)
		{
			glBegin(GL_TRIANGLES);
			for (int vIndex=0; vIndex < 3; vIndex++)
			{
				long index  = pCurrentNode->pFaces[j].vertIndex[vIndex]-1;
				long nindex = pCurrentNode->pFaces[j].vertIndex[vIndex]-1;

				glNormal3f( pCurrentNode->pNormals[ index ].x + t * (pNextNode->pNormals[ nindex ].x - pCurrentNode->pNormals[ index ].x),	
					        pCurrentNode->pNormals[ index ].y + t * (pNextNode->pNormals[ nindex ].y - pCurrentNode->pNormals[ index ].y), 
							pCurrentNode->pNormals[ index ].z + t * (pNextNode->pNormals[ nindex ].z - pCurrentNode->pNormals[ index ].z));
				glVertex3f( pCurrentNode->pVertex[ index ].x + t * (pNextNode->pVertex[ nindex ].x - pCurrentNode->pVertex[ index ].x), 	
					        pCurrentNode->pVertex[ index ].y + t * (pNextNode->pVertex[ nindex ].y - pCurrentNode->pVertex[ index ].y), 
							pCurrentNode->pVertex[ index ].z + t * (pNextNode->pVertex[ nindex ].z - pCurrentNode->pVertex[ index ].z));
			}
			glEnd();
		}

	}


}
Here is a screenshot of the rendered scene. One thing I'm with doubts is about texturing... When I've glBinded the texture then draw the floor, the following triangles I've drawn later had "absorbed" the texture's color (brown)...so I put this after the glBegin/glEnd that draws the floor: glBindTexture(GL_TEXTURE_2D, 0); It looked like i've reset the texture bind... So its the correct way of doing this? Thanks people... Bruce [edited by - brucesinner on June 4, 2003 3:51:21 PM]

Share this post


Link to post
Share on other sites
The first thing is to call glBegin/glEnd only once. Just call glBegin when you start rendering your model and glEnd when ou finish. This will save you a lot of function call overhead. The next thing you should do is lear how to use vertex arrays. This will simplify this whole code to about 10 lines. It will also give you a nice FPS boost.

About texture "unbinding" : glBindTexture(GL_TEXTURE_2D, 0); is one way but it's considerd bad practice. Much better way is to call glDisable( GL_TEXTURE_2D );

SKSlayer : Those 2 variables in inner loop will not be any problem as compiler will optimize the code to only store them in registers. And the fact they are defined only in inner loop scope gives compiler a bit more hints whare thoes two variables are even needed.

You should never let your fears become the boundaries of your dreams.

[edited by - _DarkWIng_ on June 4, 2003 4:46:47 PM]

Share this post


Link to post
Share on other sites
1st, you are sending your whole model through the AGP port at every frame. You may not render high poly models that way or it will for sure be slow.
2nd, you init 2 vars in a loop which is called several times per seconds, which has a major impact on performance
Those are the 2 major reasons for slowness.

Your screenshot link is dead, make sure to get it alive again

Share this post


Link to post
Share on other sites
_Darkwing_: thanks for the tips, but when I do glDisable(GL_TEXTURE_2D), then the texture doesn''t show at all...

About the vertex arrays...even if I need to do on-the-fly calculations as I''m doing (interpolating I mean), I can use it?

Share this post


Link to post
Share on other sites
I''ve put the glBeing/glEnd out of my loops and I''ve got a gain of 2 FPS. Not bad for a so simple modification.

And about the loss of performance when I draw the textures on screen ? It''s lowering too much...

Share this post


Link to post
Share on other sites
quote:
Original post by brucesinner
_Darkwing_: thanks for the tips, but when I do glDisable(GL_TEXTURE_2D), then the texture doesn''t show at all...

About the vertex arrays...even if I need to do on-the-fly calculations as I''m doing (interpolating I mean), I can use it?




I think you misunderstood DarkWing, by glBegin he ment the glBegin(GL_TRIANGLES); call. That call should be out side of the loops.

The texture is all wrong to. When you use glBindTexture(GL_TEXTURE_2D, 0); or glBindTexture(GL_TEXTURE_2D, NULL); no textures will show up. A texture ID has to be a non-zero unique identifier. Use glGenTextures() to get a valid texture ID. The way you have it now it won''t apply a texture, so DarkWing was saying glDisable(GL_TEXTURE_2D); is the same thing, which it is.

Share this post


Link to post
Share on other sites
Sorry Ultima X, but I think you misundestood it all! :-D

I''m using glBindTexture(GL_TEXTURE_2D, 0) to unbind the texture, of course, I''ve bind it to an ID generate with glGenTextures(), before.

And I do put the glBegin outside my loops now.
I''ve already told that in the last post.

Something like

glBegin(GL_TRIANGLES)
for(...
my loops goes here with calls to glVertex3f
glEnd()

Thats it! I gained 2 fps!

Share this post


Link to post
Share on other sites
After looking at the screen shot I'm curious about something... What your FPS without the actor? The lamps, couch, etc, seem to have a high poly count to. That could be a problem there to.

EDIT: The reason I brought up the texture stuff is because of what you said...

"_Darkwing_: thanks for the tips, but when I do glDisable(GL_TEXTURE_2D), then the texture doesn't show at all..."

So I didn't know you were trying to disable them, from that quote it sounded the other way around?

My bad

-UltimaX-

"You wished for a white christmas... Now go shovel your wishes!"

[edited by - UltimaX on June 4, 2003 5:36:44 PM]

Share this post


Link to post
Share on other sites
Without the woman:
With the floor and wall textures: only 4-5 FPS
Without textures: 33 FPS

I think if I optimize the woman display with vertex arrays or other thing I''ll get high FPS with her on screen.

I have another thing to mention:

All the models you can see on the screenshot were exported from 3ds MAX to a proprietary format of my own. But when I exported that, the coordinates were so huge... Some vertex were like (200, 80, 430) for example. So my frustum had to be big too.
Something like 1 -> 4000 to accomodate all the models...

The room for example, I had to draw a single cube with all dimensions ranging from 0 to 1 and then scaled to simulate a room. But the glScalef() function was so huge...(2500, 1100, 1500). This can be the reason for the bad performance I''m getting?

But, how can I fix it? My models coordinates already come BIG from the 3ds MAX exporter...

Share this post


Link to post
Share on other sites
If you are using glBindTexture(GL_TEXTURE_2D, 0) to unbind the texture, what are you using to bind it - hopefully glBindTexture(GL_TEXTURE_2D, 1) - not glLoadTexture2D.
You should be doing something like:


if (pCurrentNode->texture_id)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pCurrentNode->texture_id);
}
else
{
glDisable(GL_TEXTURE_2D);
... set up object colours here ...
}

... Draw all the object triangles ...

// Nice to do this at the end, so textures don't leak
// into other graphics ...
if (pCurrentNode->texture_id)
glDisable(GL_TEXTURE_2D);



You should not be getting a slowdown with texture, unless you
have an ancient graphics card, ot you load the texture every frame.

[edited by - ChookMaster on June 4, 2003 9:52:35 PM]

Share this post


Link to post
Share on other sites
brucesinner, vertex arrays would significantly boost your performance. Try looking into using hardware-accelerated vertex-array extensions such as GL_NV_vertex_array_range2 for nVidia cards, GL_ATI_vertex_array_object for ATI cards, or even the new arb extension ARB_vertex_buffer_object which aims to work for all cards (although it may take a while for drivers to support it). These simply copy the vertecie, texture coordinate, normal, and color data onto a region of AGP memory that the card can access directly. You just copy the vertecies at initialization, then to tell it to draw, you only need to call one function each frame.

I drew scenes with 70,000+ polygons using GL_ATI_vertex_array_object because I have a radeon, and would say i got at least 30 frames per sec (this was done by eye however, I did not write any code yet to calculate the fps. It could have been a lot faster or slightly slower than 30fps. im not sure. it was fluid motion, however). Without using this method I got the results you are getting (1-2 fps). It would definately be worth your while to look into using these extensions.

The list of extensions and their documentation can be found here: http://oss.sgi.com/projects/ogl-sample/registry/

Also, did you turn on back-face culling? That will increase FPS.

[edited by - Firewalker on June 4, 2003 10:35:05 PM]

Share this post


Link to post
Share on other sites
FireWalker: Yeah man, I''ve turned back-face culling on. Got one or two more FPS.

My animation has a new list of vertices and normals for each frame...I would have to, at startup, create a huge array that holds all the vertices and normals info and then pass it to the AGP memory with the extensions functions?

But that huge array wouldn''t be a memory problem?

Each vertice has 3 floats (x,y,z) that sums up 12 bytes(4 bytes each float)
The same apply for the normals (12 bytes)

Only the actor has about 15000 vertices and normals, so:

total memory = 15000 * 12 + 15000 * 12 = 360000, about 360k

I have too, an array with the faces indicies to the vertices, but need to store it once. About 25000 faces with one int each:

memory of face indicies = 25000 * 2 = 50000, 50k

So each frame take 410k of memory. If I create am array with all my frames (including the inbetweening ones), lets say 100 frames for the entire actor animation:

total memory = 410k * 100 = 4.1 megs!!!

Huge isn''t it? But all the modern computers has at least 128 megs of memory, i think it wouldn''t be a problem...

Share this post


Link to post
Share on other sites
Chookmaster: I have a Geforce 4 TI4200 64mgs at home and a Geforce 4 MX440 at work. In these two beatiful cards, I get only 1-2 fps with the textures applied to it. Ahh, I use latest Detonators drivers on them.

What do you people think could be slowing down the scene?

Do you think, the huge viewport and frustum can be the problem? Should I diminish the frustum size and scale down the model to fit in it?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Storing the animation in arrays should be much of a problem.

Using vertex arrays would definitely help.
BTW, how much of a diff do you guys think using extension vertex arrays will give as compared to using the default opengl vertex arrays?

Share this post


Link to post
Share on other sites
Proper use of VA or VBO will give you boost of performance over plain glVertex* calls in just about any case. How big will de speedup be will depend on how much geometry limited is your app.

Just one note: DON''T use nv_vertex_array_range or ati_vertex_array_object since they are vendor specific. Use new extension called arb_vertex_buffer_object that is in all newer drivers.

In your case just create a VBO in AGP memory and upload interpolated geometry each frame. And while you are on optimizing speed try running some post-T&L cache optimizations.

You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
_DarkWIng_: Yea its best to use that newer one created by the ARB, but if the card dont support it, you can always fall back on to the card specific ones. Just write some wrapper code (which is what i did) to load and render arrays, that way no matter which extension you use, you only need to write the code once, then just call those functions. My driver still doesn't support the ARB approved one, so i need to fall back onto the ATI one. If the driver someday does support that extension, my program will automatically detect it and use the ARB one without a single change to my code.


Anonmyous: the difference between OpenGL standard vertex arrays and extenion ones is that OpenGL standard ones are stored in client memory, so they still need to be copied to AGP memory every frame. Most extension ones (like the ones i mentioned before) dont, the data always resides on the card resulting in more speed because:

a) there is no extra copy like in standard Vertex Arrays
b) the drivers for the cards have algorithms for optimizing the vertecie data (especially when you use Static arrays, dynamic arrays arent as optimized, but if you are always updating the data they make the state change less costly), so they can do things like joining shared vertecies, which removes even more overhead (but OpenGL standard ones can optimize the data like this too).
c) they use the GPU to process data instead of the CPU. So while the card is rendering graphics, you can be calculating stuff like physics and AI to be ready for the next frame. Means much better parallel processing.

There are a few vertex array extensions. To make sure they ARE hardware accelerated, consult the extension archive (i think i posted it above in my other post)

So:
In the end, the hardware accelerated extension ones are the best.
OpenGL standard ones arent as fast because the data has to be copied to the card every time you call glDrawArrays() to render, but they are still faster than using a bajillion calls to glVertex*() functions each frame.

[edited by - Firewalker on June 5, 2003 7:08:35 AM]

Share this post


Link to post
Share on other sites
Firewalker : what card/driver are you using? I belive both nVidia''s detonator +44.xx and ATi''s 3.4 drivers support it. But in general warper is a very good idea since it offers you a lot of reusability + possibility of fallbacks on older HW.

You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
Ok guys, but answer me one thing:

Before I sent the data to the GPU memory I need to allocate it on a array and then call the extensions functions to load them to the vid card. Is that right? So, don''t I fall in that case I mentioned, large arrays, lots of consuming memory?

That ARB extesion is supported by all cards in market? I mean not only Nvidia and ATI, but one from 3dLabs for example...

Share this post


Link to post
Share on other sites
_DarkWIng_: Thanks for mentioning that. My driver was from April 2003, just upgraded to new driver and the ARB extension is there. (I got a Radeon 8500).


brucesinner: Yea, there are functions that come with the extension for allocating memory, and they will return a buffer handle to you. You can either copy the data at the same time you allocate the memory, or you can update the buffer at another time (Remember, static buffers are more optimized, but take longer to update than dymamic buffers. So if you are doing a lot of updating, use dynamic buffers). Look at the documentation for the specifics.

As for the memory consumption...4 megs is not much to deal with. That is always the tradeoff...memory vs processor usage. Its up to you to decide what is more important for your specific application (and from what im gathering you better trade memory for speed, cuz 2fps dont cut it :-) ).

Actually, instead of sending ALL the vertex data and having all that redundancy and duplication, you can copy each unique floating point value to the array and use glDrawElements() (or something like it depending on the extension) to pick and choose which vertecies to draw; that will save you memory, but again will probably cut into your FPS. It's all in what you need. Theres no perfect answer to resolve the memory vs speed issue. Try to find a good middle ground.


The ARB extension should be supported by mostly all cards, because it is not card specific and was approved by the ARB, so all new drivers of all cards SHOULD have it. But sometimes a person's drivers are outdated or the card doesnt implement the extension. If this happens, you need to take another approach for rendering (or tell the user they cannot use the program).

Hope that answers your question.

[edited by - Firewalker on June 5, 2003 12:31:53 PM]

Share this post


Link to post
Share on other sites
People, people!!!

I think I have solved my problem. If I tell you, you will punch me directly in the head! :-D

The problem was not with my algorithm or implementation...besides using vertex arrays would improve too much, now I''m getting 90 fps even with textures on it...

Let me talk to you what happened:
I switched my machine from an old P4 1.2 ghz w/ a TNT2 card to an Dual Pentium Xeon with 1GB ram and a Geforce 4 MX440 and installed latest detonators drivers.

But then, my program started to look awful, some polygons blinks with black color, others doesn''t shows up and the shows...a mess. Then I tried to install other versions of the detonators drivers and nothing...even im my home, with a Geforce4 Ti4200 it looks terrible. So, next, I switched the opengl32.dll by another version, old one. When I put the ''96 version, from win95 the scene looked correct.

So now you already have thought what happened. I forgot to del it, my program was ALWAYS using ''96 version of the DLL. Thats why the scene was so slow, this version doesn''t have any optimization, its a old, old one.

I switched back to newer one and my FPS boosted up!
Thanks you guys for all help you provided, I learned a lot and still will implement the vertex array stuff.

By the way, the visualization problem returned, my scene looks terrible now, again. But i will make another topic to discuss that...

Share this post


Link to post
Share on other sites