capsuleCast detection shifted in runtime

I am using the physic extension from this post and I have noticed that the convexCast or capsuleCast detection is a little bit off after collision.


The red ball capsuleCast detection is clearly shifted, however, the collision and physics still work fine. Is there anyway to reset the capsuleCast collision detection back to center?

Each ball also has these adjustments that might cause the capsuleCast shifted problem.
setContactProcessingThreshold(0.000001)
setCcdMotionThreshold(0.1)
setCcdSweptSphereRadius(0.1)

What are your dimension scales for the balls? Please, note what your options mean:

setCcdMotionThreshold(0.1): means don’t apply CCD collision detection for movements that are less than 10 cm. The actual value preferably be two balls radii minus some epsilon.

setCcdSweptSphereRadius(0.1): means use a sphere with radius of 10 cm for CCD sweep test. This should preferably be the same radius as your ball.

Those values should better match your actual balls scales and dynamics. However, they should not affect your shape casts, only the motion of the balls when they start moving. Do you use a shape cast against the table cushions as well? What are the values for the shape cast you use?

If you could create a simple repro project (just default spheres/boxes to imitate actual balls/rails) that would demonstrate that offset, then I could probably say more.

Every ball is a scale of 5 in xyz and uses the Shpere type with 0.15 radius. I am using capsuleCast because sphereCast always detects the table.
The prediction ring is located at -0.15 distance from the hit result in the forward direction, which is not 100% accurate representation but again the screenshot below the forward capsuleCast should have detected the blue ball instead of the cushion.

var result = this.app.systems.rigidbody.capsuleCast(0.09, 0.07, capStartPos, dir.clone().scale(100));
        if (result) {
            hitPos.copy(result.point);

            // Project hitPos onto the direction line
            var v = hitPos.clone().sub(cuePos);  // vector from cuePos to hitPos
            var projLength = v.dot(dir); // projected length along dir
            projectedHitPos = cuePos.clone().add(dir.clone().scale(projLength - 0.15));
            this.ballProjectRingIndicator.setPosition(projectedHitPos);
        }

The value of capsuleCast is: capsuleCast(0.09, 0.07, capStartPos, dir.clone().scale(100));
I have tested capsuleCast with 0.09 radius will bring the most accurate result. capsuleCast with 0.15 radius also has the same detection problem. I will make a repro after a break.

I would use a sphere cast and filters to ignore the table during the sweep test. I might give an example later tonight, if you can’t figure it out by then.

ah, my bad the -0.15 distance actually messed up the visual indicator. There is no problem with the detection at all. It was the force position align with forward direction and -0.15 distance that caused the visual problem.

1 Like

Could you show me how to do sphere cast and filters to ignore certain colliders? I have fixed the ring indicator and it turns out that the more collisions it had the more shift detection would happen in capsuleCast.

Well, you can modify the closest convex result callback in the convex-cast.js that you are using. You can apply custom filters and masks using:

var convexCallback = new Ammo.ClosestConvexResultCallback(data.ammoPosFrom, data.ammoPosTo);
convexCallback.set_m_collisionFilterGroup(bits);
convexCallback.set_m_collisionFilterMask(bits);

In that case, you would also need to adjust your rigidbodies filters/masks. You can check out @yaustar 's filtering example for reference:
https://playcanvas.com/project/519294/overview/physics-mask

However, in your case, I think you don’t need custom groups/masks. All you want is to filter out the table, which should be static, so you want your cast to hit everything, except static or kinematic bodies. Then you can simply set the mask for convex cast result (mask defines what groups it can touch):

convexCallback.set_m_collisionFilterMask(pc.BODYMASK_NOT_STATIC_KINEMATIC);

This will make shapecast only see dynamic objects in your scene.

Edit:
Ah, you still want your cast to see the table cushions. Right. Hmm, perhaps you could separate your cushions from your table surface. Table surface could be static, and cushions could be kinematic. Then you could use pc.BODYMASK_NOT_STATIC mask instead. Otherwise, you’d have to use the first option I provided, using custom groups/masks.

thank you for showing how to filter on shapecast. I found that the shift happens only when the cast direction face to +z or -z. It runs fine when the direction face +x or -x. I am also unable to drawline in this scene. I have tested on a new project but cannot repo this error. I guess I will just go with a new clean scene.

I guess your vector math is not placing the target correctly. When you scale the forward vector by 0.15, perhaps you need to use world instead of local forward (or the other way around). Also, if you are using a capsule as a shape for cast, the capsule orientation is important. The cast method accepts the rotation start and end. You probably want to orient it based on the direction you are aiming, rather than using the same orientation for all casts.

Is there anyway to ignore tags in convexCallback? I have to scale sphereCast forward otherwise it will always return cueBall.

I don’t know why but setting cast endpoint position to direction scale to 10000 fixed the problem.

var result = this.app.systems.rigidbody.sphereCast(0.15, cueBallPos, dir.clone().scale(10000));

The smaller the scale, the less accurate the result becomes.