It’s a start!
https://vimeo.com/270927194
The system is monstruously inefficient right now because I basically have no broadphase (I compare every collider agaist every collider, which is terrible), but I’ve at least reached a point where I have some kind of decent foundation to start building on. Also, I’ll stick to just sphere colliders (and maybe box colliders) for as long as I can, in case I end up doing massive architectural changes. I’ll implement the remaining collision primitives once I’m fairly certain I’ve got something good
For those who are curious, here’s how I’ve arranged things so far:
-
RigidBodySystem: For each rigidbody, handle applying drag and angular drag, and then handle moving the rigidbody position/rotation based on its velocity/angularVelocity
-
UpdateColliderPoseSystem: For each collider (colliders are separate entities from rigidbodies, but they all know which rigidbody “Entity” they belong to), calculate their new worldPos and worldRot based on their relativePos from their associated rigidbody
-
ComputeColliderAABBSystem: For each collider, calculate the AABB (Min, Max, Centroid, etc…)
-
BroadphaseSystem: For each collider, do an AABB test against all the other colliders, and output a NativeArray representing all the pairs of colliders that are potentially overlapping.
In the near future, I intend on implementing this state-of-the-art BVH algorithm for the broadphase. It is a great fit for the job system or the GPU because it is highly parallelisable. Plus, it doesn’t rely on incremental updates, so it seems fairly simple, safe, and straightforward. We have the popularity of RayTracing to thank for the recent increase of interest in this area of research
-
ContactsGenerationSystem: The first part of the NarrowPhase. Here we take all of the CollisionPairs from the broadphase, and do the actual collision tests. The output of this system is a NativeArray that stores all the collision infos such as contactPoint, collisionNormal, collisionImpulse, overlapDistance, etc, etc…
-
ContactsResolutionSystem: Takes all the CollisionManifolds of the previous step, and actually solves the collisions by applying impulses and displacements to the rigidbodies
Additional notes:
Manual update of systems all of those systems are [DisableAutoCreation]. I handle their creation and updating manually in a “PhysicsSimulationSystem”. This is so that I will be able to do an equivalent of “Physics.Simulate” later on with this physics system. But I haven’t really tested yet if this works well, and I’m still not 100% sure if updating systems manually like that breaks any secret optimizations for ECS/Jobs/Burst
Contacts generation and resolution done in two separate steps There is a good reason why ContactsGenerationSystem and ContactsResolutionSystem are two separate steps; it’s because we sometimes need to be able to do some logic after contact manifolds have been generated, but before the collision is actually solved. Think about a situation where you are making character controllers and want to have complete control over how the character decollides from colliders. A common case is when your character lands on a slope after a jump. Normally, it’ll decollide diagonally because of the angle, so your character will “drift” down the slope a little bit. What you’d really want in that case is to solve collisions 100% vertically instead. You can now add a system between these two that will modify the contact manifolds of your character rigidbodies before they are actually processed and resolved. This is something that we cannot do in current unity physics!
Collision “Events” strategy How will collision “events” work? The plan right now is to build a NativeMultiHashMap<Entity, CollisionManifold> as contacts are generated. Then, other user-made systems can go get this multiHashMap and use the rigidbody entity as key to see if any collisions occured. Another possibility is to store collision events and collisions count in a “CollisionInfos” component that lives alongside the rigidbody, but I’ll need to wait for components to be able to contain fixed-size arrays for that
CPU and GPU My plan right now is to do everything on the CPU for a start. It’s only after having completed the physics engine on CPU that I will start looking into doing GPU compute conversions for parts of the system. The broadphase would be a great candidate for this. I’m having doubts about whether or not the cost of CPU-to-GPU data transfer will defeat the purpose of doing things on GPU in the first place, though. A physics engine isn’t very useful if you can’t even access rigidbody position or velocities because they’re all just on the GPU. Having separate physics worlds (some CPU-only, and some GPU-only with limited data access) is a possibility I’m considering. We’ll see when we get there
An object’s physics representation and visual representation are two separate entities The rigidbodies and the actual meshes are separate entities. Mesh entities simply have a system that makes them follow their associated rigidbody entity with interpolation. In my opinion, interpolation shouldn’t be the responsibility of the rigidbody or the physics engine like it is in unity physics currently. It leads to innumerable headaches when you try to move a rigidbody position manually while still keeping interpolation. I’d much rather have visual object be completely separate from their physics representation. It makes everything so much simpler
How applying forces works Forces and torques will be applied by modifying Velocity and AngularVelocity component values directly. Users can choose if they want to take into account mass or not, or if they want to take into account deltaTime or not (impulse vs addvelocity vs force vs acceleration). But there will be static physics math functions to help calculate the resulting additive vel/angVel of adding a force at a point, for example
Gravity is user-applied Gravity is not some kind of built-in value/functionality in the physics engine. Users are given the responsibility of handling it by themselves with a system that executes right before RigidbodySystem and that applies the desired acceleration to all rigidbodies. I made this decision because there are several games where the gravity is not the same for all objects (think of games like Mario Galaxy, games in space, games with character controllers that have stronger gravity than regular objects so that their jumps feel better, or puzzle games that play with gravity), and in unity physics I’ve frequently had to set rigidbody gravity to 0 and just apply it myself in code instead. I think it’s just much cleaner to apply it ourselves based on our specific needs. With that said… there will probably still be a DefaultGravitySystem that you can choose to activate or not. Maybe it’ll be part of example content instead of the core engine
Kinematic rigidbodies can move with velocity Kinematic rigidbodies can actually be moved with velocity and angularVelocity. This is a nice feature because when you have characters standing on moving platforms, they need to know the velocity of the platform so they can add it to their own velocity. Being able to move kinematics directly with velocity saves you an extra step of having to store the platform’s calculated velocity (or lastPosition) somewhere else. Not a crucial feature, but nice to have