I made a new PhysX test project with the experimental PhysX3.4 build ( available here ), and I can see some huge improvements. Here are the latest results:
5000 colliders free-falling into the void Physx: 4.5ms (previously 6ms) ECS: 3.6ms
20000 colliders free-falling into the void Physx: 20ms (previously 36ms) ECS: 75ms (Still don’t know what’s happening here, but I suspect this could be greatly improved with a bit of tweaking of the broadphase)
5000 colliders falling on the floor into stacks Physx: 10ms (previously 11ms - 18ms) ECS: 7.2ms
I’m attaching the PhysX test project to this post. The three tests can be selected in the inspector of the “Init” object in the scene by setting the TestPreset dropdown: https://i.gyazo.com/c607fbc073ca8c71008b7671fb1e7429.png
I have a question regarding the design of your collision system with the ECS. I did a very simple collision system do that basically does brute force collisions.
But there are 2 problems: Each shape I have is a separate IComponentData struct. And I have written one system for each possible pair of collision shapes. But I feel that this get hard to maintain if you have too many shapes. Is there a better way to do it? For example having more shapes but have a central ComponentSystem that issues different Jobs depending on the collisionPairs? I tried but the performance was really weak. The thing is: In regular ComponentSystems you will access the structs by value, which can result into a big overhead if you have many entities that hold data.
but when you have a JobComponent system that uses a IJobProcessComponentData job, the structs are accessed by reference. Currently I simple put my important collision objects into an array and pass a copy of them to the IJobProcessComponentData that handles a certain collision shape.
My other question is: How do you structure N:M collisions?
For my game, I have implemented a system that works for probably between 50 and 100 objects against n - objects of a certain shape, but performance will get very messy after that.
I plan on having one component per shape too, but I haven’t yet tried implementing multiple shapes. I think I’ll be doing one single system that issues different jobs for each possible pair type.
I do think physics engines typically have one specific collision solving function for each pair type, which means that if you have 5 primitives (sphere, box, capsule, convex mesh, generic mesh), you’ll need 25 possible solvers. I think sticking to only these 5 is probably a good idea
As for performance, my collision solving represents just a tiny little portion of the total frame cost, so I haven’t yet bothered much with optimizing it further. I’m using an IJobParallelFor that goes through two arrays of entities representing the pairs of entities that are potentially colliding together, and then I use several “ComponentDataFromEntity” arrays to retrieve collision information from those entities
It’s all about finding a broadphase algorithm that doesn’t become exponentially heavier with the quantity of objects it’s dealing with. The technique I’m using currently is a pretty standard BVH. This article describes something that’s similar to what I’m doing: http://www.bwfischer.com/oculusRayTracer.html
Thank you for the quick answer!
Well those 5 collider types will certainly be enough. It would be interesting though to have a compound collider support.
For my game, 2d collision is enough, So I plan to support circle collisions, line collisions and eventually polygon collisions. But I have trouble debugging code from the job system, so I still have a few bugs.
So you retrieve all entities and with ComponentDataFromEntity you retrieve the according collision shapes?
And after you have done your broad phase algorithm you use 2 NativeArrays to store the collision pairs? (1 array = 1 collider, the same index of the second array is the other collider of the pair?)
And then do you store your collision results in a [WriteOnly] NativeArray and apply the effects back in the ComponentSystem?
One other thing I noticed: ComponentSystems generally run on the main thread. So if you do the broadphase collision detection, schedule your jobs, execute them and apply the collision effects all in the same OnUpdate iteration in a ComponentSystem, don’t you block the main thread while waiting on the async jobs to finish?
Is there a better way to do this? Maybe scheduling the jobs at the end of the frame and apply the results at the start of the next frame?
@PhilSA I also would like to potentially get access to this as soon as possible, especially as I will likely develop tangentially to you and therefore would be potentially adding alternative / additional workflows to yourself (no point working on what you are already doing so well)
I understand that when adding a git repo its always stressful as you feel the need to clean code, but honestly noone will be judgmental here on such a research based project so don’t let that hold you back if it is!
also @PhilSA it might also be a good idea to look at box2D. A lot of their methods are extremely clean and well thought out and can be uplifted for 3D very easily
I’m sure many would love to examine this project out, me included. I’m also sure this is kind of project that would attract pullrequests and could grow out to be a community project (but at the same time it’s always hard to tell how much things get traction eventually). The risk in doing things all the way is if original dev loses interest and if community is not involved enough at this point, the project usually dies. Also, it’s easy to go feature creep and always just keep adding things before you think it’s done.
I don’t try to pressure to release the project tho. Heh, I’ve done similar things myself I’ve never released so I’m not even in a position to ask such thing One reason why many are waiting to get their hands on something like this is because there are not that many good examples on how to use the new ECS for something useful. Having physics engine running on one would be pretty much first practical example on how to use it as I doubt majority will be doing fish boid simulations on their games
That’s right, but the effects are applied in another job that follows the broadphase job
I’m not yet sure if this would be a possibility (maybe it is). I haven’t taken enough time yet to think about whether or not it’s a good idea to always be 1 frame late. Technically I’m sure this would work, but it might result in usability problems.
There surely are ways to improve my thread usage, though. Here’s what it looks like now:
The repo is coming, but like I said I just want to release it once I’ve got something at least a little bit coherent. My task list before release is this:
Fix contacts resolution issue that makes colliders bounce out of collisions when they shouldn’t
Add box colliders, because having more than one collision primitive will surely make me have to change the way things work
Add rotation aspect to collision resolution, even if not final
I haven’t found much time for the physics engine this week because I had to finish things for another project, but now that that’s done I can finally go back to it
I don’t have much new stuff to show yet, but I’d like to keep people here up to date with what I’m doing just so they know the project is still going strong.
For the past week I have been focusing on understanding the problem of why some of my spheres are bouncing off some collisions even though they have no bounce. The reason why this happens is simple, but the solution wasn’t immediately obvious to me. It happens because when a sphere comes into contact with 2 or more colliders simultaneously, the impulse to solve the contact constraint and “cancel out” the velocity is applied multiple times, which is what propels the rigidbody upwards. Moreover, this problem is also the cause of jitter in large rigidbody stacks.
After studying the literature and GDC talks for a while, I’ve established that the solution to all this is to implement an LCP solver for my NarrowPhase. More precisely; the Projected Gauss-Seidel method. From what I understand, Bullet and Box2D both use similar LCP approaches in their contacts solvers, so I am fairly confident this is the way to go, at least for a start.
Implementing this solver looks like it’s going to take time, though. So it’s very possible that I’ll postpone it until after I release the first version of the source code. But maybe it just sounds scarier than it really is, which is often how these things turn out to be. I’ll re-evaluate this in a few days
If you watch the GDC talk, it’s not really about moving away from perf, their new more accurate solver is almost as fast as the old physx solver (they still care about perf).
This new solver isn’t available yet, so it’ll take a long time until we get it into Unity for example. Nvidia recently bumped latest PhysX version to 3.4.2 and it wasn’t included.
Wheel collider is just a custom suspension and tire sim part of vehicle physics. While many would use it, it’s super specific to one use case. Technically if you got a physics engine, you can implement that kind of functionality manually (as everyone does for anything more serious as stock wheel colliders aren’t that great if you need more control over them).
That being said, job system alone will help doing custom vehicle physics for many vehicles at once for sure, but IMO it’s bit out of scope of generic physics solver and takes time away from more important features.
That’s my (educated) opinion on this matter as a guy who’s worked on vehicle physics for years. If there would be some simplified suspension component in the physics implementation, chances are that most people would still redo it as these are really specific to the game and handling you are after, if done properly (which is why wheel colliders aren’t really used all that much on serious projects).
Bullet is still very much alive (I’m main author), we currently focus on simulation for deep learning (AI) and robotics, through PyBullet Python bindings. It is very exciting to see the ECS/GPU physics development experiments going on here, we used to also implement GPU physics in 2009-2013 using CUDA and OpenCL. Good luck!
Awesome work. Just to give some context, yes this kind of improvements would be great for academia and research work. Here is one my projects using unity where we would generate 1000s of non spherical particles to give you an idea. The limit is about 10000 right now and performance starts to drop early on but is still a major leap over what people currently do in academia and research (most just generate spherical packs). When I present the work, i see excitment about the possibilities with Unity and of course healthy skepticism about accuracy. So stating clearly what equations used in white paper or a publication is another thing that is limiting the adaption. I hope this info helps.
p.s. This is a relatively old project that I started when I got into Unity (although we just put it online recently). So the code is not the cleanest code in the world. I am thinking of rewriting it with ECS and new features if I have the time and depending on peoples usage.