Particle Billboarding and Camera Problem
Ugh, my head's about to explode...
I have cloned Nehe's tutorial about the particle engine (17? something like that). I have added my own code in to create a user-controlled first persone "camera" so to speak, and that works perfectly. I can fly around the little fountain I made and look at it from any angle without any anomolies except the lack of billboarding. So I figured, "Why now implement billboarding? Seems easy enough, right?" Bzzt... it's proven to be a major headache. I can't seem to get billboarding working completely correctly: I fix one problem and create another.
First off, allow me to explain how my camera works: It is rotated by the use of a quaternion. The quat takes in roll, pitch, and yaw angles and produces the quaternion matrix for rotation. Then I create a translation matrix that looks something like the following:
1 0 0 0
0 1 0 0
0 0 1 0
x y z 1
Finally, I call the glMultMatrixf(FinalMatrix) right at the beginning of my rendering (after the glLoadIdentity), where FinalMatrix = translation * rotation. While creating the FinalMatrix, I also extract the up,right, and forward vectors to keep on hand, just in case I need them later. Mind you, this part works fine if I don't attempt any billboarding.
From what I understand, it seems that I am unable to just take the 3x3 rotation matrix out of the FinalMatrix, transpose it, and plug it back in because there is a translation also.
I have tried:
1. Multiplying by the inverse of FinalMatrix. The fountain appears to be on top of the camera, so I can't test the billboarding.
2. Multiplying by the inverse of FinalMatrix then using the data of the camera's position to translate the fountain. Same result as #1
3. Multiplying by the vector you get when creating a matrix from:
rtx, rty, rtz, 0.0
upx, upy, upz, 0.0
atx, aty, atz, 0.0
0.0, 0.0, 0.0, 1.0
Odd results, can't really control camera anymore
My most recent attempt is to:
MultMatrix(CAM.MAT)
PushMatrix
Get Modelview
Identity the rotation part of the modelview
Load New Modelview
PopMatrix
Now, this produces some interesting results. I know that this isn't true billboarding (it's LightHouse3d's "cheating" one). It does indeed make the particles billboard and always face the camera. However, when I get close to the fountain and look up, my camera gets very confused and starts to go in circles - similar to someone looking at a monitor, holding out their arm in front of them and pointing to each corner of the screen in turn. Also, as I look up, the particles should disappear into the sky, but instead look like they rotate me until I seem to pass through them.
Ugh, I'm so confused. I have tried for the last 6 hours to get this right. Any ideas?
I do real things with imaginary numbers
July 09, 2004 04:23 PM
I'm not sure how you are doing it, but here is a simple approach(yes, very simple):
have each particle's draw routine draw the quad in the XY plane, then do all your calulations, translations, or whatever...
& then:
for (each particle) {
1. push the matrix
2. translate to the particles location
3. clear the matrix (only the first 3 rows of the first 3 columns)
4. draw the particle
5. pop the matrix
}
have each particle's draw routine draw the quad in the XY plane, then do all your calulations, translations, or whatever...
& then:
for (each particle) {
1. push the matrix
2. translate to the particles location
3. clear the matrix (only the first 3 rows of the first 3 columns)
4. draw the particle
5. pop the matrix
}
July 09, 2004 04:25 PM
also, if your camera does something funnny... then fix the camera code / quaternion code. If the particles do something funny... then fix them.
say u use OpenGL's matrix how will u do it then
glPushMatrix();
// Now i first need to read matrix
glGetMatix(m);
m[0-2][0-2] = 0;
glLoadIdentity();
glSetMatrix(M);
glPopMatrix();
// Something like that but i need the correct functions and stuff
glPushMatrix();
// Now i first need to read matrix
glGetMatix(m);
m[0-2][0-2] = 0;
glLoadIdentity();
glSetMatrix(M);
glPopMatrix();
// Something like that but i need the correct functions and stuff
----------------------------http://djoubert.co.uk
Thanks for the replies!
I've got the original problem figured out, but a new one has presented itself. My original camera "oddities" were not oddities at all. In fact, the camera was working perfectly - I was just losing my orientation. Whenever I would fly over the particle fountain and try to look down at the top of it, I would find myself continuously looking at the side of the fountain. I didn't realize that I was looking straight down until I added my skybox to the scene: then I could tell where I was looking and that the problem is in the orientation of the fountain, not the camera.
I feel as if I'm not explaining this very well.
Let's put it this way: My fountain shoots particles at random into the x-z plane, and fall down the y plane with gravity (if I'm looking down the Z axis). Now if move to the top of the particle fountain and look down the y axis, the particles are now spraying out in the x-y axis.
I took your suggestion dawidjoubert and my code looks exactly like that:
glLoadIdentity ();
glMultMatrixf(cam.GetMatrix()->mat);
skybox.Render();
glPushMatrix();
float mv[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glLoadIdentity();
m[0-2][0-2] = 0;
glLoadMatrixf(mv);
...draw particles..
glPopMatrix();
How many more steps does it take to preserve the particles' orientation in space but billboard the individual particles?
EDIT:
Thought of a way of explaining what's going on: I feel like what I'm doing now is billboarding the entire fountain, and not just the particles.
I've got the original problem figured out, but a new one has presented itself. My original camera "oddities" were not oddities at all. In fact, the camera was working perfectly - I was just losing my orientation. Whenever I would fly over the particle fountain and try to look down at the top of it, I would find myself continuously looking at the side of the fountain. I didn't realize that I was looking straight down until I added my skybox to the scene: then I could tell where I was looking and that the problem is in the orientation of the fountain, not the camera.
I feel as if I'm not explaining this very well.
Let's put it this way: My fountain shoots particles at random into the x-z plane, and fall down the y plane with gravity (if I'm looking down the Z axis). Now if move to the top of the particle fountain and look down the y axis, the particles are now spraying out in the x-y axis.
I took your suggestion dawidjoubert and my code looks exactly like that:
glLoadIdentity ();
glMultMatrixf(cam.GetMatrix()->mat);
skybox.Render();
glPushMatrix();
float mv[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glLoadIdentity();
m[0-2][0-2] = 0;
glLoadMatrixf(mv);
...draw particles..
glPopMatrix();
How many more steps does it take to preserve the particles' orientation in space but billboard the individual particles?
EDIT:
Thought of a way of explaining what's going on: I feel like what I'm doing now is billboarding the entire fountain, and not just the particles.
I do real things with imaginary numbers
Got it!
This has been an interesting few lessons in world/object/camera space...
Seems like what I needed to do was something along the following lines:
Set Up Camera
Translate to the position of the "sprayer"
For Each Particle...
--Save the modelview matrix - glPushMatrix
--Translate to the position of the individual particle
--Save the matrix a second time
--Strip out the rotation information
--Draw the individual particle verts at (.5, .5,), (.5, -.5,), (-.5, -.5,), and (-.5, .5,)
--Pop the second matrix
--Pop the first matrix
end loop
If anyone else out there is having trouble with viewing matricies and such, let me know and we can blunder through 'em together! :)
Btw, if anyone wants my source code it's yours
This has been an interesting few lessons in world/object/camera space...
Seems like what I needed to do was something along the following lines:
Set Up Camera
Translate to the position of the "sprayer"
For Each Particle...
--Save the modelview matrix - glPushMatrix
--Translate to the position of the individual particle
--Save the matrix a second time
--Strip out the rotation information
--Draw the individual particle verts at (.5, .5,), (.5, -.5,), (-.5, -.5,), and (-.5, .5,)
--Pop the second matrix
--Pop the first matrix
end loop
If anyone else out there is having trouble with viewing matricies and such, let me know and we can blunder through 'em together! :)
Btw, if anyone wants my source code it's yours
I do real things with imaginary numbers
Nice that you got it working. But you just happen to find the slowest way of doing it. It works ok if you only have like 100 particles max, but for more there are better methods. A much better way would be to use VA/VBO and create vertices either on CPU or on GPU using VP. If you want to go this way just say so and we'll help you on the way...
You should never let your fears become the boundaries of your dreams.
July 15, 2004 11:03 AM
I'm interested in this method even if he isn't, can you explain further? cus the way I do it... is with the "slow" method as mentioned above & I have a LOT of particles in some of my scenes.
thanks
thanks
Quote: Original post by _DarkWIng_
Nice that you got it working. But you just happen to find the slowest way of doing it. It works ok if you only have like 100 particles max, but for more there are better methods. A much better way would be to use VA/VBO and create vertices either on CPU or on GPU using VP. If you want to go this way just say so and we'll help you on the way...
::nods:: Now that you mention it DarkWing, my particles do seem to go quite slowly when I ramp up the particles. I'm not sure if it's due to the blending (is there a faster way then GL_BLEND? should masking be used?), or if it's due to the way I'm drawing the particles. I do experience a noticable slowdown when I hit ~5000 particles on the screen, yet I've found some discussions on these boards about drawing upwards of 100,000 particles and still running other models/shading etc in the background.
If you wouldn't mind elaborating a little bit on the use of VP/VBOs and particles, I'd be quite interested. I have used VPs and VBOs before, but only in passing, not in order to optimize for speed.
Edit:
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?
I do real things with imaginary numbers
Ok.. let's start with VA/VBO & CPU method first.
First you need a way to get your camera up and right vectors. How you get them depends on camera system you use. If your camera uses those vectors then just gram them from camera, if not then you can extract them from view matrix (1st and 2nd row I think).
Then you need a vertex array. For simplicity lets say it's fixed size (limited max number of particles). You create a structure like
Now each frame you need to do something like this:
First you need a way to get your camera up and right vectors. How you get them depends on camera system you use. If your camera uses those vectors then just gram them from camera, if not then you can extract them from view matrix (1st and 2nd row I think).
Then you need a vertex array. For simplicity lets say it's fixed size (limited max number of particles). You create a structure like
class ParticleVertex {public: Vector3 position; Vector2 texCoord; Color color; // add anything else you might need here...}// create vertex arrayParticleVertex *psVA = new ParticleVertex[ maxNumberOfParticles * 4 ];// fill static data -> texture coordinats will not change laterfor ( int i=0; i<maxNumberOfParticles; i+=4 ) { psVA[ i*4 ].texCoord.x = 0.0f; psVA[ i*4 ].texCoord.y = 0.0f; psVA[ i*4+1 ].texCoord.x = 1.0f; //...and so on}
Now each frame you need to do something like this:
// first fill VA// get up & rightVector3 up = camera->GetUp();Vector3 right = camera->GetRight();// for each particleint vaIndex = 0;for ( int i=0; i<numParticles; ++i ) { Vector3 pos = particle.position;<br> Color color = particle.color;<br> <span class="cpp-keyword">float</span> size = particle.size;<br><br> <span class="cpp-comment">// particle i, vertex 0</span><br> psVA[ vaIndex ].position = position - right*size + up*size;<br> psVA[ vaIndex ].color = color;<br> <span class="cpp-comment">// any other per-particle parameters</span><br> vaIndex++; <span class="cpp-comment">// <- next vertex of same particle</span><br><br> <span class="cpp-comment">// particle i, vertex 1</span><br> psVA[ vaIndex ].position = position + right*size + up*size;<br> psVA[ vaIndex ].color = color;<br> <span class="cpp-comment">// any other per-particle parameters</span><br> vaIndex++; <span class="cpp-comment">// <- next vertex of same particle</span><br><br> <span class="cpp-comment">// and so on.. for all 4 corners</span><br>}<br><br><span class="cpp-comment">// now render it</span><br><span class="cpp-comment">// setup pointers</span><br>glVertexPointer( <span class="cpp-number">3</span>, GL_FLOAT, <span class="cpp-keyword">sizeof</span>( ParticleVertex ), &psVA[ <span class="cpp-number">0</span> ].position );<br>glTexCoordPointer( <span class="cpp-number">2</span>, GL_FLOAT, <span class="cpp-keyword">sizeof</span>( ParticleVertex ), &psVA[ <span class="cpp-number">0</span> ].texCoord );<br><span class="cpp-comment">// add color all other pointers…</span><br><br><span class="cpp-comment">// and render in one call </span><br>glDrawArrays( GL_QUADS, <span class="cpp-number">0</span>, vaIndex );<br><br><br></pre></div><!–ENDSCRIPT–><br><br><br>Couple of things to be carefull about: <br>-Do NOT create a new VA each frame. Use the one from last frame and just overwrite data in it.<br>-If you need rotating/scaling particles you have to take this into account when adding right and up vectors.<br>-Changine this to VBO is not a big deal so I let it out (maybe next time:))<br>-I've skipped all texture binding and blending setup.. you know how to do that since it's same as before :)<br><br>edit: If I totaly missed something please feel free to remind me [grin]
You should never let your fears become the boundaries of your dreams.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement