Jump to content
  • Advertisement
Sign in to follow this  
erpatton

AABB vs OBB Collision Resolution Jitter on Corners

This topic is 2115 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

I've implemented a collision library for a character who is an AABB and am resolving collisions between AABB vs AABB and AABB vs OBB. I wanted slopes for certain sections, so I've toyed around with using several OBBs to make one, and it's working great except for one glaring issue; The collision resolution on the corner of an OBB makes the player's AABB jitter up and down constantly. I've tried a few things I've thought of, but I just can't wrap my head around what's going on exactly. Here's a video of what's happening as well as my code:

 

Here's the function to get the collision resolution (I'm likely not doing this the right way, so this may be where the issue lies):

public Vector2 GetCollisionResolveAmount(RectangleCollisionObject resolvedObject, OrientedRectangleCollisionObject b)
        {
            Vector2 overlap = Vector2.Zero;
            LineSegment edge = GetOrientedRectangleEdge(b, 0);


            if (!SeparatingAxisForRectangle(edge, resolvedObject))
            {
                LineSegment rEdgeA = new LineSegment(), rEdgeB = new LineSegment();
                Range axisRange = new Range(), rEdgeARange = new Range(), rEdgeBRange = new Range(), rProjection = new Range();
                Vector2 n = edge.PointA - edge.PointB;

                rEdgeA.PointA = RectangleCorner(resolvedObject, 0);
                rEdgeA.PointB = RectangleCorner(resolvedObject, 1);
                rEdgeB.PointA = RectangleCorner(resolvedObject, 2);
                rEdgeB.PointB = RectangleCorner(resolvedObject, 3);
                rEdgeARange = ProjectLineSegment(rEdgeA, n);
                rEdgeBRange = ProjectLineSegment(rEdgeB, n);
                rProjection = GetRangeHull(rEdgeARange, rEdgeBRange);
                axisRange = ProjectLineSegment(edge, n);
                
                float axisMid = (axisRange.Maximum + axisRange.Minimum) / 2;
                float projectionMid = (rProjection.Maximum + rProjection.Minimum) / 2;

                if (projectionMid > axisMid)
                {
                    overlap.X = axisRange.Maximum - rProjection.Minimum;
                }
                else
                {
                    overlap.X = rProjection.Maximum - axisRange.Minimum;
                    overlap.X = -overlap.X;
                }
            }

            edge = GetOrientedRectangleEdge(b, 1);
            if (!SeparatingAxisForRectangle(edge, resolvedObject))
            {
                LineSegment rEdgeA = new LineSegment(), rEdgeB = new LineSegment();
                Range axisRange = new Range(), rEdgeARange = new Range(), rEdgeBRange = new Range(), rProjection = new Range();
                Vector2 n = edge.PointA - edge.PointB;

                rEdgeA.PointA = RectangleCorner(resolvedObject, 0);
                rEdgeA.PointB = RectangleCorner(resolvedObject, 1);
                rEdgeB.PointA = RectangleCorner(resolvedObject, 2);
                rEdgeB.PointB = RectangleCorner(resolvedObject, 3);
                rEdgeARange = ProjectLineSegment(rEdgeA, n);
                rEdgeBRange = ProjectLineSegment(rEdgeB, n);
                rProjection = GetRangeHull(rEdgeARange, rEdgeBRange);
                axisRange = ProjectLineSegment(edge, n);

                float axisMid = (axisRange.Maximum + axisRange.Minimum) / 2;
                float projectionMid = (rProjection.Maximum + rProjection.Minimum) / 2;

                if (projectionMid > axisMid)
                {
                    overlap.Y = axisRange.Maximum - rProjection.Minimum;
                    overlap.Y = -overlap.Y;
                }
                else
                {
                    overlap.Y = rProjection.Maximum - axisRange.Minimum;
                }
            }

            return overlap;            
        }     

And here is what I'm doing to resolve it right now:

if (collisionDetection.OrientedRectangleAndRectangleCollide(obb, player.PlayerCollision))
{
	var resolveAmount = collisionDetection.GetCollisionResolveAmount(player.PlayerCollision, obb);

	if (Math.Abs(resolveAmount.Y) < Math.Abs(resolveAmount.X))
	{
		var roundedAmount = (float)Math.Floor(resolveAmount.Y);
		player.PlayerCollision._position.Y -= roundedAmount;
	}
	else if (Math.Abs(resolveAmount.Y) <= 30.0f) //Catch cases where the player should be able to step over the top of something
	{
		var roundedAmount = (float)Math.Floor(resolveAmount.Y);
		player.PlayerCollision._position.Y -= roundedAmount;
	}
	else
	{
		var roundedAmount = (float)Math.Floor(resolveAmount.X);
		player.PlayerCollision._position.X -= roundedAmount;
	}
}

Can anyone see what might be the issue here, or has anyone experienced this before that knows a possible solution? I've tried for a few days to figure this out on my own, but I'm just stumped.

Share this post


Link to post
Share on other sites
Advertisement

I've added another video that more clearly shows what's going on. I still haven't figured out what's happening with this. Would it be easier to just implement ellipses or curves for my sloped surfaces? If so, does anyone know a good starting point for adding collision detection/resolution for ellipses to my existing AABB/OBB implementation?

Share this post


Link to post
Share on other sites
I ended up implementing an AABB/Line Segment collision just to test if it would also have these issues, and i ended up figuring out the problem. It was an issue with my collision resolution.
 
When the AABB was resting on the corner of an OBB or on the top-most point of a line segment, it was resolving the Y resolution amount using the formula for the line, but was plugging in an X value that was outside of its range.
 
Here's the line segment/AABB resolution code I ended up going with:
 
public Vector2 GetCollisionResolveAmount(RectangleCollisionObject resolvedObject, LineSegmentCollisionObject line)
{
	Vector2 overlap = Vector2.Zero;
	var topRight = new Vector2(resolvedObject.Position.X + resolvedObject.HalfWidth, resolvedObject.Position.Y - resolvedObject.HalfHeight);
	var topLeft = new Vector2(resolvedObject.Position.X - resolvedObject.HalfWidth, resolvedObject.Position.Y - resolvedObject.HalfHeight);
	var bottomLeft = new Vector2(resolvedObject.Position.X - resolvedObject.HalfWidth, resolvedObject.Position.Y + resolvedObject.HalfHeight);
	var bottomRight = new Vector2(resolvedObject.Position.X + resolvedObject.HalfWidth, resolvedObject.Position.Y + resolvedObject.HalfHeight);

	var leftLinePoint = line.PointA.X < line.PointB.X ? line.PointA : line.PointB;
	var rightLinePoint = line.PointA.X > line.PointB.X ? line.PointA : line.PointB;

	if (leftLinePoint.Y > rightLinePoint.Y) //Line is rotated to the left
	{
		float diffOne = Math.Abs(FindYGivenX(leftLinePoint, rightLinePoint, bottomRight.X) - bottomRight.Y);
		float diffTwo = Math.Abs(FindYGivenX(leftLinePoint, rightLinePoint, topLeft.X) - topLeft.Y);

		if (diffOne < diffTwo) //We're above the line
		{
			if(bottomRight.X > rightLinePoint.X)
				diffOne = Math.Abs(rightLinePoint.Y - bottomRight.Y);
			overlap.Y = diffOne * -1;
		}
		else //We're below the line
		{
			overlap.Y = diffTwo;
		}
	}
	else if (rightLinePoint.Y > leftLinePoint.Y) //Line is rotated to the right
	{
		float diffOne = Math.Abs(FindYGivenX(leftLinePoint, rightLinePoint, bottomLeft.X) - bottomLeft.Y);
		float diffTwo = Math.Abs(FindYGivenX(leftLinePoint, rightLinePoint, topRight.X) - topRight.Y);

		if (diffOne < diffTwo) //We're above the line
		{
			if (bottomLeft.X < leftLinePoint.X)
				diffOne = Math.Abs(leftLinePoint.Y - bottomLeft.Y);

			overlap.Y = diffOne * -1;
		}
		else //We're below the line
		{
			overlap.Y = diffTwo;
		}
	}
	else if (rightLinePoint.X == leftLinePoint.X) //Line is vertically straight
	{
		if (resolvedObject.Position.X < line.PointA.X)
		{
			overlap.X = Math.Abs(topRight.X - line.PointA.X) * -1;
		}
		else
		{
			overlap.X = Math.Abs(line.PointA.X - topLeft.X);
		}
	}
	else //Line is horizontally straight
	{
		if (resolvedObject.Position.Y < line.PointA.Y) //above
		{
			overlap.Y = Math.Abs(bottomLeft.Y - line.PointA.Y) * -1;
		}
		else
		{
			overlap.Y = Math.Abs(topLeft.Y - line.PointA.Y);
		}
	}

	return overlap;
}

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!