12-05-2024, 10:56 AM
(This post was last modified: 12-05-2024, 10:59 AM by josemendez.)
(12-05-2024, 07:29 AM)btduser Wrote: From what I have gathered, the issue is due to the fact that when I destroy (or disable) a collider, this changes the number of items in `ObiColliderWorld.instance.colliderHandles`, but the collider handle indexes in the pin constraints don't ever get updated. This also happens if I disable the object. Presumably because in either case, `ObiColliderBase.RemoveCollider` is invoked, which modifies the collider handle list.
This either spams burst errors or causes the rope to jump to completely unrelated obi colliders. Even just disabling and re-enabling an obi collider will steal ropes from other objects - e.g. if I have 10 colliders in my scene, with a pin on collider A at index 9, disabling collider B at index 5 rearranges the list so that A is now at index 8 and index 9 is invalid, which will spam errors until I re-enable B, which causes B to get assigned index 9 again, and now the pin is pointing to B instead of A.
Hi!
Think about what happens when you destroy an element in a list: either all elements that appear after the index of the destroyed elements move one space towards the start of the list, or alternatively you can move the last element in the list to the "gap" left by the destroyed element (a swapback operation) if relative ordering of objects is not important. Either option will change the indices of objects in the list.
(12-05-2024, 07:29 AM)btduser Wrote: I don't know what I'm doing wrong - it seems like the issue is a fundamental one, that removing any collider in the scene has the potential to break completely unrelated pin constraints.
Correct. Burst can't deal with object references as it can only work with blittable types. To keep a reference of sorts to an object, indices must be used, but that means that the indices need to be updated whenever objects get moved around in memory.
(12-05-2024, 07:29 AM)btduser Wrote: The only solution I can think of is to modify my pins any time any obi collider is destroyed, but I don't see how that's feasible, since there's no way to make pins immediately aware of the change.
This is the correct solution and it is what Obi does internally. Same applies to all constraints, not just pin constraints: whenever the index of a particle or collider in the internal solver arrays change, all constraints affecting them must be re-created or updated. Remember we are dealing with indices, not pointers/references, so they are not automagically updated.
This is why the ObiColliderHandle class exists: it stores an object reference to the actual Collider, and its index in the solver arrays. This index is updated automatically by the collision system.
When you create a pin constraint using batch.AddConstraint(), the handle to this collider is stored in the batch. Any subsequent calls to
rope.SetConstraintsDirty(Oni.ConstraintType.Pin); will force the constraints to use whatever collider index is currently stored in the handle - as long as the constraint has been added to the actor, and not the solver. If you add constraints directly to the solver you're on your own when it comes to updating them anytime particles/colliders change.
See how ObiParticleAttachment does it: it subscribes itself to solver.Actor_OnPrepareStep, where it calls UpdateAttachment() which in turn calls SetConstraintsDirty if the index of the collider has changed.
kind regards,