Sign in to follow this  
AbdelrahmanelBakry

Textured Quads Particle System

Recommended Posts

I'm trying to implement a Textured Quads Particle System and I've read a lot about billboarding and there's something I can't yet figure out,
In my implementation I have this structure as the Particle structure

struct ParticleVertex
{
D3DXVECTOR3 initialpos;

float U,V;
D3DXVECTOR3 initialVelocity;

float initialSize;
float initialTime;
float lifeTime;
float mass;

D3DCOLOR beginColor;

};

Where initalpos is supposed to be the center of the quad and my VertexBuffer is Created once as a dynamic one with size equal numberofParticles* 4 (as each particle has 4 vertices). and pass the system to the VS to do the integration on the position.
What I'm missing is how I can update the buffer afterwards based on the new position (I mean updating the 4 vertices of each quad, based on the new center resulting from the integration)

Share this post


Link to post
Share on other sites
You're going to need each quad to be made of 6 vertices, because the system is going to need to be drawn as a triangle list.

If I were you, I wouldn't update the list in real time at all...let the shader move the points around it. Build the vertices with information that is velocity etc, then just pass down delta time, an origin etc. to the shader once for each system.

Share this post


Link to post
Share on other sites
Its better to use 4 vertices for each particle drawed as indexed triangle list.
You can try this:
http://www.codesampler.com/dx9src/dx9src_7.htm#dx9_particle_system
its for point sprites but you can rewrite it to use with billboarded quads.

Share this post


Link to post
Share on other sites
I have already done a particle system framework for Point Sprites and used it to build a fog system.my problem is how it can be transformed to use billboards and that's what I'm working on and can't figure it exactly how to handle the 4 or 6 vertices that will represent the particle

Share this post


Link to post
Share on other sites

...
float f = 0.5f * (float)ParticleSize;
Vector3 horizontal(viewMat.M00 * f, viewMat.M10 * f, viewMat.M20 * f);

f = -0.5f * (float)ParticleSize;
Vector3 vertical(viewMat.M01 * f, viewMat.M11 * f, viewMat.M21 * f);

Vector3 view(-viewMat.M02, -viewMat.M12 , -viewMat.M22);

D3D9Device->SetVertexDeclaration(...);
D3D9Device->SetIndices(...);
D3D9Device->SetStreamSource(...);
UINT numVert = 0;
UINT numTri = 0;
Vertex3D_PNCT1* pVertices = 0;
VBuffer->Lock((LPVOID*)&pVertices, D3DLOCK_DISCARD);
for(DWORD i = 0; i < (DWORD)AParticles.Size(); i++)
{
const Particle& particle = AParticles[i];

Vector3 shorizontal = horizontal * particle.Scale;
Vector3 svertical = vertical * particle.Scale;
pVertices[0 + numVert].Position = particle.Position + shorizontal + svertical;
pVertices[0 + numVert].Normal = view;
pVertices[0 + numVert].TexCoord0 = Vector2(0.0f, 0.0f);
pVertices[0 + numVert].Color = particle.Color;

pVertices[1 + numVert].Position = particle.Position + shorizontal - svertical;
pVertices[1 + numVert].Normal = view;
pVertices[1 + numVert].TexCoord0 = Vector2(0.0f, 1.0f);
pVertices[1 + numVert].Color = particle.Color;

pVertices[2 + numVert].Position = particle.Position - shorizontal - svertical;
pVertices[2 + numVert].Normal = view;
pVertices[2 + numVert].TexCoord0 = Vector2(1.0f, 1.0f);
pVertices[2 + numVert].Color = particle.Color;

pVertices[3 + numVert].Position = particle.Position - shorizontal + svertical;
pVertices[3 + numVert].Normal = view;
pVertices[3 + numVert].TexCoord0 = Vector2(1.0f, 0.0f);
pVertices[3 + numVert].Color = particle.Color;

if(particle.Rotation)
{
Vector2 centerCoord(0.5f, 0.5f);
pVertices[0 + numVert].TexCoord0.RotateBy(particle.Rotation, centerCoord);
pVertices[1 + numVert].TexCoord0.RotateBy(particle.Rotation, centerCoord);
pVertices[2 + numVert].TexCoord0.RotateBy(particle.Rotation, centerCoord);
pVertices[3 + numVert].TexCoord0.RotateBy(particle.Rotation, centerCoord);
}

numVert += 4;
numTri += 2;

if(numVert > (VBuffer->GetNumVertices() - 4))
{
VBuffer->Unlock();
D3D9Device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, 0, 0, numVert, 0, numTri);
pVertices = 0;
numVert = 0;
numTri = 0;
VBuffer->Lock((LPVOID*)&pVertices, D3DLOCK_DISCARD);
}
}
VBuffer->Unlock();

if(numVert > 0)
{
D3D9Device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, 0, 0, numVert, 0, numTri);
}
...

Share this post


Link to post
Share on other sites
I forget to add code for indices:

UINT numIndices = numParticles * 6;
USHORT* pIndices = 0;
IBuffer->Lock((LPVOID*)&pIndices);
USHORT j = 0;
for(USHORT i = 0; i < numIndices; i += 6)
{
pIndices[0+i] = 0+j;
pIndices[1+i] = 2+j;
pIndices[2+i] = 1+j;
pIndices[3+i] = 0+j;
pIndices[4+i] = 3+j;
pIndices[5+i] = 2+j;
j += 4;
}
IBuffer->Unlock();




any progress?

Share this post


Link to post
Share on other sites
What I do for my particles is something like this:

ever frame:
update every particle position, check for deaths, etc.
lock vertex buffer
fill it up with particle positions, colours, etc.
unlock buffer
then a single DrawPrimitive() call renders them all

If you aren't sure how to billboard check out this post (Lord Evil), it helped me a lot:

http://www.gamedev.net/community/forums/topic.asp?topic_id=415727

Good luck.

Share this post


Link to post
Share on other sites
There's something I don't understand in the code. May you please explain this part

float f = 0.5f * (float)ParticleSize;
Vector3 horizontal(viewMat.M00 * f, viewMat.M10 * f, viewMat.M20 * f);

f = -0.5f * (float)ParticleSize;
Vector3 vertical(viewMat.M01 * f, viewMat.M11 * f, viewMat.M21 * f);

Vector3 view(-viewMat.M02, -viewMat.M12 , -viewMat.M22);


Thanks

Share this post


Link to post
Share on other sites
I thought that code is obvious.


//viewMat is your view matrix from "player camera"

float f = 0.5f * (float)ParticleSize;// get horizontal offset from center based from quad size

Vector3 horizontal(viewMat.M00 * f, viewMat.M10 * f, viewMat.M20 * f);//horizontal vector "oriented" in object space to face camera



f = -0.5f * (float)ParticleSize;//get vertical offset from center based from quad size

Vector3 vertical(viewMat.M01 * f, viewMat.M11 * f, viewMat.M21 * f);//vertical vector "oriented" in object space to face camera



Vector3 view(-viewMat.M02, -viewMat.M12 , -viewMat.M22);//get quad normal





if you are using D3DXMATRIX just replace viewMat.M00, viewMat.M01...
with access () operator: viewMat(0,0), viewMat(0,1)...

[Edited by - belfegor on October 3, 2010 6:02:53 PM]

Share this post


Link to post
Share on other sites
Ok I got what that part of your code but there's something in your Code that makes it doesn't compile and I can't see anyone, anywhere telling who it can be done
I mean this line

VBuffer->GetNumVertices()

I think it is responsible for the drawing, As my code is now rendering nothing on the screen.

Share this post


Link to post
Share on other sites
VBuffer is just wrapped LPDIRECT3DVERTEXBUFFER9.

Set maximum particles that vertex buffer can hold:

const int MaxParticles = 100;
const int NumVertices = MaxParticles * 4; //4 vertices in a quad, VBuffer->GetNumVertices()





then you should create buffers something like this:

struct ParticleVertex
{
D3DXVECTOR3 Position;
D3DXVECTOR2 TexCoord;
DWORD Color;
};

D3DVERTEXELEMENT9 VertexElements[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 20, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};

...

hr = D3D9Device->CreateVertexDeclaration(VertexElements, &VDeclaration);
...

hr = D3D9Device->CreateVertexBuffer(
sizeof(ParticleVertex) * NumVertices,
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &VBuffer, 0);
...
hr = D3D9Device->CreateIndexBuffer(
sizeof(USHORT) * (MaxParticles * 6), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &IBuffer, 0);





you should have code to move particles and use that with code in earlier posts.

Share this post


Link to post
Share on other sites
Quote:
Original post by belfegor
*** Source Snippet Removed ***


Hi,

Using:

Vector3 horizontal(viewMat.M00 * f, viewMat.M10 * f, viewMat.M20 * f);
Vector3 vertical(viewMat.M01 * f, viewMat.M11 * f, viewMat.M21 * f);

look to me like a smart way to compute the four quad vertexes, avoiding a vector-matrix multiplication to transform each vertex. I will switch to this way too.

May I ask you what you use the normal vector in the quads for ?
How do you light the particles ?

I'm currently computing the light reaching the particle position (ie the center of the quad), but since the particle doesn't have a real orientation, I can't see the benefit which comes from the normal (if you use it for shading)

Thanks !!

Share this post


Link to post
Share on other sites
ok Thanks belfegor I finally made it work :)
I figured out the cause of the rendering problem, I was doing the integration that moves the particles in the shader but I found out that it doesn't go with your code as it doesn't update "particle.Position" so It worked when moved the integration in the update function of my system and my Effect file became really simple unlike when I used it for the point sprite, but It Finalllllly Worked :).
If anyone has ideas on how to do a billboard more based on Shaders As The only computation my VS does is just passing the texture coordinates and giving the vertex a color :), No Integration or any other Computation I don't know if that's the ideal design for the billboard Particle System

Share this post


Link to post
Share on other sites
@NiGoea

The code above is from my old project (testing particles), which i haven't
visited long time ago (i was busy with other problems). It is left half-finished
(lot of unused variables, hardcoded stuff here & there...) but it works.
I haven't use "normals" for anything, as you said it makes no sense to use it for lightning
(i'v used premade vertex struct witch i was using in other project, and copy/paste it in "particles" project).
I was using only ambient lightning for particles there.

@AbdelrahmanelBakry
You can try to use volume texture in shader and step thru each
slice to get more variable/realistic effect (smoke, bloodspray...).

Share this post


Link to post
Share on other sites
Quote:
Original post by belfegor
@NiGoea

The code above is from my old project (testing particles), which i haven't
visited long time ago (i was busy with other problems). It is left half-finished
(lot of unused variables, hardcoded stuff here & there...) but it works.
I haven't use "normals" for anything, as you said it makes no sense to use it for lightning
(i'v used premade vertex struct witch i was using in other project, and copy/paste it in "particles" project).
I was using only ambient lightning for particles there.


Thanks ;)
(premade vertex struct to achieve what ?)

Share this post


Link to post
Share on other sites
Quote:

(premade vertex struct to achieve what ?)


Nothing particular. It was test project using mesh with multi
subsets, switching from texture to vertex color (where each subset have
its own unique color).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this