[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 40f6d6dc37
commit 799e1de136
9 changed files with 97 additions and 97 deletions

View File

@ -1,5 +1,5 @@
noinst_LIBRARIES = libcollider.a
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 "geom.h"
class Geom;
struct CollisionContact {
vector3d pos;
vector3d normal;
double depth;
int triIdx;
void* userData1, *userData2;
int geomFlag;
};
#include "collision_contact.h"

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);
}
void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*)) {
void CollisionSpace::CollideGeoms(Geom* a) {
/* Our big Aabb. */
vector3d pos = a->GetPosition();
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. */
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) {
@ -79,17 +79,24 @@ void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*))
bigAabb2.min += pos2;
bigAabb2.max += pos2;
if(bigAabb.Intersects(bigAabb2)) {
a->Collide(*i, callback);
if(!(*i)->HasMoved()) (*i)->Collide(a, callback);
a->Collide(*i);
if(!(*i)->HasMoved()) (*i)->Collide(a);
}
}
}
}
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) {
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:
void CollideGeoms(Geom* a, void (*callback)(CollisionContact*));
void CollideGeoms(Geom* a);
void CollideRaySphere(const vector3d& start, const vector3d& dir, isect_t* isect);
std::list<Geom*> m_geoms;

View File

@ -42,7 +42,7 @@ vector3d Geom::GetPosition(void) const {
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
* 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;
const double len = v.Length();
if(len < sphere.radius) {
CollisionContact c;
c.pos = GetPosition();
c.normal = (1.0/len)*v;
c.depth = sphere.radius - len;
c.triIdx = 0;
c.userData1 = this->m_data;
c.userData2 = sphere.userData;
c.geomFlag = 0;
(*callback)(&c);
contact.pos = GetPosition();
contact.normal = (1.0/len)*v;
contact.depth = sphere.radius - len;
contact.triIdx = 0;
contact.userData1 = this->m_data;
contact.userData2 = sphere.userData;
contact.geomFlag = 0;
return;
}
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(i1 > 0) {
if(i1 < len) {
CollisionContact c;
c.pos = from + dir*i1;
c.normal = vector3d::Normalize(v);
c.depth = len - i1;
c.triIdx = 0;
c.userData1 = this->m_data;
c.userData2 = sphere.userData;
c.geomFlag = 0;
(*callback)(&c);
contact.pos = from + dir*i1;
contact.normal = vector3d::Normalize(v);
contact.depth = len - i1;
contact.triIdx = 0;
contact.userData1 = this->m_data;
contact.userData2 = sphere.userData;
contact.geomFlag = 0;
}
}
}
@ -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;
for(int i = 0; i < m_geomtree->m_numVertices; i++) {
vector3d v(&m_geomtree->m_vertices[3*i]);
@ -116,19 +112,20 @@ void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) {
isect.triIdx = -1;
b->m_geomtree->TraceRay(_from, _dir, &isect);
if(isect.triIdx != -1) {
CollisionContact c;
/* In world coords. */
c.pos = b->GetTransform() * (from + dir*isect.dist);
vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx);
c.normal = vector3d(n.x, n.y, n.z);
c.normal = b->GetTransform().ApplyRotationOnly(c.normal);
const double depth = len - isect.dist;
if(depth > contact.depth) {
/* In world coords. */
contact.pos = b->GetTransform() * (from + dir*isect.dist);
vector3f n = b->m_geomtree->GetTriNormal(isect.triIdx);
contact.normal = vector3d(n.x, n.y, n.z);
contact.normal = b->GetTransform().ApplyRotationOnly(contact.normal);
c.depth = len - isect.dist;
c.triIdx = isect.triIdx;
c.userData1 = m_data;
c.userData2 = b->m_data;
c.geomFlag = b->m_geomtree->GetTriFlag(isect.triIdx);
(*callback)(&c);
contact.depth = len - isect.dist;
contact.triIdx = isect.triIdx;
contact.userData1 = m_data;
contact.userData2 = b->m_data;
contact.geomFlag = b->m_geomtree->GetTriFlag(isect.triIdx);
}
}
}
}

View File

@ -1,10 +1,10 @@
#pragma once
#include "../matrix4x4.h"
#include "../vector3.h"
#include "collision_contact.h"
class GeomTree;
class isect_t;
class CollisionContact;
class Sphere;
class Geom {
@ -21,10 +21,12 @@ public:
bool IsEnabled(void) { return m_active; }
bool HasMoved(void) { return m_moved; }
GeomTree* GetGeomTree(void) { return m_geomtree; }
void Collide(Geom* b, void(*callback)(CollisionContact*));
void CollideSphere(Sphere& sphere, void (*callback)(CollisionContact*));
void Collide(Geom* b);
void CollideSphere(Sphere& sphere);
void SetUserData(void* d) { m_data = d; }
void* GetUserData(void) { return m_data; }
CollisionContact contact;
private:
/* double-buffer position so we can keep previous position. */
matrix4x4d m_orient[2], m_invOrient;

View File

@ -93,6 +93,10 @@ vector3d DynamicBody::GetPosition(void) const {
}
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) {
m_vel += timeStep * m_force * (1.0/m_mass);
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,
int numContacts, dContact contacts[]) {
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;
}
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]);
}
#endif
static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
Body* pb1, *pb2;
@ -332,50 +326,42 @@ static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) {
return true;
}
#define MAX_CONTACTS 1
/* XXX SO REESTED!! 1 CONTACT PER PHYSICS TICK?! WTH?! */
static int contact_num;
static void hitCallback(CollisionContact* c) {
if(contact_num++ >= MAX_CONTACTS) return;
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* po2 = static_cast<Object*>(c->userData2);
if(!_OnCollision2(po1, po2, c)) return;
dBodyID b1 = 0;
dBodyID b2 = 0;
/* Get the dynamics body for each geom. */
if(po1->IsType(Object::DYNAMICBODY)) b1 = static_cast<DynamicBody*>(po1)->m_body;
if(po2->IsType(Object::DYNAMICBODY)) b2 = static_cast<DynamicBody*>(po2)->m_body;
const bool po1_isDynBody = po1->IsType(Object::DYNAMICBODY);
const bool po2_isDynBody = po2->IsType(Object::DYNAMICBODY);
/* Collision response. */
assert(po1_isDynBody || po2_isDynBody);
dJointID j = dJointCreateContact(Space::world, _contactgroup, &contact);
dJointAttach(j, b1, b2);
#endif
if(po1_isDynBody && po2_isDynBody) {
} 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
@ -464,7 +450,6 @@ void Space::ApplyGravity(void) {
void Space::TimeStep(float step) {
ApplyGravity();
contact_num = 0;
CollideFrame(rootFrame);
/* TODO: Does not need to be done this often. */