Hi there, I've got a scenario where I can't seem to take advantage of ECS and Jobs. There is about 10.000 rigidbody on the floor. I've got 100 affectors that fly around and nearby rigidbodies get slowly attracted to them. (let's say 5 rigidbodies attracted on average per affector) while flying around. I can't seem to figure out how to leverage ECS to my benefit, my options that I saw thus far are : 1. Adding a component to every rigidbody affected by a affector seems troublesome : first I would add and remove hundreds of them per frame and one rigidbody can be affected by multiple affector and I can't add multiple component to an entity. 2. Create an entity for every rigidbody affected and add a component that reference both my affector and rigidbody. I can get the components with ComponentDataFromEntity to the jobs however I have to modify the PhysicsVelocity component in it and that's not allowed since it may be modified by two thread. 3. Use the idea of 2. but launch a job for each affector that I have but that would mean a hundred of them with an average of 5 entities per job, seems really wasteful. I feel like there is a ECS way that I have overlooked or some kind of pattern perhaps... Any ideas ?
The 2d1c. Triggers - Force Field sample does this. I'll grant you the code could be greatly simplified for your specific use-case but should help. The 2d1. Events - Triggers sample is a bare bones trigger sample if you prefer to start there.
@steveeHavok That is... extremely similar to what I'm trying to do. That will teach me not to look at every folder in the repository, I only saw the bare bone trigger sample that you talked about. It seems that I will only be limited to one affector with this sample but it is a very good starting point. Thank you ! Edit: It seems that adding other affectors is quite the task which was actually most of my problem actually. I still don't see how I can modify the rigidbodies velocity with multiple affectors in a safe way without slowing everything down. Any ideas ?
for each attractor iterate over all objects it affects, calculate a force for the object, and add it to the force already applied to that object
Well of course it's a simple matter if I'm doing everything by iterations, but then I'm losing a ton of performance if I'm not maximizing Jobs/Threads. I feel like this scenario will apply to lot of different things I want to do therefore I'm trying to have the most optimized one from the beginning.
ok, you can do it this way store all attractor positions to the native array pass those positions to a job that iterates on all objects based on all attractor positions calculate a vector field value at objects position and apply a force based on it
I'm not sure what exactly you trying to achieve, is it something like interaction with the grass? in any case, you need a nested loop as long as you need each attractor position to calculate each object's force to get precise result. but if you have both really many attractors and really many objects they affect it may be reasonable to split it into two passes - calculate attractor forces sum at reasonable resolution and store vector field as a 3d-array - iterate on all objects and sample that baked vector field for the force to get approx force value (you can get close enough to real value by interpolation between nearest available values) in this case, you sacrifice some precision but save on iterations Another way to optimize it is to split world space into sections (based on maximum attractor radius) and to do calculations only inside one section
I'm actually trying to do something pretty close to the example but yes with many affectors and many rigidbodies. I can't seem to quite understand what you mean by your 3d-array/vector field/interpolation method. I guess it does feel like a proper solution is not quite that easy with ECS when you've got multiple objects that can affects the same object.
I'll try to explain better Vector field is a function that takes a position is space as input and returns a vector (force in your case) https://www.khanacademy.org/math/mu...valued-functions/v/vector-fields-introduction So for your case you can create a function kind of: vector3 ClaculateForce( float3 position, attractors[] attractors ) inside it iterates on attractors, and calculates a sum of their effect in a given point Next, instead of applying it to each object, you can apply it to points in space of your scene, with a certain step so your scene space is divided into voxels and you know the force in the center of each voxel Next, you iterate on all objects, for each object you can get force values from nearest voxels, and by interpolating those values you now get very close to direct calculation result. So now instead of invoking high-cost ClaculateForce function objects-count times, you call it voxels-count times + (read near voxels + interpolate)*objects-count times. In case of a huge amount of objects/attractors, this trick may save you a lot of CPU time.
Vector fields are useful for particles on the GPU, but in this case I think @Shinao wants to utilize an (m + n) log n algorithm like the one Unity.Physics provides and get near-perfect accuracy for a lot cheaper than m * n. Unless I am misunderstanding the code, ITriggerEventsJob is a single-threaded job, which means you should be able to iterate through all events and directly apply impulses to the entities' rigidbodies using ComponentDataFromEntity<PhysicsVelocity>. Of course if you want to apply your impulses in parallel as well, then I suspect Unity.Physics may not meet your needs as it stands today.
@SubPixelPerfect Thanks for the explanation. Wouldn't I have the same problem storing the forces of the affectors into the voxels when one body can be affected by multiple affectors and therefore the writing in the voxels should be single threaded to avoid overwrite ? It might be faster on this particular use case though. @DreamingImLatios I thought ITriggerEventsJob was running in parallel, can't seem to find an answer in the manual/api on that. How do you know that ? But if that is the case then yes there is no point in doing something if my triggers are already iterative...
In CreateJobReflectionData, the JobType is Single. However, what ITriggerEventsJob really does is iterate over a NativeContainer storing all the pairs of triggers that were calculated in the broadphase. That broadphase runs in parallel, so it is very possible that using ITriggerEventsJob may still be significantly faster than a brute force algorithm overall. The reason ITriggerEventsJob is a single-threaded algorithm is because the broadphase can't ensure thread safety between any two pairs of entities. The only way you can do that is by using an islanding algorithm or a multibox (a multibox BVH in Unity's case).