Yesterday, 11:31 AM
(This post was last modified: Yesterday, 11:41 AM by josemendez.)
(24-06-2025, 05:15 PM)chenji Wrote: It'd be better if force zone can expose a callback per actor to let us change current force zone settings per actor in future release.
Not going to happen, since per-actor callbacks have the exact same problems as per-particle callbacks: they're impossible to do in the GPU (you cannot call back to the CPU from the GPU mid-dispatch), in the CPU they'd allow the user to execute arbitrary code from worker threads while the simulation is running, which throws thread safety out of the window.
Obi provides a single callback for all contacts at the end of each simulation step. This is efficient, always doable, and safe as they happen in the main thread. It also provides the same data used by the engine internally (same system used by force zones), so it comes at a very small cost compared to per-particle or per-actor callbacks.
(24-06-2025, 05:15 PM)chenji Wrote: and let us change data for different actors?
You can do this using the existing collision callback. It's easy to retrieve the actor/force zone per contact and apply your custom force/acceleration/etc.
Here's a slightly modified version of the sample code found in the manual. It finds all particles inside a specific trigger and applies a custom acceleration to them, depending on which actor they belong to.
Code:
[RequireComponent(typeof(ObiSolver))]
public class ZeroGravityZone: MonoBehaviour
{
ObiSolver solver;
void Awake()
{
solver = GetComponent<ObiSolver>();
}
void OnEnable()
{
solver.OnCollision += Solver_OnCollision;
}
void OnDisable()
{
solver.OnCollision -= Solver_OnCollision;
}
void Solver_OnCollision(object sender, ObiNativeContactList e)
{
var world = ObiColliderWorld.GetInstance();
foreach (Oni.Contact contact in e)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
// if this is a force zone:
if (col != null && col.TryGetComponent(out ObiForceZone zone))
{
// get the index of the particle inside the force zone:
int particleIndex = solver.simplices[contact.bodyA];
// get the actor it belongs to:
ObiActor actor = solver.particleToActor[particleIndex].actor;
// apply different acceleration depending on the actor.
if (actor == myActor)
solver.velocities[particleIndex] += contact.normal * zone.intensity * Time.deltaTime;
else
solver.velocities[particleIndex] -= contact.normal * zone.intensity * Time.deltaTime;
}
}
}
}
}