Page 1 of 1

Help with excluding a selection of Bodies from RayCast

Posted: Sun Jun 02, 2019 7:31 pm
by abego
Hello!

I am trying to filter out specific bodies during raycasting. While searching for solutions I found this question asked before: viewtopic.php?f=4&t=2565&p=14245, but I can't seem to get it working, as the RayCast does not register any hits at all. My goal is to have a ragdoll standing upright by keeping the head up with a OneBodyLinearServo, with the Target set 2 meters above ground. The ground is a Box located at (0, 0, 0) with dimensions of (64, 1, 64).

I have fetched the IRayHitHandler from the Grapper class in the Demos, and modified it to this:

Code: Select all

struct RagdollRayHitHandler : IRayHitHandler
{
    public Ragdoll ragdoll;
    public float T;
    public CollidableReference HitCollidable;
    [MethodImpl (MethodImplOptions.AggressiveInlining)]
    public bool AllowTest (CollidableReference collidable)
    {
        return !ragdoll.bodies.Contains (collidable.Handle); <-- I have tried filtering out collidables here, if they are a part of the ragdoll
    }

    [MethodImpl (MethodImplOptions.AggressiveInlining)]
    public void OnRayHit (in BepuPhysics.Trees.RayData ray, ref float maximumT, float t, in Vector3 normal, CollidableReference collidable)
    {
        //We are only interested in the earliest hit. This callback is executing within the traversal, so modifying maximumT informs the traversal
        //that it can skip any AABBs which are more distant than the new maximumT.
        if (t < maximumT)
            maximumT = t;
        if (t < T)
        {
            //Cache the earliest impact.
            T = t;
            HitCollidable = collidable;
        }
    }
}
Ragdoll is a class containing handles to all the bodyparts, created in exactly the same way as in the Ragdoll Demo. The ragdoll.bodies field is a HashSet<int>, where all handles to the bodyparts are stored.

Here is how I cast the ray:

Code: Select all

        simulation.Bodies.GetDescription (ragdoll.handles.Head, out BodyDescription head);

        RagdollRayHitHandler rayHit = new RagdollRayHitHandler ();
        rayHit.ragdoll = ragdoll;
        rayHit.T = 2;

        simulation.RayCast (head.Pose.Position, new Vector3 (0, -1, 0), 2, ref rayHit);

        if (rayHit.T < 2)
        {
            Vector3 target = head.Pose.Position + new Vector3 (0, -1 * rayHit.T + 2, 0);

            if (!ragdoll.hasMotor)
                ragdoll.AddUprightMotor (target, simulation);
            else
                ragdoll.UpdateUprightMotor (target, simulation);
        } else
            ragdoll.RemoveUprightMotor (simulation);
The ray is cast at the same rate that Simulation.Timestep is called.

I have verified that the Ragdoll.AddUprightMotor method is working, as I could fix the ragdoll to a specific Target when it was created in earlier tests.

Re: Help with excluding a selection of Bodies from RayCast

Posted: Sun Jun 02, 2019 9:23 pm
by abego
After some more testing I have found that Collidables in Simulation.Bodies and Simulation.Statics can have the same handles, and since the Box that is the ground is the first Static object created, and the hips of the ragdoll is the first dynamic object created, they have the same handle '0'.
To work around this i have added a check in the AllowTest method of the RagdollRayHitHandler that always allows testing if the Collidable is static

Code: Select all

[MethodImpl (MethodImplOptions.AggressiveInlining)]
public bool AllowTest (CollidableReference collidable)
{
    return collidable.Mobility == CollidableMobility.Static || !ragdoll.bodies.Contains (collidable.Handle); //Returns true if collidable is Static, or if collidable is not part of the ragdoll
}
Is this the correct/optimal way to do this, or does anyone know of another way to do this?

Re: Help with excluding a selection of Bodies from RayCast

Posted: Sun Jun 02, 2019 10:34 pm
by Norbo
Is this the correct/optimal way to do this, or does anyone know of another way to do this?
That's a correct way to do it, yup.

Another approach would be to make use of the CollidableReference's Packed field which packs the dynamic/kinematic/static type into the upper 2 bits. Since dynamic body collidables are encoded with a type of 0, you could check the ragdoll.bodies for collidable.Packed rather than collidable.Handle.

Re: Help with excluding a selection of Bodies from RayCast

Posted: Sun Jun 02, 2019 11:17 pm
by abego
Thank you, I'm gonna go with your approach, seems a little cleaner.