Sign in to follow this  
entropy

SolidParticleSystem Animation Performance

Recommended Posts

I'm a bit of a novice (with Babylon.js and 3D programming in general), so please bear with me.

I'm wanting to create a scene with many repeating objects; so, of course, I want to use instancing to maximize performance. The documentation, the many examples, and countless posts on this forum eventually led me to the SolidParticleSystem. Indeed, this seems to do almost exactly what I want.

The SPS seems to work great so long as all the particles are static. Tens of thousands of particles are no problem. However, that all changes as soon as the properties of the particles need to change on a regular basis. I've created a simple example to illustrate the "issue": https://playground.babylonjs.com/#H8ZQMH. (Now, in the Playground example, I could move the entire mesh at once and likely achieve better performance, but in my specific application I need to move and orient each particle independently.)

After doing some further reading, my understanding is that setParticles (and updateParticle) are carried out on the CPU side, which probably explains the poor performance. Is there a way to do this on the GPU (or, rather, speed up the process in some way)? In my limited experience using DirectX directly, you would do this in the vertex buffer by, e.g., adding the instance position vector to each vertex. Would something like that be possible using Babylon.js?

Share this post


Link to post
Share on other sites
5 hours ago, JohnK said:

Hi @entropy and welcome to the forum. Here is a simple example of shader code changing the positions of individual SPS particles. This could be extended.

Thanks for the replies! For the most part, SPS works really well for me. Much of the time, the particles are just sitting there and the performance is great. Occasionally, I'll need to move them to new positions based upon user input...this is when things slow down a bit.

@JohnK, what you are describing sounds very promising. I'm not seeing the code, though--could you try posting it again?

Share this post


Link to post
Share on other sites

@JohnKWell, I already have another question. In the example that you posted, "box_spacing" and "time" were passed to the vertex shader as uniforms, and then set by (for example):

boxes.material.setFloat("time", time);

This changes that parameter for all instances of the boxes. What I'm really trying to do is to set a parameter on a per particle basis. For example, is it possible to have a vertex shader look something like

// Attributes
attribute vec3 position;
attribute vec3 instancePosition;
attribute vec2 uv;

// Uniforms
uniform mat4 worldViewProjection;

// Varying
varying vec2 vUV;

void main(void) {
    // translate then rotate
    gl_Position = worldViewProjection * (vec4(position, 1.0) + vec4(instancePosition, 1.0));
    vUV = uv;
}

and then set a different "instancePosition" on a per box basis?

 

Share this post


Link to post
Share on other sites

As you said, in the SPS everything is done CPU side and the performance is directly related to the global number of vertices (not the number of particles) to manage.

When using a 16 segment sphere, what is actually a mesh with numerous vertices, as a particle model, it gets quickly to a big global number of vertices. Same with a 3 segment sphere model : https://playground.babylonjs.com/#H8ZQMH#1

a box (only 24 vertices... ok, I know it's not your need) would be much more faster : https://playground.babylonjs.com/#H8ZQMH#2 

 

If you don't really need spheres but circular objects, you could use planar discs instead (maybe in billboard mode if the camera moves) : https://playground.babylonjs.com/#H8ZQMH#3

Share this post


Link to post
Share on other sites

Maybe I am missing the question, but there should be no problem moving 10k+ Particles with any FPS loss.  I tested your example scene with the sinsodial movement of a chain of boxes, cranked it to 20k boxes on my iPhone and had no FPS drop.

 

I kinda don’t know what the specific question is.

Share this post


Link to post
Share on other sites

@Pryme8 in the sinsodial PG the movement is based on the boxes position and the time parameter, entropy wants to know if a shader could be used to set the position and rotation of each particle independently. Actually it was me who suggested shaders in the opening question he wanted to know if there was a way of doing this with the GPU.

On 10/26/2018 at 10:25 PM, entropy said:

After doing some further reading, my understanding is that setParticles (and updateParticle) are carried out on the CPU side, which probably explains the poor performance. Is there a way to do this on the GPU (or, rather, speed up the process in some way)? In my limited experience using DirectX directly, you would do this in the vertex buffer by, e.g., adding the instance position vector to each vertex. Would something like that be possible using Babylon.js?

 

23 hours ago, entropy said:

In the example that you posted, "box_spacing" and "time" were passed to the vertex shader as uniforms, and then set by (for example):


boxes.material.setFloat("time", time);

This changes that parameter for all instances of the boxes. What I'm really trying to do is to set a parameter on a per particle basis

Probably jerome's answer would work as well as any other.

Share this post


Link to post
Share on other sites

Yes, @JohnK summarized what I was trying to say quite elegantly. I did find an example on the three.js website:

https://threejs.org/examples/#webgl_buffergeometry_instancing_interleaved_dynamic

If you look at the code, you'll see a vertex shader similar to the one in my previous post. In the three.js case, the offset and orientation information are passed as per instance attributes to allow the GPU to do all of the vertex transforms. While the tutorial that JohnK referenced doesn't do quite what I was hoping, it does illustrate the power of the technique. Here I've modified the example from the tutorial to animate 10000 sixteen-vertex spheres:

https://www.babylonjs-playground.com/#1OH09K#86

Compare that to the pure SPS solution in my original post that struggled to animate 2000 smoothly. (Granted, the latter is only applying a texture without lighting effects, so it's not a direct comparison.) All that's missing is per instance variables...is that possible to do while using SPS?

I hope I don't sound too querulous. I'm coming from programming 3D in the WPF realm, and Babylon.js is already performing one or two of orders of magnitude faster!...and it's much easier to use.

 

Share this post


Link to post
Share on other sites

I can't access your PG for now. Note that the parameter subdivisions in the sphere constructor isn't the final vertex number, just the number of subdivisions between the sphere poles, so it gets to far more vertices in final.

If you look at the 3Js example code that you gave ( https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_instancing_interleaved_dynamic.html ), you can see that :

- there's only 5000 boxes, what the classical SPS can manage quite easily and fast (with per particle color, texture, scaling, visibility and even intersections or depth sort 🙂  ) 

- they aren't even boxes, as per se, because their geometries need to be declared manually (I mean float local coordinates and indices) in the vertex buffer before being passed to the BufferGeometry that handles the GPU communication.

Actually this what the SPS does for you in a simpler way for the final user. In this demo, they simply added a custom shader to compute the rotation GPU side.

 

Nevertheless if you still want a real GPU approach, you could check this example out (40K boxes an tetrahedrons computed GPU side) : http://jerome.bousquie.fr/BJS/test/SPSGpu/spsShader.html

It's just an experiment, probably it could be optimized a lot.

All the files are here http://jerome.bousquie.fr/BJS/test/SPSGpu/ 

 

[EDIT] checked your PG : nice 🙂

Share this post


Link to post
Share on other sites
14 hours ago, Pryme8 said:

I kinda don’t know what the specific question is.

The more I think about it the more sure I am that Pryme8 is correct. We do not know your use case. What sort of individual changes do you want for each particle and how and when do you want them to be achieved?

Here is a simplified version with just 5 spheres. Can you complete the PG by showing under what circumstances properties of each sphere change independently and how it looks when these changes take place?

https://playground.babylonjs.com/#H8ZQMH#4

Share this post


Link to post
Share on other sites

I mean I used the SPS for a project with @dbawel.  He would have to say the exacts numbers but I think we were doing 6k or something on screen models with physics and no FPS drop.  So I think from what I understand your goals to be that it would accommodate you if set up correct.

The other option is like others said is to use a Shader, but this will have extreme limits.  First if you are doing anything other then simple shapes (like a point, or a block) things get fairly complicated.  It would essentially be a glorified GPU particle system.  You could take a look at the GPU particle engine, and see about adapting it.

Are you doing basic points? or are you looking to advance into realistic meshs, if you want to do this on the GPU with meshes only you will need to look up Stackless BVH traversal (these are above my pay grade) and figure out how to implement that kind of system.  IQ told me to check that stuff out when I was looking up answers for other projects, but I think it might help you as well (if you are trying to do full meshs).

If you are just doing points ignore that whole last section.

Share this post


Link to post
Share on other sites
14 hours ago, JohnK said:

The more I think about it the more sure I am that Pryme8 is correct. We do not know your use case. What sort of individual changes do you want for each particle and how and when do you want them to be achieved?

Here is a simplified version with just 5 spheres. Can you complete the PG by showing under what circumstances properties of each sphere change independently and how it looks when these changes take place?

https://playground.babylonjs.com/#H8ZQMH#4

Unfortunately, there's no way to model my exact situation in the Playground. I'm using Babylon.js (running in a CEFSharp control) as a 3D viewport in a C#/WPF application. The positions/orientations of each particle are determined on the C# side of the code based upon user inputs at runtime. Basically, I'll need to do something like

  for (var p = 0; p < SPS.nbParticles; p++) {
        SPS.particles[p].position = data[p];
        }

where data[p] is information ultimately derived from C# code.

 

9 hours ago, Pryme8 said:

I mean I used the SPS for a project with @dbawel.  He would have to say the exacts numbers but I think we were doing 6k or something on screen models with physics and no FPS drop.  So I think from what I understand your goals to be that it would accommodate you if set up correct.

The other option is like others said is to use a Shader, but this will have extreme limits.  First if you are doing anything other then simple shapes (like a point, or a block) things get fairly complicated.  It would essentially be a glorified GPU particle system.  You could take a look at the GPU particle engine, and see about adapting it.

Are you doing basic points? or are you looking to advance into realistic meshs, if you want to do this on the GPU with meshes only you will need to look up Stackless BVH traversal (these are above my pay grade) and figure out how to implement that kind of system.  IQ told me to check that stuff out when I was looking up answers for other projects, but I think it might help you as well (if you are trying to do full meshs).

If you are just doing points ignore that whole last section.

I think, ultimately, you're probably right. The code (as is) is already way faster than my previous solution (using native WPF 3D)...now I'm just getting greedy for performance. 😁 Here's a more realistic case that I might have to deal with:

https://playground.babylonjs.com/#H8ZQMH#5

I'll primarily be animating boxes, not spheres. On my system, I can animate ~10k boxes and maintain 60 fps. Anything more than that and the frame rate plummets. For the most part, 10k boxes will be sufficient for my purposes. But offloading translation/rotation to the GPU will give me extra headroom for those fringe cases (and/or it will allow me to use more detailed meshes).

19 hours ago, jerome said:

Nevertheless if you still want a real GPU approach, you could check this example out (40K boxes an tetrahedrons computed GPU side) : http://jerome.bousquie.fr/BJS/test/SPSGpu/spsShader.html🙂

@jeromeWow, that seems to work smoothly! I've tried downloading the code, but can't seem to get it to run on my local machine. Any tips on integrating this into a Babylon.js project?

Share this post


Link to post
Share on other sites

Here is a very crude simulation of input from a range of data sets https://playground.babylonjs.com/#H8ZQMH#6 Note reduction in vertices in spheres

Now with 10 times as many spheres https://playground.babylonjs.com/#H8ZQMH#7

Same number using discs and billboard mode https://playground.babylonjs.com/#H8ZQMH#8

Share this post


Link to post
Share on other sites

Thanks for all the help so far. @jerome...I've been looking at and trying to interpret the "Turbo SPS" code that you linked to earlier. Please let me know if the following explanation is correct.

In your vertex shader, you assign the following attributes: "position", "uv", "translation", "scaling", and "rotation". Typically, I would think of the last three attributes as instance attributes. In other words, they would would get updated only once per instance, so all of the vertices of the same instance would automatically have the same "scaling" parameter, for example. Instead, it seems like you are using those as per vertex attributes where you simply repeat the same "scaling" value for every vertex in the instance, etc.?

@JohnK...that's very clever. That does mimic the behavior of my intended application, more so than my original example. What kind of performance are you getting with that second example with 20000 spheres? I only get about 10 fps.

Share this post


Link to post
Share on other sites
4 hours ago, entropy said:

What kind of performance are you getting with that second example with 20000 spheres? I only get about 10 fps.

Better than me. I am getting 2fps. At least we now have a better idea of what you need. My shader skills are not up to going any further.

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  

  • Recently Browsing   0 members

    No registered users viewing this page.