Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.
Posted 12 April 2009 - 10:12 PM
Posted 14 April 2009 - 02:10 AM
bool applyReponse(RigidBody& a, RigidBody& b, const Vector& mtd)
{
// inverse masses (for static objects, inversemass = 0).
float ima = a.m_inverseMass;
float imb = b.m_inverseMass;
float im = ima + imb;
if(im < 0.000001f) im = 1.0f;
// separate the objects so they just touch each other
const float relaxation = 0.8f; // relaxation coefficient, arbitrary value in range [0, 1].
a.m_position += mtd * (ima / im) * relaxation;
b.m_position -= mtd * (imb / im) * relaxation;
// collision plane normal. It's the mtd vector, but normalised.
Vector n = mtd;
n.normalise();
// impact velocity along normal of collision 'n'
Vector v = (a.m_velocity - b.m_velocity);
float vn = v.dotProduct(n);
// objects already separating, no reflection
if (vn > 0.0f) return true;
const float cor = 0.7f; // coefficient of restitution. Arbitrary value, in range [0, 1].
// relative collision impulse
float j = -(1.0f + cor) * vn / (im);
// apply collision impulse to the two objects
a.m_velocity += n * (j * ima);
b.m_velocity -= n * (j * imb);
return true;
}
Posted 14 April 2009 - 07:47 PM
Posted 14 April 2009 - 07:58 PM
Posted 14 April 2009 - 08:08 PM
Posted 14 April 2009 - 09:02 PM
Vector closestPoint(const Vector& p, const Rectangle& r)
{
// relative position of sphere centre from the rectangle centre
Vector d = (p - r.m_centre);
// rectangle half-size
Vector h = r.m_halfSize;
// special case when the sphere centre is inside the rectangle
if(fabs(d.x) < h.x && fabs(d.y) < h.y)
{
// use left or right side of the rectangle boundary
// as it is the closest
if((h.x - fabs(d.x)) < (h.y - fabs(d.y)))
{
d.y = 0.0f;
d.x = h.x * sign(d.x);
}
// use top or bottom side of the rectangle boundary
// as it is the closest
else
{
d.x = 0.0f;
d.y = h.y * sign(d.y);
}
}
else
{
// clamp to rectangle boundary
if(fabs(d.x) > h.x) d.x = h.x * sign(d.x);
if(fabs(d.y) > h.y) d.y = h.y * sign(d.y);
}
// the closest point on rectangle from p
Vector c = r.m_centre + d;
return c;
}
bool applyReponse(sphere& a, rectangle& b, const Vector& normal)
{
// inverse masses (for static objects, inversemass = 0).
float ima = a.m_inverseMass;
float imb = b.m_inverseMass;
float im = ima + imb;
if(im < 0.000001f) im = 1.0f;
// impact velocity along normal of collision 'n'
Vector v = (a.m_velocity - b.m_velocity);
float vn = v.dotProduct(normal);
// objects already separating, no reflection
if (vn > 0.0f) return true;
const float cor = 0.7f; // coefficient of restitution. Arbitrary value, in range [0, 1].
// relative collision impulse
float j = -(1.0f + cor) * vn / (im);
// apply collision impulse to the two objects
a.m_velocity += normal * (j * ima);
b.m_velocity -= normal * (j * imb);
return true;
}
void collisionResponse(sphere& s, rectangle& r)
{
Vector closest = closestPoint(s.m_centre, r);
Vector normal = (s.m_centre - closest);
normal.normalise();
applyReponse(s, r, normal);
}
Posted 15 April 2009 - 04:56 PM
Posted 15 April 2009 - 11:49 PM
Quote:
Original post by knonk
Hi Oliii,
I did try to read your explain but still don't get it clearly,
Let me say again your method :
1) Finding the closest point between rectangle and sphere, also is collision point
2) Apply the collision response from collision point
Is it right?
Quote:
I don't understand from second step in your explain(It's easier to understand if u could explain more clearly here) ,Could you tell me more clearly and basically your method,please !
Posted 16 April 2009 - 05:16 PM
Posted 16 April 2009 - 09:51 PM
// separate the objects so they just touch each other
const float relaxation = 0.8f; // relaxation coefficient, arbitrary value in range [0, 1].
a.m_position += mtd * (ima / im) * relaxation;
b.m_position -= mtd * (imb / im) * relaxation;
Posted 16 April 2009 - 11:32 PM
Posted 18 April 2009 - 08:44 AM
#include <windows.h>
#include <gl\glut.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "glut32.lib")
float sign(float a) { return (a>0)? 1.0f : -1.0f; }
float clamp(float x, float min, float max) { return (x < min)? min : (x > max)? max : x; }
float frand(float x) { return (rand() / (float) RAND_MAX) * x; }
float Pi() { static const float _Pi = (float)atan(1.0f) * 4.0; return _Pi; }
struct Vector
{
float x, y;
Vector()
{}
Vector(float _x, float _y)
: x(_x)
, y(_y)
{}
Vector& operator +=(const Vector& V) { x += V.x; y += V.y; return *this; }
Vector& operator -=(const Vector& V) { x -= V.x; y -= V.y; return *this; }
Vector& operator *=(float k) { x *= k ; y *= k ; return *this; }
Vector& operator /=(float k) { x /= k ; y /= k ; return *this; }
Vector operator + (const Vector& V) const { return Vector(x + V.x, y + V.y); }
Vector operator - (const Vector& V) const { return Vector(x - V.x, y - V.y); }
Vector operator * (float k) const { return Vector(x * k, y * k); }
Vector operator / (float k) const { return Vector(x / k, y / k); }
float operator * (const Vector& V) const { return x * V.x + y * V.y; }
float operator ^ (const Vector& V) const { return x * V.y - y * V.x; }
float length() const { return (float)sqrt(x*x + y*y); }
float normalise() { float l = length(); if( l >0.0000001f) { x /= l; y /= l; } return l; }
Vector normalised() const { Vector temp = *this; temp.normalise(); return temp; }
float dotProduct (const Vector& V) const { return (*this) * V; }
Vector scale (const Vector& xScale) const { return Vector(x * xScale.x, y * xScale.y); }
Vector invScale (const Vector& xScale) const { return Vector(x / xScale.x, y / xScale.y); }
Vector rotate(const Vector& C, float a) const
{
float px = (x - C.x) * (float)cos(a) - (y - C.y) * (float)sin(a) + C.x;
float py = (x - C.x) * (float)sin(a) + (y - C.y) * (float)cos(a) + C.y;
return Vector(px, py);
}
Vector& randomise(const Vector& Min, const Vector& Max)
{
x = Min.x + frand(Max.x - Min.x);
y = Min.y + frand(Max.y - Min.y);
return *this;
}
};
struct Colour
{
float r;
float g;
float b;
float a;
Colour(float R, float G, float B, float A)
{
r = R;
g = G;
b = B;
a = A;
}
void render() const
{
glColor4f(r, g, b, a);
}
};
void renderPoint(const Vector& P, Colour col, float radius)
{
col.render();
glBegin(GL_POINTS);
glPointSize(radius);
glVertex2f(P.x, P.y);
glEnd();
}
void renderRectangle(const Vector& P, const Vector& H, Colour col, float radius)
{
col.render();
glBegin(GL_LINE_LOOP);
glLineWidth(radius);
glVertex2f(P.x - H.x, P.y - H.y);
glVertex2f(P.x + H.x, P.y - H.y);
glVertex2f(P.x + H.x, P.y + H.y);
glVertex2f(P.x - H.x, P.y + H.y);
glEnd();
}
void renderArrow(const Vector& P, const Vector& D, Colour col, float radius)
{
col.render();
glLineWidth(radius);
float angle = atan2(D.y, D.x);
glPushMatrix();
glTranslatef(P.x, P.y, 0.0f);
glScalef(D.length(), D.length(), 1.0f);
glRotatef(angle * 180.0f / Pi(), 0, 0, 1);
glBegin(GL_LINES);
glVertex2f(0, 0);
glVertex2f(1, 0);
glVertex2f(1, 0);
glVertex2f(0.9, -0.05);
glVertex2f(1, 0);
glVertex2f(0.9, +0.05);
glEnd();
glPopMatrix();
}
void renderCircle(const Vector& P, float r, Colour col, float radius)
{
col.render();
glLineWidth(radius);
glBegin(GL_LINE_LOOP);
int steps = 16;
float angle = 0.0;
for(int i = 0; i < steps; i ++, angle += (2.0 * Pi()) / (float) steps)
{
Vector D(cos(angle) * r, sin(angle) * r);
glVertex2f(P.x + D.x, P.y + D.y);
}
glVertex2f(P.x + r, P.y);
glEnd();
}
void update(float dt, Vector& velocity, Vector& position, const Vector& screenSize)
{
position += velocity * dt;
velocity *= 0.999f;
if(position.x < 0)
position.x = screenSize.x;
if(position.y < 0)
position.y = screenSize.y;
if(position.x > screenSize.x)
position.x = 0;
if(position.y > screenSize.y)
position.y = 0;
}
Vector closestPointOnRectangle(const Vector& point, const Vector& centre, const Vector& halfSize)
{
// relative position of sphere centre from the rectangle centre
Vector d = (point - centre);
// rectangle half-size
Vector h = halfSize;
// special case when the sphere centre is inside the rectangle
if(fabs(d.x) < h.x && fabs(d.y) < h.y)
{
// use left or right side of the rectangle boundary
// as it is the closest
if((h.x - fabs(d.x)) < (h.y - fabs(d.y)))
{
d.y = 0.0f;
d.x = h.x * sign(d.x);
}
// use top or bottom side of the rectangle boundary
// as it is the closest
else
{
d.x = 0.0f;
d.y = h.y * sign(d.y);
}
}
else
{
// clamp to rectangle boundary
if(fabs(d.x) > h.x) d.x = h.x * sign(d.x);
if(fabs(d.y) > h.y) d.y = h.y * sign(d.y);
}
// the closest point on rectangle from p
Vector c = centre + d;
return c;
}
bool rectangleRectangleColliding(const Vector& rect1Pos, const Vector& rect1HalfSize, const Vector& rect2Pos, const Vector& rect2HalfSize, Vector& mtd)
{
Vector min1 = rect1Pos - rect1HalfSize;
Vector max1 = rect1Pos + rect1HalfSize;
Vector min2 = rect2Pos - rect2HalfSize;
Vector max2 = rect2Pos + rect2HalfSize;
float dx0 = (max2.x - min1.x);
if(dx0 < 0) return false;
float dx1 = (max1.x - min2.x);
if(dx1 < 0) return false;
float dy0 = (max2.y - min1.y);
if(dy0 < 0) return false;
float dy1 = (max1.y - min2.y);
if(dy1 < 0) return false;
mtd = Vector(0, 0);
mtd.x = (dx0 < dx1)? dx0 : -dx1;
mtd.y = (dy0 < dy1)? dy0 : -dy1;
if(fabs(mtd.x) < fabs(mtd.y))
mtd.y = 0;
else
mtd.x = 0;
return true;
}
bool circleRectangleColliding(const Vector& sphereCentre, const float sphereRadius, const Vector& rectPos, const Vector& rectHalfSize, Vector& mtd)
{
Vector pointOnRectangle = closestPointOnRectangle(sphereCentre, rectPos, rectHalfSize);
Vector delta = (sphereCentre - pointOnRectangle);
float distanceSquared = (delta.dotProduct(delta));
if(distanceSquared > sphereRadius * sphereRadius)
return false;
Vector normal = delta / sqrt(distanceSquared);
Vector pointOnSphere = sphereCentre - normal * sphereRadius;
mtd = (pointOnRectangle - pointOnSphere);
renderPoint(pointOnRectangle, Colour(0, 1, 0, 1), 2);
renderPoint(pointOnSphere, Colour(0, 1, 0, 1), 2);
return true;
}
void intersectionResponse(Vector& pa, float ima,
Vector& pb, float imb,
const Vector& intersectionVector)
{
// separate the objects so they just touch each other
const float relaxation = 0.8f; // relaxation coefficient, arbitrary value in range [0, 1].
pa += intersectionVector * (ima / (ima + imb)) * relaxation;
pb -= intersectionVector * (imb / (ima + imb)) * relaxation;
}
void collisionResponse(Vector& va, float ima,
Vector& vb, float imb,
Vector& n)
{
// inverse masses (for static objects, inversemass = 0).
float im = ima + imb;
// impact velocity along normal of collision 'n'
Vector v = (va - vb);
float vn = v.dotProduct(n);
// objects already separating, no reflection
if (vn > 0.0f) return;
const float cor = 0.7f; // coefficient of restitution. Arbitrary value, in range [0, 1].
// relative collision impulse
float j = -(1.0f + cor) * vn / (im);
// apply collision impulse to the two objects
va += n * (j * ima);
vb -= n * (j * imb);
}
int screen_width = 640;
int screen_height = 480;
float framerate = 30.0f;
struct Sphere
{
Vector P;
Vector V;
float r;
float m;
};
struct Rect
{
Vector P;
Vector H;
Vector V;
float m;
};
// the rectangle (two vectors per rectangle, position, and halfsize).
enum { MAX_RECTANGLES = 100 };
int rectangleCount = 0;
Rect rectangles[MAX_RECTANGLES];
Sphere sphere;
Vector mousePos(0, 0);
//-------------------------------------------------------------------------------------------------
//
// OPENGL Functions
//
//-------------------------------------------------------------------------------------------------
void init()
{
sphere.P.randomise(Vector(0, 0), Vector(screen_width, screen_height));
sphere.V = Vector(0, 0);
sphere.m = frand(30) + 10;
sphere.r = frand(20) + 10;
rectangleCount = rand() % 10 + 10;
for(int i = 0; i < rectangleCount; i ++)
{
rectangles[i].P.randomise(Vector(0, 0), Vector(screen_width, screen_height));
rectangles[i].H.randomise(Vector(screen_width / 100, screen_height / 100), Vector(screen_width / 20, screen_height / 20));
rectangles[i].V = Vector(0, 0);
rectangles[i].m = frand(30) + 10;
}
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glViewport( 0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, screen_width, screen_height, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// move spehre towards the mouse
Vector disp = mousePos - sphere.P;
float d = disp.length();
if(d > 5.0) disp *= 5.0f / d;
sphere.V += disp;
float dt = 1.0f / framerate;
// update sphere
update(dt, sphere.V, sphere.P, Vector(screen_width, screen_height));
// update rectangles
for(int i = 0; i < rectangleCount; i ++)
{
update(dt, rectangles[i].V, rectangles[i].P, Vector(screen_width, screen_height));
}
// collide sphere with rectangles
for(int i = 0; i < rectangleCount; i ++)
{
Vector mtd;
if(circleRectangleColliding(sphere.P, sphere.r, rectangles[i].P, rectangles[i].H, mtd))
{
intersectionResponse(sphere.P, 1.0f / sphere.m, rectangles[i].P, 1.0f / rectangles[i].m, mtd);
collisionResponse(sphere.V, 1.0f / sphere.m, rectangles[i].V, 1.0f / rectangles[i].m, mtd.normalised());
}
}
// collide rectangles against each other
for(int i = 0; i < rectangleCount; i ++)
{
for(int j = i+1; j < rectangleCount; j ++)
{
Vector mtd;
if(rectangleRectangleColliding(rectangles[i].P, rectangles[i].H, rectangles[j].P, rectangles[j].H, mtd))
{
intersectionResponse(rectangles[i].P, 1.0f / rectangles[i].m, rectangles[j].P, 1.0f / rectangles[j].m, mtd);
collisionResponse(rectangles[i].V, 1.0f / rectangles[i].m, rectangles[j].V, 1.0f / rectangles[j].m, mtd.normalised());
}
}
}
// render sphere
renderPoint(sphere.P, Colour(1, 0, 0, 1), 5);
renderPoint(mousePos, Colour(1, 0, 0, 1), 5);
renderCircle(sphere.P, sphere.r, Colour(1, 1.0, 1.0, 1), 2);
renderArrow(sphere.P, mousePos-sphere.P, Colour(1, 0.2, 0.2, 1), 1);
// render rectangles
for(int i = 0; i < rectangleCount; i ++)
{
renderPoint(rectangles[i].P, Colour(1, 0, 0, 1), 5);
renderRectangle(rectangles[i].P, rectangles[i].H, Colour(1, 1.0, 0.5, 1), 3);
}
glutSwapBuffers();
}
void reshape(int w,int h)
{
screen_width = w;
screen_height = h;
}
void ticker(int i)
{
display();
glutTimerFunc((int) (1000.0f / framerate), ticker, 0);
}
void keyboard(unsigned char key, int x, int y)
{
if(key == 27)
{
exit(0);
}
if(key == ' ')
{
init();
}
}
void mouse(int x, int y)
{
mousePos.x = x;
mousePos.y = y;
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
glutInitWindowSize(screen_width, screen_height);
glutInitWindowPosition(100,100);
glutCreateWindow("verlet");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutPassiveMotionFunc(mouse);
glutKeyboardFunc(keyboard);
glutTimerFunc((int) (1000.0f / framerate), ticker, 0);
glClearColor(0.0f,0.0f,0.3f,0.1f);
glPointSize(8);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
init();
glutMainLoop();
return 0;
}
Posted 21 April 2009 - 09:33 PM
Posted 22 April 2009 - 11:39 AM
Posted 22 April 2009 - 05:39 PM
Posted 22 April 2009 - 10:35 PM
Posted 27 April 2009 - 05:13 PM
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.
GameDev.net™, the GameDev.net logo, and GDNet™ are trademarks of GameDev.net, LLC.