GPU powered particles


#1

This is something I’ve been working on for the last 3 months or so, I got the proof of concept version up in a few days, but then things kind of kept on exploding in my face… anyway it is almost ready, or at least ready enough to be show.

tl;dr version:
git here: github.com/wezu/p3d_gpu_particle

You use the editor to make some effects, save it to a file, then import wfx and do:

particle=Wfx()
particle.load("default.wfx")
particle.start() 

You can link effects to moving emitters, set a global force or per emitter forces, turn the effects on and off (per emitter), or pause the whole system

smiley=loader.loadModel('smiley')
smiley.reparentTo(render)
#link emitter to node
particle.set_emitter_node(emitter_id=3, node=smiley)
#set emitter force
particle.set_emitter_force(emitter_id=1, Vec3(0.5, 0, 0))
#set global force
particle.set_global_force(Vec3(0,0,-1))

Editor screenshot:

The Long version

The system uses 3 floating point texture buffers, that are ‘rotated’ in a way similar to triple buffering. The first buffer has the position of the particles two frames back, the second one has the position last frame, and the third one is the one we render to in the current frame, then in the next frame the first buffer will be the one we render to and buffer two and three will have the position in the last frames. This way I don’t need to store the particle velocity and I can run it on OGL 3.x hardware that has no compute shader nor image store functions (but also uses more memory).

The particles use the position texture in the vertex shader to set the position of each particle, each vertex is rendered as a point with a texture (the texture is/can be animated). You can control the size, weight, texture and lifetime of each particle, but why make things simple? The size and weight are not just start and end values, you have a sin function that controls how these values change over time.

Since there is no programmable blend stage, I needed to make two geoms - one with additive blending and the other with alpha blending (well ‘dual’ actually), because you need additive blending for things like fire, alpha blending for smoke and from time to time the binary part of dual blending is also useful for things like snow.

You can render over a million particles with this system, but if you have all of them on screen and they are big (like 100pixels each) then you’d better have a gpu with a lot of fillrate because that’s the bottleneck here.

Some things that are missing but planed:

  1. Collisions with the world
    A cheap way to do collisions would be to render a heighmap with normals from above and let the particles collide with that, but that would only work in some scenarios (outdoor scenes). A more advanced solution is to render a 3D texture of the world (voxelize it), but without compute shaders I don’t see a way to do it in realtime, it still could work for static scenes. I’ve also read on the interweb that one could use the depth buffer of the main camera to do collisions with particles, but I don’t think that would work for my setup (I don’t know the screen space position of a particle when I’m doing physics, I just have the particles world space pos).

  2. Vector fields
    This is simple, I just need to find a way to generate a vector field, write it to a 3D texture and get that texture to a smpler3D :mrgreen:

  3. Better texture support in the editor
    I wanted to make the texture thing simple, just say what texture you want for a batch of particles and it will do the work for you, but it’s not working as expected , so I’ll need to write something different with a bit more manual input from the user.

  4. Helper functions in the editor
    I need to write some functions to help generate particles in specific shapes - rings, spheres, planes, custom mesh shape and some others

  5. Attract, repulse, vortex forces
    I’m doing the physics in a fragment shader and to be honest I have no idea how to code this kind of forces :blush:

There are probably things that can be improved or added, if you have any suggestions or questions, feel free to ask here.


#2

Hi wezu-

nice work! Unfortunately, when I tried the code, I got:

  File "XXXXX\p3d_gpu_particle-master\p3d_gpu_particle-master\wfx.py", line 199,
in load
    shader_attrib = shader_attrib.setFlag(ShaderAttrib.F_shader_point_size, True)
AttributeError: type object 'panda3d.core.ShaderAttrib' has no attribute 'F_shader_point_size'

I use the P3D 1.9.2 x64 version.

I suspect the flag ‘‘F_shader_point_size’’ was (may?) not added in 1.9.2 but in 1.10 - see [url]Does anyone care about Point based particles?]


#3

Yes, sorry, I totally forgot about that - You need a dev version to run this.

If you comment out line 199 in wfx.py you could run it with 1.9, but all the particles will be the same size (1 pixel, unless you set some other size in line 250 eg. point_node.setRenderMode(RenderModeAttrib.MPoint, 25)) and the texcords will also get messed up :neutral_face:


#4

Many thanks !

Yes, it works with the adjustments you mentioned (and framerate is good). I’ll probably need to go to 1.10 to fully benefit from this code.

Thanks


#5

I’ve made a bit of an update. It is now possible to have the particles collide with the scene geometry using a heightmap of the scene (the system generates the map automagically if you pass in a heightmap_resolution paramater). Keep in mind that this is a design flawed by design, the particles will never collide with perfectly vertical walls and will fall right through any surface obscured by anything above it.

Here’s a very bad video of a demo available at the git repo (main2.py):

youtu.be/pfNcDuUSxaQ

My skills and hardware is very bad for recording video, so if anyone is willing to make a better one do give me a link.

There’s also been some changes to the editor, and the page on the git also has a wiki… and now I remembered that the ‘bounce’ variable I put into the editor should be used by the collisions, but it’s not (I’ll do it next time) :mrgreen:


#6

Another update.

Now you can run the collision detection against a 3D texture/voxel. There’s a little tool called voxel.py in the repo, check that out on how to generate a 3d texture from your own scene (the tool can pack the txo into a multifile if you want it to, the txo can be really big -32mb for 128x128x128- but it compresses well).

There’s a new video here:
youtu.be/5DAO8La7MAY

I also tested it with a few more particles (just over 250 000):
s29.postimg.org/ugq4as2ef/512snow.png

I’m still thinking how to make a vector field, the problem is not storing or reading the data, the problem is making sensible vectors in the first place - manually writing the vectors one at a time to the voxel grid is out of the question, I’ll probably need to write another tool for that.

All the source is still at the same location as before: github.com/wezu/p3d_gpu_particle


#7

I am wondering if your system could be used to create the effect I am wanting to perform. I am not finding a way to do it with the standard panda particle systems. I need a particle system that is confined to the boundaries of a surface (a Geom, I guess - I am a bit of a beginner with Panda3D at this point). The particles could be generated either from a point in the center of the surface or from one or more edges of the surface. I need to be able to control the movement of the particles on the surface according to a function which I can set. What I am wanting to do is basically create a simulation of cymatics on the surfaces of objects in the scene. Do you think your system could be used to do this? How would I go about working with it to try doing this? Thanks. Cicada


#8

I had to look up what cymatics are and I’m not sure how best to make such a thing. Maybe my system could be hammered into the right shape, but I don’t think that’s the best solution - the function driving the motion of the particles would have to be written as a glsl fragment shader and if you have that part you can probably just display it as an image or use it as displacement/height map.


#9

Well, in general, the particles in cymatics are sand grains that get distributed on the surface according to how the sound waves vibrate through the object. What I am wanting to do is control the movement of the particles with soundwaves that get passed through a function that mimics the way the way that sound vibrations might propagate through various objects.
I don’t have a clear understanding of how the particles in a particle system are modeled and controlled, but it seemed like the system that comes with Panda3D did not provide a way for me to explicitly move the particles around. It did seem like writing some sort of shader would perhaps be the correct way to do this, but I am still investigating and I came across your system and thought perhaps there could be a way to use it.