[Fix] Made the linear component of collisions with static bodies work.
This commit is contained in:
parent
40f6d6dc37
commit
799e1de136
@ -1,5 +1,5 @@
|
|||||||
noinst_LIBRARIES = libcollider.a
|
noinst_LIBRARIES = libcollider.a
|
||||||
libcollider_a_SOURCES = geom_tree.cpp geom.cpp collision_space.cpp
|
libcollider_a_SOURCES = geom_tree.cpp geom.cpp collision_space.cpp
|
||||||
|
|
||||||
include_HEADERS = geom_tree.h geom.h collision_space.h collider.h
|
include_HEADERS = geom_tree.h geom.h collision_space.h collider.h collision_contact.h
|
||||||
|
|
||||||
|
@ -4,14 +4,5 @@
|
|||||||
#include "collision_space.h"
|
#include "collision_space.h"
|
||||||
#include "geom.h"
|
#include "geom.h"
|
||||||
|
|
||||||
class Geom;
|
#include "collision_contact.h"
|
||||||
|
|
||||||
struct CollisionContact {
|
|
||||||
vector3d pos;
|
|
||||||
vector3d normal;
|
|
||||||
double depth;
|
|
||||||
int triIdx;
|
|
||||||
void* userData1, *userData2;
|
|
||||||
int geomFlag;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
14
src/collider/collision_contact.h
Normal file
14
src/collider/collision_contact.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct CollisionContact {
|
||||||
|
vector3d pos;
|
||||||
|
vector3d normal;
|
||||||
|
double depth;
|
||||||
|
int triIdx;
|
||||||
|
void* userData1, *userData2;
|
||||||
|
int geomFlag;
|
||||||
|
CollisionContact(void) {
|
||||||
|
depth = 0; triIdx = -1; userData1 = userData2 = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -58,7 +58,7 @@ void CollisionSpace::TraceRay(const vector3d& start, const vector3d& dir, isect_
|
|||||||
CollideRaySphere(start, dir, isect);
|
CollideRaySphere(start, dir, isect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*)) {
|
void CollisionSpace::CollideGeoms(Geom* a) {
|
||||||
/* Our big Aabb. */
|
/* Our big Aabb. */
|
||||||
vector3d pos = a->GetPosition();
|
vector3d pos = a->GetPosition();
|
||||||
Aabb bigAabb;
|
Aabb bigAabb;
|
||||||
@ -68,7 +68,7 @@ void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*))
|
|||||||
|
|
||||||
/* First test this reested sh*t against the planet sphere thing. */
|
/* First test this reested sh*t against the planet sphere thing. */
|
||||||
if(sphere.radius != 0) {
|
if(sphere.radius != 0) {
|
||||||
a->CollideSphere(sphere, callback);
|
a->CollideSphere(sphere);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
|
for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
|
||||||
@ -79,17 +79,24 @@ void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*))
|
|||||||
bigAabb2.min += pos2;
|
bigAabb2.min += pos2;
|
||||||
bigAabb2.max += pos2;
|
bigAabb2.max += pos2;
|
||||||
if(bigAabb.Intersects(bigAabb2)) {
|
if(bigAabb.Intersects(bigAabb2)) {
|
||||||
a->Collide(*i, callback);
|
a->Collide(*i);
|
||||||
if(!(*i)->HasMoved()) (*i)->Collide(a, callback);
|
if(!(*i)->HasMoved()) (*i)->Collide(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollisionSpace::Collide(void (*callback)(CollisionContact*)) {
|
void CollisionSpace::Collide(void (*callback)(CollisionContact*)) {
|
||||||
/* For now, do a totally stupid intersection of every body on every other. */
|
|
||||||
for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
|
for(std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) {
|
||||||
if((*i)->HasMoved()) CollideGeoms(*i, callback);
|
(*i)->contact = CollisionContact();
|
||||||
|
if((*i)->HasMoved()) {
|
||||||
|
CollideGeoms(*i);
|
||||||
|
if((*i)->HasMoved()) {
|
||||||
|
CollideGeoms(*i);
|
||||||
|
if((*i)->contact.triIdx != -1)
|
||||||
|
(*callback)(&(*i)->contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CollideGeoms(Geom* a, void (*callback)(CollisionContact*));
|
void CollideGeoms(Geom* a);
|
||||||
void CollideRaySphere(const vector3d& start, const vector3d& dir, isect_t* isect);
|
void CollideRaySphere(const vector3d& start, const vector3d& dir, isect_t* isect);
|
||||||
std::list<Geom*> m_geoms;
|
std::list<Geom*> m_geoms;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ vector3d Geom::GetPosition(void) const {
|
|||||||
m_orient[m_orientIdx][14]);
|
m_orient[m_orientIdx][14]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Geom::CollideSphere(Sphere& sphere, void(*callback)(CollisionContact*)) {
|
void Geom::CollideSphere(Sphere& sphere) {
|
||||||
/*
|
/*
|
||||||
* If the geom is actually within the sphere, create a contact so
|
* If the geom is actually within the sphere, create a contact so
|
||||||
* that we can't fall into spheres forever and ever and ever..
|
* that we can't fall into spheres forever and ever and ever..
|
||||||
@ -50,15 +50,13 @@ void Geom::CollideSphere(Sphere& sphere, void(*callback)(CollisionContact*)) {
|
|||||||
vector3d v = GetPosition() - sphere.pos;
|
vector3d v = GetPosition() - sphere.pos;
|
||||||
const double len = v.Length();
|
const double len = v.Length();
|
||||||
if(len < sphere.radius) {
|
if(len < sphere.radius) {
|
||||||
CollisionContact c;
|
contact.pos = GetPosition();
|
||||||
c.pos = GetPosition();
|
contact.normal = (1.0/len)*v;
|
||||||
c.normal = (1.0/len)*v;
|
contact.depth = sphere.radius - len;
|
||||||
c.depth = sphere.radius - len;
|
contact.triIdx = 0;
|
||||||
c.triIdx = 0;
|
contact.userData1 = this->m_data;
|
||||||
c.userData1 = this->m_data;
|
contact.userData2 = sphere.userData;
|
||||||
c.userData2 = sphere.userData;
|
contact.geomFlag = 0;
|
||||||
c.geomFlag = 0;
|
|
||||||
(*callback)(&c);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(int i = 0; i < m_geomtree->m_numVertices; i++) {
|
for(int i = 0; i < m_geomtree->m_numVertices; i++) {
|
||||||
@ -80,15 +78,13 @@ void Geom::CollideSphere(Sphere& sphere, void(*callback)(CollisionContact*)) {
|
|||||||
if(i2 > 0) {
|
if(i2 > 0) {
|
||||||
if(i1 > 0) {
|
if(i1 > 0) {
|
||||||
if(i1 < len) {
|
if(i1 < len) {
|
||||||
CollisionContact c;
|
contact.pos = from + dir*i1;
|
||||||
c.pos = from + dir*i1;
|
contact.normal = vector3d::Normalize(v);
|
||||||
c.normal = vector3d::Normalize(v);
|
contact.depth = len - i1;
|
||||||
c.depth = len - i1;
|
contact.triIdx = 0;
|
||||||
c.triIdx = 0;
|
contact.userData1 = this->m_data;
|
||||||
c.userData1 = this->m_data;
|
contact.userData2 = sphere.userData;
|
||||||
c.userData2 = sphere.userData;
|
contact.geomFlag = 0;
|
||||||
c.geomFlag = 0;
|
|
||||||
(*callback)(&c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +92,7 @@ void Geom::CollideSphere(Sphere& sphere, void(*callback)(CollisionContact*)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) {
|
void Geom::Collide(Geom* b) {
|
||||||
m_moved = false;
|
m_moved = false;
|
||||||
for(int i = 0; i < m_geomtree->m_numVertices; i++) {
|
for(int i = 0; i < m_geomtree->m_numVertices; i++) {
|
||||||
vector3d v(&m_geomtree->m_vertices[3*i]);
|
vector3d v(&m_geomtree->m_vertices[3*i]);
|
||||||
@ -116,19 +112,20 @@ void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) {
|
|||||||
isect.triIdx = -1;
|
isect.triIdx = -1;
|
||||||
b->m_geomtree->TraceRay(_from, _dir, &isect);
|
b->m_geomtree->TraceRay(_from, _dir, &isect);
|
||||||
if(isect.triIdx != -1) {
|
if(isect.triIdx != -1) {
|
||||||
CollisionContact c;
|
const double depth = len - isect.dist;
|
||||||
|
if(depth > contact.depth) {
|
||||||
/* In world coords. */
|
/* In world coords. */
|
||||||
c.pos = b->GetTransform() * (from + dir*isect.dist);
|
contact.pos = b->GetTransform() * (from + dir*isect.dist);
|
||||||
vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx);
|
vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx);
|
||||||
c.normal = vector3d(n.x, n.y, n.z);
|
contact.normal = vector3d(n.x, n.y, n.z);
|
||||||
c.normal = b->GetTransform().ApplyRotationOnly(c.normal);
|
contact.normal = b->GetTransform().ApplyRotationOnly(contact.normal);
|
||||||
|
|
||||||
c.depth = len - isect.dist;
|
contact.depth = len - isect.dist;
|
||||||
c.triIdx = isect.triIdx;
|
contact.triIdx = isect.triIdx;
|
||||||
c.userData1 = m_data;
|
contact.userData1 = m_data;
|
||||||
c.userData2 = b->m_data;
|
contact.userData2 = b->m_data;
|
||||||
c.geomFlag = b->m_geomtree->GetTriFlag(isect.triIdx);
|
contact.geomFlag = b->m_geomtree->GetTriFlag(isect.triIdx);
|
||||||
(*callback)(&c);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../matrix4x4.h"
|
#include "../matrix4x4.h"
|
||||||
#include "../vector3.h"
|
#include "../vector3.h"
|
||||||
|
#include "collision_contact.h"
|
||||||
|
|
||||||
class GeomTree;
|
class GeomTree;
|
||||||
class isect_t;
|
class isect_t;
|
||||||
class CollisionContact;
|
|
||||||
class Sphere;
|
class Sphere;
|
||||||
|
|
||||||
class Geom {
|
class Geom {
|
||||||
@ -21,10 +21,12 @@ public:
|
|||||||
bool IsEnabled(void) { return m_active; }
|
bool IsEnabled(void) { return m_active; }
|
||||||
bool HasMoved(void) { return m_moved; }
|
bool HasMoved(void) { return m_moved; }
|
||||||
GeomTree* GetGeomTree(void) { return m_geomtree; }
|
GeomTree* GetGeomTree(void) { return m_geomtree; }
|
||||||
void Collide(Geom* b, void(*callback)(CollisionContact*));
|
void Collide(Geom* b);
|
||||||
void CollideSphere(Sphere& sphere, void (*callback)(CollisionContact*));
|
void CollideSphere(Sphere& sphere);
|
||||||
void SetUserData(void* d) { m_data = d; }
|
void SetUserData(void* d) { m_data = d; }
|
||||||
void* GetUserData(void) { return m_data; }
|
void* GetUserData(void) { return m_data; }
|
||||||
|
|
||||||
|
CollisionContact contact;
|
||||||
private:
|
private:
|
||||||
/* double-buffer position so we can keep previous position. */
|
/* double-buffer position so we can keep previous position. */
|
||||||
matrix4x4d m_orient[2], m_invOrient;
|
matrix4x4d m_orient[2], m_invOrient;
|
||||||
|
@ -93,6 +93,10 @@ vector3d DynamicBody::GetPosition(void) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DynamicBody::TimeStepUpdate(const float timeStep) {
|
void DynamicBody::TimeStepUpdate(const float timeStep) {
|
||||||
|
/*
|
||||||
|
* XXX Remember this is used to step back also in the collision code.
|
||||||
|
* very silly btw.
|
||||||
|
*/
|
||||||
if(m_enabled) {
|
if(m_enabled) {
|
||||||
m_vel += timeStep * m_force * (1.0/m_mass);
|
m_vel += timeStep * m_force * (1.0/m_mass);
|
||||||
m_angVel += timeStep * m_torque * (1.0 / m_angInertia);
|
m_angVel += timeStep * m_torque * (1.0 / m_angInertia);
|
||||||
|
@ -271,6 +271,7 @@ void Space::UpdateFramesOfReference(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static bool _OnCollision(dGeomID g1, dGeomID g2, Object* o1, Object* o2,
|
static bool _OnCollision(dGeomID g1, dGeomID g2, Object* o1, Object* o2,
|
||||||
int numContacts, dContact contacts[]) {
|
int numContacts, dContact contacts[]) {
|
||||||
if((o1->IsType(Object::LASER)) || (o2->IsType(Object::LASER))) {
|
if((o1->IsType(Object::LASER)) || (o2->IsType(Object::LASER))) {
|
||||||
@ -305,14 +306,7 @@ static bool _OnCollision(dGeomID g1, dGeomID g2, Object* o1, Object* o2,
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
static void dump_contact(const dContact* c) {
|
|
||||||
printf("pos %f,%f,%f\n", c->geom.pos[0], c->geom.pos[1], c->geom.pos[2]);
|
|
||||||
printf("normal %f,%f,%f\n", c->geom.normal[0], c->geom.normal[1], c->geom.normal[2]);
|
|
||||||
printf("depth %f\n", c->geom.depth);
|
|
||||||
printf("side1:side2 %d:%d\n", c->geom.side1, c->geom.side2);
|
|
||||||
printf("fdir1 %f,%f,%f\n", c->fdir1[0], c->fdir1[1], c->fdir1[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
|
static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
|
||||||
Body* pb1, *pb2;
|
Body* pb1, *pb2;
|
||||||
@ -332,50 +326,42 @@ static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_CONTACTS 1
|
|
||||||
/* XXX SO REESTED!! 1 CONTACT PER PHYSICS TICK?! WTH?! */
|
|
||||||
static int contact_num;
|
|
||||||
static void hitCallback(CollisionContact* c) {
|
static void hitCallback(CollisionContact* c) {
|
||||||
if(contact_num++ >= MAX_CONTACTS) return;
|
|
||||||
printf("AUCH!! %x (depth %f)\n", SDL_GetTicks(), c->depth);
|
printf("AUCH!! %x (depth %f)\n", SDL_GetTicks(), c->depth);
|
||||||
#if 0
|
|
||||||
dContact contact;
|
|
||||||
|
|
||||||
contact.surface.mode = dContactBounce;
|
|
||||||
contact.surface.mu = 0.8;
|
|
||||||
contact.surface.mu2 = 0;
|
|
||||||
contact.surface.bounce = 0.1;
|
|
||||||
contact.surface.bounce_vel = 0.1;
|
|
||||||
|
|
||||||
contact.geom.pos[0] = c->pos.x;
|
|
||||||
contact.geom.pos[1] = c->pos.y;
|
|
||||||
contact.geom.pos[2] = c->pos.z;
|
|
||||||
contact.geom.pos[3] = 1;
|
|
||||||
contact.geom.normal[0] = c->normal.x;
|
|
||||||
contact.geom.normal[1] = c->normal.y;
|
|
||||||
contact.geom.normal[2] = c->normal.z;
|
|
||||||
contact.geom.normal[3] = 1;
|
|
||||||
contact.geom.depth = c->depth;
|
|
||||||
contact.geom.g1 = 0;
|
|
||||||
contact.geom.g2 = 0;
|
|
||||||
contact.fdir1[0] = 0;
|
|
||||||
contact.fdir1[1] = 0;
|
|
||||||
contact.fdir1[2] = 0;
|
|
||||||
|
|
||||||
Object* po1 = static_cast<Object*>(c->userData1);
|
Object* po1 = static_cast<Object*>(c->userData1);
|
||||||
Object* po2 = static_cast<Object*>(c->userData2);
|
Object* po2 = static_cast<Object*>(c->userData2);
|
||||||
|
|
||||||
if(!_OnCollision2(po1, po2, c)) return;
|
if(!_OnCollision2(po1, po2, c)) return;
|
||||||
|
|
||||||
dBodyID b1 = 0;
|
const bool po1_isDynBody = po1->IsType(Object::DYNAMICBODY);
|
||||||
dBodyID b2 = 0;
|
const bool po2_isDynBody = po2->IsType(Object::DYNAMICBODY);
|
||||||
/* Get the dynamics body for each geom. */
|
/* Collision response. */
|
||||||
if(po1->IsType(Object::DYNAMICBODY)) b1 = static_cast<DynamicBody*>(po1)->m_body;
|
assert(po1_isDynBody || po2_isDynBody);
|
||||||
if(po2->IsType(Object::DYNAMICBODY)) b2 = static_cast<DynamicBody*>(po2)->m_body;
|
|
||||||
|
|
||||||
dJointID j = dJointCreateContact(Space::world, _contactgroup, &contact);
|
if(po1_isDynBody && po2_isDynBody) {
|
||||||
dJointAttach(j, b1, b2);
|
|
||||||
#endif
|
} else {
|
||||||
|
/* One body is static. */
|
||||||
|
vector3d hitNormal;
|
||||||
|
if(po2_isDynBody) hitNormal = -c->normal;
|
||||||
|
else hitNormal = c->normal;
|
||||||
|
printf("Hi! %f,%f,%f\n", hitNormal.x, hitNormal.y, hitNormal.z);
|
||||||
|
|
||||||
|
DynamicBody* mover;
|
||||||
|
if(po1_isDynBody) mover = static_cast<DynamicBody*>(po1);
|
||||||
|
else mover = static_cast<DynamicBody*>(po2);
|
||||||
|
|
||||||
|
const vector3d vel = mover->GetVelocity();
|
||||||
|
vector3d reflect = vel - (hitNormal * vector3d::Dot(vel, hitNormal) * 2.0f);
|
||||||
|
/* Dampen a little. */
|
||||||
|
reflect = reflect * 0.5;
|
||||||
|
|
||||||
|
/* Step back. */
|
||||||
|
mover->TimeStepUpdate(-L3D::GetTimeStep());
|
||||||
|
/* and set altered velocity. */
|
||||||
|
mover->SetVelocity(reflect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -464,7 +450,6 @@ void Space::ApplyGravity(void) {
|
|||||||
void Space::TimeStep(float step) {
|
void Space::TimeStep(float step) {
|
||||||
ApplyGravity();
|
ApplyGravity();
|
||||||
|
|
||||||
contact_num = 0;
|
|
||||||
CollideFrame(rootFrame);
|
CollideFrame(rootFrame);
|
||||||
|
|
||||||
/* TODO: Does not need to be done this often. */
|
/* TODO: Does not need to be done this often. */
|
||||||
|
Loading…
Reference in New Issue
Block a user