[Fix] Made the linear component of collisions with static bodies work.

This commit is contained in:
Rtch90 2018-04-08 18:25:42 +01:00
parent 7c8204f02d
commit e7fb5d085e
9 changed files with 97 additions and 97 deletions

View File

@ -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

View File

@ -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;
};

View 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;
}
};

View File

@ -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);
}
}
} }
} }

View File

@ -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;

View File

@ -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;
/* In world coords. */ if(depth > contact.depth) {
c.pos = b->GetTransform() * (from + dir*isect.dist); /* In world coords. */
vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx); contact.pos = b->GetTransform() * (from + dir*isect.dist);
c.normal = vector3d(n.x, n.y, n.z); vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx);
c.normal = b->GetTransform().ApplyRotationOnly(c.normal); contact.normal = vector3d(n.x, n.y, n.z);
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); }
} }
} }
} }

View File

@ -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;

View File

@ -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);

View File

@ -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. */