Jump to content
  • Advertisement
Sign in to follow this  
Spa8nky

Collision detection method is correct but object shakes when resolution takes place?

This topic is 3263 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello folks, I have the following algorithm that works out how far an object is from a line segment whilst keeping the object inside a certain radius at all times. The problem is that when I am resolving the position of the object it will visibly shake. This occurs when it is at the outmost limit of the allowed distance from the closest point on the segement (i.e. > radius). What have I done wrong here?
            // Set projected position to current object position
            Vector3 position_Projected = debug_Polygon[0].Position;

            // Get key presses this frame
            if (InputState.Global.IsKeyDown(Keys.Left))
            {
                position_Projected = debug_Polygon[0].Position + new Vector3(-0.005f, 0, 0);
            }
            if (InputState.Global.IsKeyDown(Keys.Right))
            {
                position_Projected = debug_Polygon[0].Position + new Vector3(0.005f, 0, 0);
            }
            if (InputState.Global.IsKeyDown(Keys.Down))
            {
                position_Projected = debug_Polygon[0].Position + new Vector3(0, -0.005f, 0);
            }
            if (InputState.Global.IsKeyDown(Keys.Up))
            {
                position_Projected = debug_Polygon[0].Position + new Vector3(0, 0.005f, 0);
            }

            // Find the distance between the object and the nearest point on the segment
            float distance = debug_Segment.SquareDistanceToPoint(position_Projected);

            // If the object is outside the radius
            if (distance > 2.0f)
            {
                // Calculate penetration depth
                distance -= 2.0f;
                
                // Compute the closest point on the segement to the projected position
                Vector3 center_Segment = debug_Segment.ClosestPtPointSegment(position_Projected);

                // Calculate the normal based on the closest point on segment to object's position
                Vector3 normal = center_Segment - position_Projected;
                normal.Normalize();

                // Distance can also be found with normal (when it isn't normalized)
                //Console.WriteLine("Distance " + normal.LengthSquared());
                
                position_Projected += normal * (distance /* - radius_BoundingSphere */ - GameConstants.EPSILON);
            }

            // Update object's position with final projected position (doesn't change if key isn't pressed)
            debug_Polygon[0].Position = position_Projected;


Thank you.

Share this post


Link to post
Share on other sites
Advertisement
It happens because of the Epsilon. In this case you should be able to remove it, if you only want to stay within a sphere. It's only necessary when you want the player to be able to be on both sides of a surface, to make sure he doesn't accidentally go through it. Staying within a sphere should be achievable by just setting distance to the radius whenever it's larger, and moving that distance in the direction of the endpoint.

Share this post


Link to post
Share on other sites
Quote:
Original post by Erik Rufelt
It happens because of the Epsilon.


I have tried removing the epsilon before and it still does exactly the same thing. Any other thoughts?

Share this post


Link to post
Share on other sites
Distance (penetration depth): 0.009919167
Object position: {X:-1.412716 Y:0 Z:0}
Projected position: {X:-1.407797 Y:0 Z:0}

Distance (penetration depth): 0.01014829
Object position: {X:-1.412797 Y:0 Z:0}
Projected position: {X:-1.407649 Y:0 Z:0}

Distance (penetration depth): 0.006502628
Object position: {X:-1.411511 Y:0 Z:0}
Projected position: {X:-1.410008 Y:0 Z:0}

EDIT:

Theses are some distances from the segment to the new projected point, shouldn't they be dead on 2?

1.997116
1.979426
1.986003
1.999779

Share this post


Link to post
Share on other sites
Quote:
shouldn't they be dead on 2?

I don't see why they should. The line

if( distance > 2 ) distance -= 2;

could result in any value of distance, depending on the initial value.

If you want to keep the object inside the radius "at all times," why not:

position_Projected = normal * (radius-epsilon);

Also, you use "SquareDistanceToPoint." Is "distance" the actual penetration depth or the square of the penetration depth?

Share this post


Link to post
Share on other sites
"distance" is actually the square distance from object position to segment, does that mess up my calculations?

If I have the following:


position_Projected += normal * (float)Math.Sqrt(distance);


then the shaking is worse.

Quote:

position_Projected = normal * (radius-epsilon);


This makes the object wrap around the circle (warp from one side to opposite side)?!

Share this post


Link to post
Share on other sites
Oops! How about:

position_Projected = center_Segment - normal*(radius-epsilon);

EDIT: which, actually, is what Erik suggested. Since your test is distance > 2 rather than distance => 2, you can leave the epsilon out (as Erik said).
EDIT2: By the way, are you using a radius of sqrt(2)?

Share this post


Link to post
Share on other sites
Using your method and hopefully answering your edit questions I get the following working code:


// Find the distance between the object and the nearest point on the segment
float distance = debug_Segment.SquareDistanceToPoint(position_Projected);
float radius = 2.0f;
float radius_Squared = radius * radius;

// If the object is outside the radius (> instead of >= means I don't have to use an Epsilon)
if (distance > radius_Squared)
{
// Compute the closest point on the segement to the projected position
Vector3 center_Segment = debug_Segment.ClosestPtPointSegment(position_Projected);

// Calculate the normal based on the closest point on segment to object's position
Vector3 normal = center_Segment - position_Projected;
normal.Normalize();

// Distance can also be found with normal (when it isn't normalized)
//Console.WriteLine("Distance " + normal.LengthSquared());

position_Projected = center_Segment - normal * radius;
}






If this is what Erik was getting at then apologies to Erik for me being a bit slow on the uptake.

The line:

position_Projected = center_Segment - normal * radius;

is much simpler than my:

projectedPosition -= normal * (distance - radius - GameConstants.EPSILON);

option.

However, if I were to make the point a bounding sphere, how would I take into account the extra radius of the sphere?

Thank you.

EDIT: Misspelled Erik's name!

[Edited by - Spa8nky on October 15, 2009 6:17:47 PM]

Share this post


Link to post
Share on other sites
Quote:
if I were to make the point a bounding sphere..

If you mean to keep a bounding sphere inside the radius as you did a point, and assuming position_Projected is the center of that sphere (similar to your existing code):

float distance = debug_Segment.SquareDistanceToPoint(position_Projected);
// account for distance from pos_projected to outer edge of sphere
float temp = sqrt(distance)+sphere_radius;
distance = temp*temp;

and..

// if needs to be repositioned, keep the position + sphere_rad inside radius
position_Projected = center_Segment - normal * (radius-sphere_radius);

However, if you were avoiding the sqrt() for efficiency (which was a good idea), you would have to use a sqrt() anyway now. So you could change your code:

distance = sqrt(SquareDistance()) + sphere_radius;
if(distance > radius) ..

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!