Advertisement

Particle Billboarding and Camera Problem

Started by July 09, 2004 02:57 PM
13 comments, last by _DarkWIng_ 20 years, 4 months ago
Thanks Dark!

Sorry I didn't get back to you sooner. I have implemeneted the Vertex Arrays example and it works... not necessarily well, but it works.

What I mean is that when I run some tests on one version versus another (two different builds completely), I get the following results:

100 Particles
Push/Pop __ way: 150-155 fps
VertexArray way: 150-155 fps

1000 Particles
Push/Pop __ way: 99-101 fps
VertexArray way: 94-96 fps

5000 Particles
Push/Pop __ way: 24-25 fps
VertexArray way: 30-31 fps

5000 Particles
Push/Pop __ way: 24-25 fps
VertexArray way: 30-31 fps

20000 Particles
Push/Pop __ way: 7 fps
VertexArray way: 8.5-9 fps

50000 Particles
Push/Pop __ way: 3.23 fps
VertexArray way: 4.10 fps

With these results in mind, I have a few questions if you have time:
1. Is it possible to speed up blending? If I look at my fountain from far away, it runs fast. However, if I zoom up close to the fountain, the fps drop like a rock.
2. Could I simply be limited to the fill rate of my videocard? I'm at work right now on a 1.8 ghz machine with a GeForce mx 440 videocard, so it's not exactly the best setup in the world.
3. Should I be seeing more of a performance gain when using the vertex arrays? It seems that the % gain increases with the number of particles, but a 25% increase on 3 fps doesn't make all that much of a difference.
4. It seems odd that in every case but the 1000 particle system the VA wins. Is that because the push/pop method is actually faster at lower particle counts, or is it due to some flaw in my coding?
5. How in the world to people claim to get 100000 particles on the screen running at anything near a reasonable framerate?
I do real things with imaginary numbers
Quote: Now that I think about it, those 100,000 particle posts were talking about point sprites. Are those a whole lot faster than regular particles or are they completely different from your standard issue particle?


It depends on what you’re trying to accomplish skyfire. While point sprites are much faster than bill boarded quads they are not quite as versatile. Here is a general rule you can use to determine if point sprites will suffice. If your particles will always face the camera no matter what direction the camera is looking at then use point sprites because they are faster and you do not have to make a bill board matrix. On the flip side if you need your particles to lock onto a certain axis then making a bill board matrix is the way to go. There are a few reasons you would want to lock a billboard matrix on an axis. If your bill boarded quads are trees or bushes or something then you will more than likely want to lock them on the x axis so when/if you fly over them they don't rotate parallel with the earth. For the spray of a fountain though point sprites would be more than adequate. The speed increase comes from sending only a single point to OpenGL rather than 4 points. You can also still use them in a vertex array as well but your point sprites only need a single vertex rather than 4. The best way to think of point sprites is regular GL_POINTS that can be bound to a texture.

- Cheers
Advertisement
The code I wrote is most basic approach. It can be optimized in many cases.

Show us your code and we'll se what it can be done to speed it up.

Blending can be speed-up a bit with alpha testing. But it depends on scenario thow.
You should never let your fears become the boundaries of your dreams.
Ask and ye shall receive:

	// Set up the modelview matrix for the camera	glMultMatrixf(cam.GetMatrix()->mat);	sb.Render(); // Render my skybox	glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	glDisable(GL_DEPTH_TEST);	glEnable(GL_BLEND);		Vector cup;	Vector cright, cview;	// Camera uses a quaternion m_orientation to do 	// rotations.  The axis can be extracted from 	// it using the following functions	cup = cam.m_orientation.GetUpAxis();	cview = cam.m_orientation.GetViewAxis();	cright= CrossProduct(cview, cup);	int vaindex = 0;	for(int loop = 0; loop < MAX_PARTICLES; loop++) {		Vector pos, color;		float life;		pos.x = particles[loop].x;		pos.y = particles[loop].y;		pos.z = particles[loop].z;		color.x = particles[loop].r;		color.y = particles[loop].g;		color.z = particles[loop].b;		life = particles[loop].life;		//My vector class is sort of broken at the		//moment, so this way seemed to be the best		//way to go - i.e. least multiplies		 float crx = cright.x * 0.5;		 float cry = cright.y * 0.5;		 float crz = cright.z * 0.5;		 float cux = cup.x * 0.5;		 float cuy = cup.y * 0.5;		 float cuz = cup.x * 0.5;		//Set up ll		particleVA[vaindex].position[0] = pos.x - crx + cux;		particleVA[vaindex].position[1] = pos.y - cry + cuy;		particleVA[vaindex].position[2] = pos.z - crz + cuz;		particleVA[vaindex].color[0] = color.x;		particleVA[vaindex].color[1] = color.y;		particleVA[vaindex].color[2] = color.z;		particleVA[vaindex].color[3] = life;		vaindex++;		//...		//Duplicate 3 more times for the other corners		//...		// Apply velocities to particle position		particles[loop].x += particles[loop].xv/(slowDown*1000);		particles[loop].y += particles[loop].yv/(slowDown*1000);		particles[loop].z += particles[loop].zv/(slowDown*1000);		// Update particle velocities from accelerations		particles[loop].xv += particles[loop].xa;		particles[loop].yv += particles[loop].ya;		particles[loop].zv += particles[loop].za;		// Fade the particle for next frame		particles[loop].life -= particles[loop].fade;		if(particles[loop].life < 0.0f) {			//PArticle is dead, reset particle			particles[loop].life = 4.0f;			particles[loop].fade = float(rand() % 100) / 1000.0f + 0.003f;			//reset position to origin			particles[loop].x=0.0f;					// Center On X Axis			particles[loop].y=0.0f;					// Center On Y Axis			particles[loop].z=0.0f;					// Center On Z Axis			//get new particle velocity based on speeds			particles[loop].xv=float((rand()%60)-30.0f) * 10;	// X Axis Speed And Direction			particles[loop].yv=ySpeed+float((rand()%60)-30.0f);	// Y Axis Speed And Direction			particles[loop].zv=float((rand()%60)-30.0f) * 10;		// Z Axis Speed And Direction			//assign color			particles[loop].r = colors[pcolor][0];			particles[loop].g = colors[pcolor][1];			particles[loop].b = colors[pcolor][2];		}		if (GetKeyState(VK_NUMPAD8) & 0x80 && (particles[loop].ya<20.5f)) particles[loop].ya+=0.1f;		// If Number Pad 2 And Y Gravity Is Greater Than -1.5 Increase Pull Downwards		if (GetKeyState(VK_NUMPAD2) & 0x80 && (particles[loop].ya>-20.5f)) particles[loop].ya-=0.1f;		// If Number Pad 6 And X Gravity Is Less Than 1.5 Increase Pull Right		if (GetKeyState(VK_NUMPAD6) & 0x80 && (particles[loop].xa<1.5f)) particles[loop].xa+=0.01f;		// If Number Pad 4 And X Gravity Is Greater Than -1.5 Increase Pull Left		if (GetKeyState(VK_NUMPAD4) & 0x80 && (particles[loop].xa>-1.5f)) particles[loop].xa-=0.01f;		if (GetKeyState(VK_TAB) & 0x80)						// Tab Key Causes A Burst		{			particles[loop].x=0.0f;					// Center On X Axis			particles[loop].y=0.0f;					// Center On Y Axis			particles[loop].z=0.0f;					// Center On Z Axis			particles[loop].xv=float((rand()%50)-26.0f)*10.0f;	// Random Speed On X Axis			particles[loop].yv=float((rand()%50)-25.0f)*10.0f;	// Random Speed On Y Axis			particles[loop].zv=float((rand()%50)-25.0f)*10.0f;	// Random Speed On Z Axis		}	}	glEnableClientState(GL_VERTEX_ARRAY);	glEnableClientState(GL_COLOR_ARRAY);	glEnableClientState(GL_TEXTURE_COORD_ARRAY);	// Bind the texture of the particle	t1.Bind(); 	glVertexPointer( 3, GL_FLOAT, sizeof( ParticleVertex ), &particleVA[0].position );	glTexCoordPointer( 2, GL_FLOAT, sizeof( ParticleVertex ), &particleVA[0].tcoord );	glColorPointer( 4, GL_FLOAT, sizeof( ParticleVertex ), &particleVA[0].color );	// and render in one call 	glDrawArrays( GL_QUADS, 0, vaindex );	glEnableClientState(GL_TEXTURE_COORD_ARRAY);	glDisableClientState(GL_COLOR_ARRAY);	glDisableClientState(GL_VERTEX_ARRAY);	glPopAttrib();


I apologize that it's a little messy. I'll try posting this and see how it looks, then edit it to make it cleaner.
I do real things with imaginary numbers
-1St make sure you are running in release mode.
-Don't update whole color each frame. Just update alpha each frame, but leave RGB alone (update on new particle or something like that).
-Move "Vector pos, color;" (and possibly all the floats) out of for loop.
-You are calling "particleVA[vaindex].xxx" bunch of times. Try using references or pointer.
-"particles[loop].x += particles[loop].xv/(slowDown*1000);" 3x for each particle. Precalculate (outside for loop) float invSlovDown = 1.0f / (slowDown*1000); and then in loop particles[loop].x += particles[loop].xv * invSlovDown;"
-"float crx = cright.x * 0.5;" (6x) You don't need this. Just multiply cright and cup with 0.5f. They don't change over loop.
-A bit off-topic: "float(rand() % 100)". Never use modulo operation on RNG. You kill uniform distribution by this. Use something like: range * float(rand()) / float(MAX_RAND);

Someone might spot some more things to do.. I have to get some sleep.
You should never let your fears become the boundaries of your dreams.

This topic is closed to new replies.

Advertisement