Jump to content
  • Advertisement
Sign in to follow this  
Thimounier

3D Background damping

This topic is 3159 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! I dont know how should I proceed correctly in a sphere-background (a cube) collision. I've tried something, but its not so good. Does anybody have another sugestion, more "realistic" for the code of these collision? That's what I have done: struct SPHERE { SPHERE* Next; long Index; MATERIAL* Mat; double R[3]; double V[3]; double A[3]; double Rad; double Mass; }; extern double TotalTime; extern double TimeStep; extern double Gravity[3]; extern double BoxMin[3]; extern double BoxMax[3]; /*************************************************************************************************************/ void MED_External_Forces() { for (SPHERE* s = Spheres; s != NULL; s = s->Next) { // Gravity s->A[0] += Gravity[0]; s->A[1] += Gravity[1]; s->A[2] += Gravity[2]; // Background damping ?????? I need another solution :( if (s->R[0] < BoxMin[0] + s->Rad && s->V[0] < 0.0) { s->R[0] = BoxMin[0] + s->Rad; s->V[0] = -s->V[0]; } if (s->R[1] < BoxMin[1] + s->Rad && s->V[1] < 0.0) { s->R[1] = BoxMin[1] + s->Rad; s->V[1] = -s->V[1]; } if (s->R[2] < BoxMin[2] + s->Rad && s->V[2] < 0.0) { s->R[2] = BoxMin[2] + s->Rad; s->V[2] = -s->V[2]; } if (s->R[0] > BoxMax[0] - s->Rad && s->V[0] > 0.0) { s->R[0] = BoxMax[0] - s->Rad; s->V[0] = -s->V[0]; } if (s->R[1] > BoxMax[1] - s->Rad && s->V[1] > 0.0) { s->R[1] = BoxMax[1] - s->Rad; s->V[1] = -s->V[1]; } if (s->R[2] > BoxMax[2] - s->Rad && s->V[2] > 0.0) { s->R[2] = BoxMax[2] - s->Rad; s->V[2] = -s->V[2]; } //it's not good... s1->A[0] = -1000 * s1->V[0]; s1->A[1] = -1000 * s1->V[1]; s1->A[2] = -1000 * s1->V[2]; s2->A[0] = -1000 * s2->V[0]; s2->A[1] = -1000 * s2->V[1]; s2->A[2] = -1000 * s2->V[2]; } } Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Wright, I've got no answers...

I simply want an algoritm for the collision between a sphere and the path, considering the friction (static and dinamic) on the path and the reconstituition of the sphere at the moment of iteraction.

Thanks

Share this post


Link to post
Share on other sites
No answers...

Could somebody help me to find a way to detect the collision between a sphere and a wall (we have a cubic closed box)? The sphere suffers damping...

Thanks anyway.

Share this post


Link to post
Share on other sites
There's two ways you could do the collision detection. You could project the center of the circle into the coordinate space of the box, and then simply check that the point is at least a radii's distance from any axis extent. (Look up a circle vs AABB or OBB test.) Alternatively you could check the circle against the 4 line segments that make up the rectangle. This would be the most flexible solution if you ever decide to use non-rectangular environments.

So once you get collision detection figure out, you should be able to generate a contact point. A point in space and a normal. If the circle collides with a wall, the point will be the intersection, and the normal will point from the point of intersection to the center of the circle.

Given the contact normal it is possible to compute a collision response impulse, based on the current energy of the circle and the coeficient of restitution.


Vector correctiveImpulse = Zero;

//only apply an impulse if the contact is moving towards penetration
if (Dot(circleMomentum, contactNormal) < 0)
correctiveImpulse = Project(circleMomentum, contactNormal) * (-1 - coefRestitution);

circleMomentum += correctiveImpulse;


If coefR is zero, the circle will lose all energy in the direction of the contact normal. If coefR is 1.0f, the circle will reflect off the surface like a bouncy ball. Also note that momentum is simply mass*velocity. The mass can be factored out and the calculation above can be done directly on the velocity of the circle.

Friction is a little more complicated. Essentially you will need to find a reference vector similar to the contactNormal. It is orthogonal to the contactNormal and lies in the plane formed by the contactNormal and the circles velocity. (in 2d this is simply the 2d plane that all entities live in)

You will compute all of your force calculations along this vector, the resultant force or impulse will be along this vector, and it is integrated into the body.

A more comprehensive derivation of the contact impulse calculation, one which includes angular properties can be found here: http://myphysicslab.com/collision.html

Share this post


Link to post
Share on other sites
Thanks for the explanation. And the link is very useful.

I am trying to make this algoritm for the contact detection, but i still have no success. The problem is not the idea, i know what should i do, but translating it into a C code is the most dificult part. Could you please, based on my code (posted above), show me how should i proceed? I dont want you to give me the code, but just an idea of how it must be wrote.

Thank you for the help.

Share this post


Link to post
Share on other sites
For one you definitely need to use a vector object, instead of manually manipulating the x y z values independently.

Second i already explained how to compute the collision impulse per contact point. All you need to do is come up with a list of contact points and run my algorithm on them.

This could be hard to do with your code the way that it is where the collision detection and resolution are jumbled together. They need to be clearly seperated.

You see where you're just negating the velocity when the ball is penetrating the environment? This is bad, and could cause your ball to just sit there and ping pong back and forth along the surface as if it were stuck to it. You need to do the dot product check that my explination included.


If the sphere collides with an edge
{
Move the sphere to the edge.
if (the sphere is moving towards the edge)
apply an impulse in the normal direction as described above.
}


You missed the second if, and you're not correctly computing the impulse, you're just negating one component. This will restrict you to axis aligned environment boundaries. It will be hard to add friction with code organized in that way also.

You should create a contact structure:


struct Contact
{
Vector Point, Normal;
float Time; //or penetration depth
};


Your collision detection algorithm should return the first contact to happen, or a list of contacts, depending on your system. Then, a seperate collision resolution function will take the contact(s) as input and correct the trajectory of the ball.

Let me know if you want me to elaborate anymore on any particular part.

Share this post


Link to post
Share on other sites
Im very happy for your help, but I still haven't made success with my code...
Humbly, I ask you to construct some basis on my existing code of what you are trying to tell me . I think that being 3D make things go hardly...

Since now, thank.

Share this post


Link to post
Share on other sites
I kind of already started an example but honestly i'm too busy to do a proper solution with finding the time of impact and solving the collisions in order as the time step is integrated.

I'll finish my example this evening but it will be most basic, only a small improvement over what you have at the moment. But i'm going to feel pretty bad about calling it my work and making it publicly available. :(

Share this post


Link to post
Share on other sites
Here you go, here's an example in 2D. 3D is not much different.


#include <vector>

struct Vector
{
Vector(float x = 0, float y = 0)
: X(x), Y(y)
{ }

float X, Y;

Vector operator * (float f) const { return Vector(X * f, Y * f); }
Vector operator + (const Vector &v) const { return Vector(X + v.X, Y + v.Y); }
Vector &operator += (const Vector &v) { X += v.X; Y += v.Y; return *this; }
Vector operator - (const Vector &v) const { return Vector(X - v.X, Y - v.Y); }
Vector &operator -= (const Vector &v) { X -= v.X; Y -= v.Y; return *this; }
};

static float Dot(const Vector &left, const Vector &right)
{
return left.X * right.X + left.Y * right.Y;
}

struct Circle
{
Circle(const Vector &center = Vector(), float radius = 1)
: Center(center), Radius(radius)
{ }

Vector Center;
float Radius;
};

struct AABB
{
AABB(const Vector &min = Vector(), const Vector &max = Vector())
: Min(min), Max(max)
{ }

Vector Min, Max;
};

struct Contact
{
Contact(const Vector &point = Vector(), const Vector &normal = Vector(), float penetration = 0)
: Point(point), Normal(normal), Penetration(penetration)
{ }

Vector Point, Normal;
float Penetration;
};

static bool IntersectsInside(const Circle &c, const AABB &a, std::vector<Contact> &output)
{
Vector radius(c.Radius, c.Radius);
Vector maxSidePenetration = (c.Center + radius) - a.Max;
Vector minSidePenetration = a.Min - (c.Center - radius);

size_t oCnt = output.size();

if (maxSidePenetration.X > 0) output.push_back(Contact(Vector(a.Max.X, c.Center.Y), Vector(-1,0), maxSidePenetration.X));
if (maxSidePenetration.Y > 0) output.push_back(Contact(Vector(c.Center.X, a.Max.Y), Vector(0,-1), maxSidePenetration.Y));
if (minSidePenetration.X > 0) output.push_back(Contact(Vector(a.Min.X, c.Center.Y), Vector(1,0), minSidePenetration.X));
if (minSidePenetration.Y > 0) output.push_back(Contact(Vector(c.Center.X, a.Min.Y), Vector(0,1), minSidePenetration.Y));

return (output.size() > oCnt);
}

struct RigidBody
{
RigidBody(const Circle &shape = Circle(), const Vector &position = Vector()
, const Vector &velocity = Vector(), float coefRestitution = 1.0f)
: Shape(shape), Position(position), Velocity(velocity), CoefRestitution(coefRestitution)
{ }

Circle Shape;
Vector Position, Velocity;
float CoefRestitution;
};

struct Simulation
{
AABB Bounds;
std::vector<RigidBody> Bodies;
Vector Gravity;

void TestSetup()
{
Gravity = Vector(0,-10);
Bounds = AABB(Vector(0,0), Vector(200,200));
Bodies.push_back(RigidBody(Circle(Vector(), 10), Vector(), Vector(20,30), 1.0f));
Bodies.push_back(RigidBody(Circle(Vector(), 10), Vector(), Vector(-50,20), 0.5f));
}

void Update(float dt)
{
size_t bCnt = Bodies.size();
for (size_t b = 0; b < bCnt; ++b)
{
RigidBody &body = Bodies;
CollisionAndResolutionWithStaticEnvironment(body);
Integrate(body, dt);
}
}

private:
void CollisionAndResolutionWithStaticEnvironment(RigidBody &rb)
{
std::vector<Contact> contacts;
contacts.reserve(4);

rb.Shape.Center = rb.Position; //ghettohack

if (IntersectsInside(rb.Shape, Bounds, contacts))
{
std::vector<Contact>::iterator c;
for (c = contacts.begin(); c != contacts.end(); ++c)
{
//rectify position
rb.Position += c->Normal * c->Penetration;

float vDotN = Dot(rb.Velocity, c->Normal);
if (vDotN < 0)
{
//moving towards contact, apply impulse
Vector deltaV = c->Normal * vDotN * (-1 - rb.CoefRestitution);
rb.Velocity += deltaV;
}
}
}
}

void Integrate(RigidBody &rb, float dt)
{
rb.Velocity += Gravity * dt;
rb.Position += rb.Velocity * dt;
}
};



Edit: added gravity.

[Edited by - bzroom on October 29, 2009 2:06:09 PM]

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!