sengoku
15-01-2008 14:22:55
Hi,
We're using Newton for our physics, and I'm trying to get 'walk zones' working. They're basically invisible triggers that you walk through. I've got everything fully working, except for one thing: userProcess() is only called during contact. Once you're fully inside the invisible trigger volume, userProcess() stops getting called (fair enough, it tells you 'contact' information, and its no longer contacting).
So what I need to know is - how can I tell that my player body is intersecting in any way with the walk area, be it faces intersecting, or completely enveloped? Because as it stands right now, I can't tell the difference between inside and outside, only contacting and non-contacting.
A side note: this worked quite well doing the detection inside userBegin(), but as you would expect its only using the AABBs, so the collisions sometimes aren't very accurate. We require the detection to be fairly correct.
The workaround I'm proposing is to have wafer thin walk volumes set at waist height, so their faces always intersect with the player, but that seems kinda silly to me (especially as winding also matters for intersecting faces, so there are chances for incorrect misses). Any thoughts?
dudeabot
15-01-2008 17:20:06
you can try checking the distance from center, if its between a range, then he is "in"
walaber
15-01-2008 19:42:17
one possible solution is a flag-based approach, where in contactProcess() you check the relative velocity to the surface normal between the objects, and if negative you set the "inWalkZone" flag to true, and don't set it to false again until you get another contactProcess() where the relative velocity is positive, meaning the object is leaving the region...
I'm not sure how reliable this would be though.
another option is to always assume that the player is NOT in a collision volume. then, when you get a hit on contactProcess, mark a flag that you are inside.
for every frame, IF the flag is true, use Newton's low-level collision functions to determine if the body is still inside the collision volume. if this function returns false, reset the flag to zero, and forget about it again until you get another hit from the callback...
nullsquared
15-01-2008 23:16:07
I'm not exactly sure how OgreNewt works, but what I did with my "triggers" was store the current time of each collision between the "trigger" object and the "entering/leaving" object. Then, in some kind of update function, loop over the current "inside" bodies, and check the difference between "now" current time and the "object's" current time. If it's over 2x or more of your Newton time step, then it's not in the trigger anymore. This works since Newton's collision callback is done every update where two objects are colliding, not just on the first time a collision occurred. Not exactly sure how this maps out to OgreNewt, but the general theory is there.
sengoku
21-01-2008 08:26:58
Hey,
Thanks for the suggestions. I've tried your solution Walaber, and I couldn't get any of the manual collision functions to give me what I was after. I already use your method of assuming you're not in the collision volume until you hit it (this is how I trigger enter and exit events), so it was straightforward to try adding the lower level function checks.
Here's what I tried anyway:
During userBegin() (for AABB culling), I tried using NewtonCollisionCollide, NewtonCollisionClosestPoint (even though its not supposed to work on tree collisions, I tried it), and NewtonCollisionPointDistance.
NewtonCollisionCollide gives the same results as userProcess - ie it only triggers on face intersection, not full volume intersection.
NewtonCollisionClosestPoint didn't work, as expected.
NewtonCollisionPointDistance also didn't work. Now this I expected should work, because I was just passing in the location of my player and the walk area it collided with, and its supposed to return "zero if the point is inside the convex primitive". Instead it was always returning zero. As far as I know our walk areas are convex.
So I'm not sure what was going wrong with NewtonCollisionPointDistance, but I'm still somewhat stumped. Again, we use tree collisions and I'm fairly sure they're convex.
Also I agree about the velocity check Walaber, it seems like it would easily fall over, so I'm not sure if its worth trying.
nullsquared, I'm not quite sure I follow your method. My collision callback ceases to get called when one volume is entirely inside another one (or I can use the AABB intersecting one, which always works, but is inaccurate). I have entering and exiting handled correctly, the issue here is one of volume intersection. If I have misunderstood then are you able to go into more detail?
Thanks!
nullsquared
21-01-2008 20:17:01
nullsquared, I'm not quite sure I follow your method. My collision callback ceases to get called when one volume is entirely inside another one (or I can use the AABB intersecting one, which always works, but is inaccurate). I have entering and exiting handled correctly, the issue here is one of volume intersection. If I have misunderstood then are you able to go into more detail?
Is your "walk area"/trigger thing a convex object (be it a primitive or a hull), or a tree/user collision? (If its a tree/user collision with faces pointing inwards, there are no callbacks since an object that is inside is not colliding with the tree/user mesh itself.)
What is the OgreNewt equivalent of the material process callback? You need to make a "trigger" object that receives this callback. Then, pseduo-code:
class Trigger {
std::map<Body*, unsigned> objects;
void onCollide(Body *collidingBody) {
if (collidingBody is not in objects already)
bodyEnteredTrigger(collidingBody)
objects[collidingBody] = getCurrentTime();
}
// this should be called _AFTER_ the physics updates, every frame
void update() {
for every object in objects
if getCurrentTime() - iter->second > 2 * NewtonGetTimeStep(world) then
this object is not in the trigger any more, remove it
bodyExitedTrigger(iter->first)
}
}
while (gameIsStillRunning) {
doStuff();
doPhysicsUpdate();
callUpdateForEveryTrigger();
doStuff();
}
You'll need to make sure that the trigger body is never asleep, give it some mass and make sure its material does not allow collisions between it and other stuff (but make sure its notified of this collision first, "onCollide()") - do not use any forces on it, wake it up, and then call NewtonBodySetAutoFreeze(body, false) so that it doesn't sleep.
Any body found in "objects" is intersecting the trigger, it will continue intersecting the trigger until bodyExitedTrigger() is called.
I'm sorry this is not OgreNewt-specific, but I don't use OgreNewt. The general theory of a trigger, though, is here.