Jump to content
  • Advertisement
Sign in to follow this  
Flawe

Circle vs rectangle corner collision

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

Hi all, So I'm trying to do some collision physics and I'm currently working with a circle adn a rectangle. I also want to preserve kinetic energi after collision so the two objects have finite masses. When the circle/ball collides with one of the four sides of the rectangle everything seems to be fine. I do have some problem with the corners though. Here's how I was thinking of solving this: When the circle touches a corner, I use the line between the corner and the middle of the circle to create a normal. Then I use the velocity vector for the collision, decompose it so I get a component along the normal and one perpendicular to it. I do the same with the velocity vector for the rectangle and then I use the two vector components which lie along the normal and use them to collide the two objects as you would with a one dimensional collision. I think this should give a somewhat realistic bounce when the two objects collide, but what I fear is that my code is really messed up. So I would love if someone has the time and take a look at it and give me some feedback what could be wrong. I've been sitting with this for quite some time and you will notice that the further down into the code you get, the more messed up it is. But it's still just a sketch so I blame it on that. I just want the damn collisions to work =) Here's the code for when the ball collides with the top left corner of the rectangle. I think I basically have the same code for all the corners except for when two/three lines where the normal is calculated (since x_pos, y_pos are in the middle of the rectangle). I also got an applet up with this code, you can find it here and see what happens when collisions occur. If you reload the page it should generate new speeds and dimensions for the objects. If you don't wanna look at the applet what happens is that the ball kinda (sometimes) gets stuck inside the rectangle, when it collides with a corner, of course. I think it might have something to do that all the trigonometry with the angles loses what quadrant the angle should be in, or something. Well any help would be greatly appreciated. And the code...
//top left cornet
		if (getDistance(ball_x, ball_y, rect_x-rect_w/2, rect_y-rect_h/2) < ball_r)
		{
			//change color to indicate collision
			ball.setColor(Color.blue);

			//stupid variables for the dot product
			double pt1 = ball_vx;
			double pt2 = ball_vy;
			double pt3 = (rect_x - rect_w/2) - ball_x; //this is the collision normal, a line form the middle of the circle to the corner
			double pt4 = (rect_y - rect_h/2) - ball_y;
			
			//dot product to find angle between ball's velocity vector and collision normal
			double ai = ((pt1*pt3) + (pt2*pt4)) / ((Math.sqrt(pt1*pt1+pt2*pt2)) * (Math.sqrt(pt3*pt3+pt4*pt4)));
			double i = Math.acos(ai);

			//rotate the vector (OBS. might need some tweaking for the different cases if something shows up)
			/*double xp = Math.cos(2*i)*ball_vx - Math.sin(2*i)*ball_vy; //detta ska också ändras för andra fall
			double yp = Math.sin(2*i)*ball_vx + Math.cos(2*i)*ball_vy;
			
			//set final velocity vector
			ball.setVelX(xp);
			ball.setVelY(yp);*/

			//this is the velocity vector for the ball projected on the normal
			double bcv = ball_vec * Math.cos(i);

			//use dot product to find the angle between the rect's velocity vector and the normal
			pt1 = rect_vx;
			pt2 = rect_vy;
			double air = ((pt1*pt3) + (pt2*pt4)) / ((Math.sqrt(pt1*pt1+pt2*pt2)) * (Math.sqrt(pt3*pt3+pt4*pt4)));
			double ir = Math.acos(air);

			//the rect's velocity vector projected on the normal
			double rcv = rect_vec * Math.cos(ir);

			//calculate the velocities after collision
			double ball_final = bcv * ((ball_m-rect_m)/(ball_m+rect_m)) + rcv * ((2*rect_m)/(ball_m+rect_m));
			double rect_final = bcv * ((2*ball_m)/(ball_m+rect_m)) - rcv * ((ball_m-rect_m)/(ball_m+rect_m));

			//now we have the two final vectors on the normal. these need to be used together with the remaining components from the initial velocity vectors
			//to get the final velocity vectors This should be correct in theory, I hope, but I fear the code bellow is messed up.

			//first the ball
			double remaining_component = Math.sin(i) * ball_vec; //get the remaining component from the initial velocity vector (i.e. the one not colliding)
			double ball_f = Math.sqrt(remaining_component*remaining_component + ball_final*ball_final); //the final velocity vector
			//calculate the new angle between the new velocity vector and the normal
			double new_i = Math.atan(ball_final / remaining_component);
			//calculate angle between normal and x-axis
			double norm_a = Math.atan(pt4/pt3);
			//angle between velocity vector and x-axis
			double final_a = norm_a - new_i; //this i'm very uncertain about
			//set the speeds
			ball.setVelX(ball_f * Math.cos(final_a));
			ball.setVelY(ball_f * Math.sin(final_a));

			//now the rectangle
			remaining_component = Math.sin(ir) * rect_vec; //get the remaining component from the initial velocity vector (i.e. the one not colliding)
			double rect_f = Math.sqrt(remaining_component*remaining_component + rect_final*rect_final); //the final velocity vector
			//calculate the new angle between the new velocity vector and the normal
			new_i = Math.atan(rect_final / remaining_component);
			//angle between velocity vector and x-axis
			final_a = norm_a + new_i;
			//set the speeds
			rect.setVelX(rect_f * Math.cos(final_a));
			rect.setVelY(rect_f * Math.sin(final_a));
		}


Share this post


Link to post
Share on other sites
Advertisement
Check if the objects are already moving apart before applying the collision forces. What happens is the objects collide, their velocities update so they are separating, but the velocities were not high enough to separate in one frame. The next frame they are already moving apart but still overlapping so they collide again, which applies forces that pushes the objects towards each other.

Share this post


Link to post
Share on other sites
That was a good point...and probably why the objects got stuck together. I solved this very fast by moving the ball out from the rectangle along the normal 10 pixels. Now they don't get stuck anymore at least, but if you watch the collisions, they're not correct. Or actually, I think they are but it looks like the angles swap in some weird way.

Could anyone take a look at the trigonometry in my code above and see where the error might be? I'm looking for it non-stop but maybe someone else is faster. It's alot to ask to go through the code above but maybe someone has time =)

Here's the applet again -> APPLET
When the ball collides with a side of the rectangle it flashes green and when it collides with a corner it flashes blue.

Share this post


Link to post
Share on other sites
I've done some small corrections to the code where I had to invert tan(dx/dy) to tan(dy/dx) in some places and such...It's still not totally correct though. If anyone wants to watch the uppdated applet above, you can see that in some cases the bounces are actually correct. It looks like the calculations aren't generalized...

Here's the new code if anyone's interested


//top left cornet
if (getDistance(ball_x, ball_y, rect_x-rect_w/2, rect_y-rect_h/2) < ball_r)
{
//change color to indicate collision
ball.setColor(Color.blue);

//stupid variables for the dot product
double pt1 = ball_vx;
double pt2 = ball_vy;
double pt3 = (rect_x - rect_w/2) - ball_x; //this is the collision normal, a line form the middle of the circle to the corner
double pt4 = (rect_y - rect_h/2) - ball_y;

//dot product to find angle between ball's velocity vector and collision normal
double ai = ((pt1*pt3) + (pt2*pt4)) / ((Math.sqrt(pt1*pt1+pt2*pt2)) * (Math.sqrt(pt3*pt3+pt4*pt4)));
double i = Math.acos(ai);

//this is the velocity vector for the ball projected on the normal
double bcv = ball_vec * Math.cos(i);

//use dot product to find the angle between the rect's velocity vector and the normal
pt1 = rect_vx;
pt2 = rect_vy;
double air = ((pt1*pt3) + (pt2*pt4)) / ((Math.sqrt(pt1*pt1+pt2*pt2)) * (Math.sqrt(pt3*pt3+pt4*pt4)));
double ir = Math.acos(air);

//the rect's velocity vector projected on the normal
double rcv = rect_vec * Math.cos(ir);

//calculate the velocities after collision
double ball_final = bcv * ((ball_m-rect_m)/(ball_m+rect_m)) + rcv * ((2*rect_m)/(ball_m+rect_m));
double rect_final = bcv * ((2*ball_m)/(ball_m+rect_m)) - rcv * ((ball_m-rect_m)/(ball_m+rect_m));

//now we have the two final vectors on the normal. these need to be used together with the remaining components from the initial velocity vectors
//to get the final velocity vectors This should be correct in theory, I hope, but I fear the code bellow is messed up.

//first the ball
double remaining_component = Math.sin(i) * ball_vec; //get the remaining component from the initial velocity vector (i.e. the one not colliding)
double ball_f = Math.sqrt(remaining_component*remaining_component + ball_final*ball_final); //the final velocity vector
//calculate the new angle between the new velocity vector and the normal
double new_i = Math.atan(remaining_component / ball_final); //OBSOBS switched places for these two guys
//calculate angle between normal and x-axis
double norm_a = Math.atan(pt4/pt3);
//angle between velocity vector and x-axis
double final_a = new_i - norm_a; //OBS swiched places
//set the speeds
ball.setVelX(ball_f * Math.cos(final_a));
ball.setVelY(ball_f * Math.sin(final_a));

//now the rectangle
remaining_component = Math.sin(ir) * rect_vec; //get the remaining component from the initial velocity vector (i.e. the one not colliding)
double rect_f = Math.sqrt(remaining_component*remaining_component + rect_final*rect_final); //the final velocity vector
//calculate the new angle between the new velocity vector and the normal
new_i = Math.atan(remaining_component / rect_final); //Switched places
//angle between velocity vector and x-axis
final_a = new_i - norm_a;
//set the speeds
rect.setVelX(rect_f * Math.cos(final_a));
rect.setVelY(rect_f * Math.sin(final_a));

}


Share this post


Link to post
Share on other sites
if you want generalised calculations, you should really use vector maths. That bounce stuff can be fix in a few lines of code. No trig either.

Here is the generalised response code.

Here is the box/circle detection, along with the corner detection.

the whole code :


// Find the closest point on the box surface to a point
Vector ClosestPointOnBox(const Vector& Point, const Vector& Centre, const Vector& Extent, bool& inside)
{
Vector Delta = (Point - Centre);
inside = true;

if (fabs(Delta.x) > Extent.x)
{
inside = false;
Delta.x = Extent.x * sign(Delta.x);
}
if (fabs(Delta.y) > Extent.y)
{
inside = false;
Delta.y = Extent.y * sign(Delta.y);
}
if (fabs(Delta.z) > Extent.z)
{
inside = false;
Delta.z = Extent.z * sign(Delta.z);
}

// point was found outside. all good.
if(!inside)
return Centre + Delta;

// find the MTD (Minimum Translation Distance).
Vector MTD;

// calculate the distance of the point form one face along each axes.
MTD.x = (Extent.x - fabs(Delta.x)) * sgn(Delta.x);
MTD.y = (Extent.y - fabs(Delta.y)) * sgn(Delta.y);
MTD.z = (Extent.z - fabs(Delta.z)) * sgn(Delta.z);

// Find the minimum of the three.
if (fabs(MTD.x) < fabs(MTD.y))
{
MTD.y = 0.0f;

if (fabs(MTD.z) < fabs(MTD.x))
MTD.x = 0.0f;
else
MTD.z = 0.0f;
}
else
{
MTD.x = 0.0f;

if (fabs(MTD.z) < fabs(MTD.y))
MTD.y = 0.0f;
else
MTD.z = 0.0f;
}
// point on surface
return Point + MTD;
}





// Resolve a collision, using the conservation of momentum
bool ResolveCollision(const Vector& N, Vector& Va, float ima, Vector& Vb, float imb, float CoR=0.8f, float CoF=0.05f)
{
// relative velocities
Vector V = (Va - Vb);
float vn = V.DotProduct(N); // velocity along normal, or impact velocity
if (vn > 0.0f) return false; // objects moving away from each other.

//-------------------------------------------------
// Collision Impulse
//-------------------------------------------------
float i = (-(1.0f + CoR) * vn / (ima + imb)); // collision impulse.
Vector Ir = N * i; // vector collision impulse
Va += Ir * ima;
Vb -= Ir * imb;

//-------------------------------------------------
// Friction Impulse
//-------------------------------------------------
Vector Vt = V - (vn * N); // velocity projected in plane of collision
Vector If = Vt * (-CoF / (ima + imb)); // friction impulse
Va += If * ima;
Vb -= If * imb;
return true;
}





// Solve the intersection between two embedded objects
bool ResolveIntersection(const Vector& N, float depth, Vector& Ca, float ima, Vector& Cb, float imb, float relaxation=0.5f)
{
Ca += N * depth * (ima / (ima + imb)) * relaxation;
Cb -= N * depth * (imb / (ima + imb)) * relaxation;
return true;
}





// Compute the collision between a box and a sphere
// 1) Detect intersection
// 2) Solve intersection
// 3) Solve collision impulse
bool CollideSphereBox(C_Sphere& S, C_Box& B)
{
// Find the closest point on box to the sphere centre
bool inside;
Vector Pclosest = ClosestPointOnBox(S.m_Centre, B.m_Centre, B.m_HalfSize, inside);

// Check if closest point is inside the sphere
Vector Delta = (S.m_Centre - Pclosest);
float delta_length_squared = Delta.DotProduct(Delta);

// Sphere and box dont intersect
if(delta_length_squared > S.m_Radius * S.m_Radius) return false;

// Generate the collision plane information
float delta_length = sqrt(delta_length_squared);
Vector Ncoll;
float dcoll;

// Ball centre was inside the box.
// The intersection is deep.
if(inside)
delta_length *= -1.0f;

Ncoll = Delta / delta_length;
dcoll = S.m_Radius - delta_length;

// resolve the intersection
ResolveIntersection(Ncoll, dcoll, S.m_Centre, S.m_InverseMass, B.m_Centre, B.m_InverseMass);

// resolve the collision
ResolveCollision(Ncoll, S.m_Velocity, S.m_InverseMass, B.m_Velocity, B.m_InverseMass);

return true;
}




[Edited by - oliii on March 25, 2007 1:56:37 PM]

Share this post


Link to post
Share on other sites
yeah, I don't know what's going on. I can't seem to access anything from my account... :/

hmm that's interesting. I posted after you, and my post is inserted before yours. GDnet gremlins on a rampage...

Share this post


Link to post
Share on other sites
Thanx for the reply. Looks really great. I'm having a hard time understanding all the code but I'll probably get through it. Would love to see that demo but it doesn't seem to work.

Share this post


Link to post
Share on other sites
here's the full source. you will need glfw (gl framework).


/*
------------------------------------------------------------------
File: main.cpp
Started: 21/03/2007 22:33:14

$Header: $
$Revision: $
$Locker: $
$Date: $

Author: Olivier renault
------------------------------------------------------------------
Module:
Description:
------------------------------------------------------------------
$History: $
------------------------------------------------------------------
*/


#include <GL/glfw.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#pragma comment( lib, "opengl32.lib")
#pragma comment( lib, "glu32.lib")
#pragma comment( lib, "glfw.lib")
#pragma comment( lib, "glfwdll.lib")

// crappy non-ansi MSDEV compiler compliance
#define for if(0); else for

extern int Update(double deltaTime);
extern int Init();
extern int Shutdown();

int screen_width = 800;
int screen_height = 600;


int Run()
{
static double time = 0.0f;
const double desiredTime = 1.0f / 60.0f;

double oldTime = time;
while (glfwGetTime() - time < desiredTime)
{}
time = glfwGetTime();
double deltaTime = time - oldTime;

return Update(deltaTime);
}

int main( void )
{
int running = GL_TRUE;

glfwInit();

Init();

if ( !glfwOpenWindow( screen_width, screen_height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW ) )
{
glfwTerminate();

return -1;
}

while( running )
{
running = Run();

if (glfwGetKey( GLFW_KEY_SPACE ))
Init();

running &= (!glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED ));
}

Shutdown();

glfwTerminate();

return 0;
}


inline float fsign(float x) { return (x < 0.0f)? -1.0f : 1.0f; }
inline float frand(float x=1.0f) { return (rand() / (float) RAND_MAX) * x; }
inline float frand(float a, float b) { return a + frand(b- a); }
inline void fswap(float& a, float& b) { float c = a; a = b; b = c; }
inline float pi (void) { static const float pi = (float) atan(1.0f) * 4.0f; return pi; }

class Vector
{
public:
float x, y, z;

inline Vector(void)
{}

Vector(const Vector& V)
: x(V.x)
, y(V.y)
, z(V.z)
{}

Vector(float ix,float iy, float iz=0.0f)
: x(ix)
, y(iy)
, z(iz)
{}

inline Vector &operator /=(const float scalar) { x /= scalar; y /= scalar; z /= scalar; return *this; }

inline Vector &operator *=(const float scalar) { x *= scalar; y *= scalar; z *= scalar; return *this; }

inline Vector &operator +=(const Vector &Other) { x += Other.x; y += Other.y; z += Other.z; return *this; }

inline Vector &operator -=(const Vector &Other) { x -= Other.x; y -= Other.y; return *this; }

inline float operator * (const Vector &V) const { return (x*V.x) + (y*V.y) + (z*V.z); } // dot product

inline Vector operator * (float s) const { Vector T(*this); return T *= s; }

inline Vector operator / (float s) const { Vector T(*this); return T /= s; }

inline Vector operator + (const Vector &V) const { Vector T(*this); return T += V; }

inline Vector operator - (const Vector &V) const { Vector T(*this); return T -= V; }

friend Vector operator * (float k, const Vector& V) { return (V * k); }

inline Vector operator -(void) const { return Vector(-x, -y, -z); }

inline float DotProduct(const Vector& V) { return (*this) * V; }

inline float LengthSquared(void) const { return (*this) * (*this); }

inline Vector Scale(const Vector& V) { return Vector(x*V.x, y*V.y, z*V.z); }

inline float Length(void) const { return (float) sqrt(LengthSquared()); }

float Normalise(void)
{
float fLength = Length();

if (fLength == 0.0f)
return 0.0f;

(*this) *= (1.0f / fLength);

return fLength;
}

Vector Normalised(void) const
{
Vector T(*this);
T.Normalise();
return T;
}
};


class C_Sphere
{
public:
C_Sphere() {}

C_Sphere(const Vector& Centre, float radius, float mass=1.0f)
: m_Centre(Centre)
, m_Velocity(0, 0, 0)
, m_Radius(radius)
, m_InverseMass(mass > 0.00001f? 1.0f / mass : 0.0f)
{}

void Update(float dt)
{
m_Centre += m_Velocity * dt;
}

void Render()
{
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINE_LOOP);
float a = 0.0f;
float da = pi() / 16.0f;

for(int i = 0; i < 32; i ++, a += da)
{
Vector P = m_Centre + Vector((float)cos(a), (float)sin(a), 0.0f) * m_Radius;
glVertex2f(P.x, P.y);
}
glEnd();

}

Vector m_Centre;
Vector m_Velocity;
float m_Radius;
float m_InverseMass;
};


class C_Box
{
public:
C_Box() {}

C_Box(const Vector& Centre, const Vector& HalfSize, float mass=1.0f)
: m_Centre(Centre)
, m_Velocity(0, 0, 0)
, m_HalfSize(HalfSize)
, m_InverseMass(mass > 0.00001f? 1.0f / mass : 0.0f)
{}

void Update(float dt)
{
m_Centre += m_Velocity * dt;
}

void Render()
{
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINE_LOOP);
glVertex2f(m_Centre.x - m_HalfSize.x, m_Centre.y - m_HalfSize.y);
glVertex2f(m_Centre.x - m_HalfSize.x, m_Centre.y + m_HalfSize.y);
glVertex2f(m_Centre.x + m_HalfSize.x, m_Centre.y + m_HalfSize.y);
glVertex2f(m_Centre.x + m_HalfSize.x, m_Centre.y - m_HalfSize.y);
glEnd();
}

Vector m_Centre;
Vector m_Velocity;
Vector m_HalfSize;
float m_InverseMass;
};

C_Box Walls[4];
C_Sphere Ball;
C_Box Paddle;

int Init()
{
Vector P[4] = { Vector(-1.0f, 0.0f, 10.0f), Vector(1.0f, 0.0f, 10.0f), Vector(0.0f, -1.0f, 10.0f), Vector(0.0f, 1.0f, 10.0f) };
Vector E[4] = { Vector(0.2f, 1.0f, 10.0f), Vector(0.2f, 1.0f, 10.0f), Vector(1.0f, 0.2f, 10.0f), Vector(1.0f, 0.2f, 10.0f) };


Vector L(screen_width * 0.5f, screen_height * 0.5f, 100.0f);

for(int i = 0; i < 4; i ++)
{
Vector C = L + P.Scale(L);
Vector H = E.Scale(L);
Walls = C_Box(C, H, 0.0f);
}

Paddle = C_Box(L, L.Scale(Vector(0.1f, 0.05f, 5.0f)), 1000.0f);
Ball = C_Sphere(L + L * 0.5f, L.Length() * 0.05f, 1.0f);
Paddle.m_Centre.z = Ball.m_Centre.z = 0.0f;

return 1;
}

int Shutdown()
{
return 1;
}

int Render()
{
glViewport( 0, 0, screen_width, screen_height );
glClearColor( 0.0f, 0.0f, 0.0f, 0.1f );
glClear( GL_COLOR_BUFFER_BIT );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0f, screen_width, screen_height, 0.0f);

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

for(int i = 0; i < 4; i ++)
{
Walls.Render();
}
Paddle.Render();
Ball.Render();

glfwSwapBuffers();

//printf("delta : %f ms, %f fps.\n", deltaTime * 1000.0f, 1.0f / deltaTime);
return 1;
}

int Update(double deltaTime)
{
int x, y;
glfwGetMousePos(&x, &y);
Vector Delta = Vector(x, y) - Paddle.m_Centre;
Paddle.m_Velocity = Delta / deltaTime;

Ball.m_Velocity += Vector(0.0f, 500.0f * deltaTime, 0.0f);

Paddle.Update(deltaTime);
Ball.Update(deltaTime);

extern bool CollideSphereBox(C_Sphere& S, C_Box& B);

for(int i = 0; i < 4; i ++)
{
CollideSphereBox(Ball, Walls);
}
CollideSphereBox(Ball, Paddle);


Render();
return 1;
}

// Find the closest point on the box surface to a point
Vector ClosestPointOnBox(const Vector& Point, const Vector& Centre, const Vector& Extent, bool& inside)
{
Vector Delta = (Point - Centre);
inside = true;

if (fabs(Delta.x) > Extent.x)
{
inside = false;
Delta.x = Extent.x * fsign(Delta.x);
}
if (fabs(Delta.y) > Extent.y)
{
inside = false;
Delta.y = Extent.y * fsign(Delta.y);
}
if (fabs(Delta.z) > Extent.z)
{
inside = false;
Delta.z = Extent.z * fsign(Delta.z);
}

// point was found outside. all good.
if(!inside)
return Centre + Delta;

// find the MTD (Minimum Translation Distance).
Vector MTD;

// calculate the distance of the point form one face along each axes.
MTD.x = (Extent.x - fabs(Delta.x)) * fsign(Delta.x);
MTD.y = (Extent.y - fabs(Delta.y)) * fsign(Delta.y);
MTD.z = (Extent.z - fabs(Delta.z)) * fsign(Delta.z);

// Find the minimum of the three.
if (fabs(MTD.x) < fabs(MTD.y))
{
MTD.y = 0.0f;

if (fabs(MTD.z) < fabs(MTD.x))
MTD.x = 0.0f;
else
MTD.z = 0.0f;
}
else
{
MTD.x = 0.0f;

if (fabs(MTD.z) < fabs(MTD.y))
MTD.y = 0.0f;
else
MTD.z = 0.0f;
}
// point on surface
return Point + MTD;
}

// Resolve a collision, using the conservation of momentum
bool ResolveCollision(const Vector& N, Vector& Va, float ima, Vector& Vb, float imb, float CoR=0.8f, float CoF=0.15f)
{
// relative velocities
Vector V = (Va - Vb);
float vn = V.DotProduct(N); // velocity along normal, or impact velocity
if (vn > 0.0f) return false; // objects moving away from each other.

//-------------------------------------------------
// Collision Impulse
//-------------------------------------------------
float i = (-(1.0f + CoR) * vn / (ima + imb)); // collision impulse.
Vector Ir = N * i; // vector collision impulse
Va += Ir * ima;
Vb -= Ir * imb;

//-------------------------------------------------
// Friction Impulse
//-------------------------------------------------
Vector Vt = V - (vn * N); // velocity projected in plane of collision
Vector If = Vt * (-CoF / (ima + imb)); // friction impulse
Va += If * ima;
Vb -= If * imb;
return true;
}

// Solve the intersection between two embedded objects
bool ResolveIntersection(const Vector& N, float depth, Vector& Ca, float ima, Vector& Cb, float imb, float relaxation=0.5f)
{
Ca += N * depth * (ima / (ima + imb)) * relaxation;
Cb -= N * depth * (imb / (ima + imb)) * relaxation;
return true;
}

// Compute the collision between a box and a sphere
// 1) Detect intersection
// 2) Solve intersection
// 3) Solve collision impulse
bool CollideSphereBox(C_Sphere& S, C_Box& B)
{
// Find the closest point on box to the sphere centre
bool inside;
Vector Pclosest = ClosestPointOnBox(S.m_Centre, B.m_Centre, B.m_HalfSize, inside);

// Check if closest point is inside the sphere
Vector Delta = (S.m_Centre - Pclosest);
float delta_length_squared = Delta.DotProduct(Delta);

// Sphere and box dont intersect
if(delta_length_squared > S.m_Radius * S.m_Radius) return false;

// Generate the collision plane information
float delta_length = sqrt(delta_length_squared);
Vector Ncoll;
float dcoll;

// Ball centre was inside the box.
// The intersection is deep.
if(inside)
delta_length *= -1.0f;

Ncoll = Delta / delta_length;
dcoll = S.m_Radius - delta_length;

// resolve the intersection
ResolveIntersection(Ncoll, dcoll, S.m_Centre, S.m_InverseMass, B.m_Centre, B.m_InverseMass);

// resolve the collision
ResolveCollision(Ncoll, S.m_Velocity, S.m_InverseMass, B.m_Velocity, B.m_InverseMass);

return true;
}


Share this post


Link to post
Share on other sites
Thanx Oliii, that's some great help. I'm just wondering one thing...why use Inverse Mass? Could you maybe explain the impulse and friction formulae a little more, because I don't recognize them and I'm having a hard time understanding them.


//-------------------------------------------------
// Collision Impulse
//-------------------------------------------------
float i = (-(1.0f + CoR) * vn / (ima + imb)); // collision impulse.
Vector Ir = N * i; // vector collision impulse
Va += Ir * ima;
Vb -= Ir * imb;

//-------------------------------------------------
// Friction Impulse
//-------------------------------------------------
Vector Vt = V - (vn * N); // velocity projected in plane of collision
Vector If = Vt * (-CoF / (ima + imb)); // friction impulse
Va += If * ima;
Vb -= If * imb;

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!