Report trigger enter and exit per body, not per shape
PhysX reports one trigger pair per pair of shapes, so a body with more
than one collision shape inside a TriggerBody, or a trigger with more
than one shape around one body, is reported several times over. The
reports went into a set, so the first shape to leave took the whole body
out of it: bodyExited was emitted and collisionCount dropped while the
body was still inside. The body's side, enteredTriggerBody and
exitedTriggerBody, was emitted straight from the pairs, so a body with
two shapes was told twice that it had entered. All of that contradicts
what the count and both pairs of signals are documented to mean.
So follow the pairs the reports are about. Every PxShape is tagged with
the collision shape it was built for, which is what a pair can be
identified by across a rebuild: rebuilding replaces every PxShape of a
node but none of its collision shapes. A body is inside a trigger while
any of its pairs is, and out once the last one stops overlapping. Both
directions come out of that one list, so a body that asked only to be
told itself is followed without being counted, one that asked for
nothing at all is followed without being reported, and what is reported
on the way out is what was reported on the way in even if the body
changes its mind while inside. collisionCount is kept as bodies come and
go rather than counted on demand, since that list holds an entry per
body a trigger overlaps and the property is read from bindings on every
change. Which bodies it counts was never written down, and is now.
A body whose overlap moves from one of its shapes to another, one
leaving as the next enters, has both reports in the same batch, and
PhysX does not say which order it puts them in, so the found one is
taken first for the pair that has both. Every other pair keeps the order
it came in, so a body leaving one trigger as it enters another is still
reported in that order.
Rebuilds need care of their own. PhysX reports the pairs of the shapes
it takes away, but as pairs of a shape that is already gone, which
cannot be told apart and is ignored. So those pairs are held until the
next round of reports says which of them the new shapes are in, and
whatever is not reported again is dropped. That is what keeps a body
with an animated shape from being reported as leaving and entering once
per frame, and what ends an overlap when a shape is destroyed or carried
out from under a body that stays put.
A trigger's actor also stops being kept awake. It is a dynamic actor,
since PhysX only reports a trigger pair when one of the two is, and
gravity was left on it, so its pose had to be written every frame to
hide the fall. That kept it awake, and PhysX skips a trigger pair's
overlap test only when both of its actors are asleep, so every body a
trigger held was tested every step however long it had been settled.
With gravity off and the pose written only when it moves, a trigger that
stands still over sleeping bodies costs nothing.
Add tests/auto/trigger_counting, one scene per thing that can happen to
a body a trigger holds: a two-shape body slid out through one side, a
body deleted while inside, a shape rebuilt every frame, shapes destroyed
one by one, the trigger's own shape rebuilt every frame, a shape carried
out from under a body, a sleeping body whose shape is nudged, a body
relaying its overlap from one shape to another in a single step, a body
that starts asking once it is already inside, and a body that only asked
to be told itself. Every handler reads the body it is handed and counts
an unexpected one as a hundred, so a stale pointer fails rather than
passing as a number that looks right, which is what makes these worth
running under -fsanitize=address.
Pick-to: 6.12 6.11
Change-Id: I74d32518cd4a2b154857b48e2761ec48d6645c00
Reviewed-by: Kristoffer Skau <kristoffer.skau@qt.io>