New and improved edge collision handling! Get it while it's hot!
This commit is contained in:
parent
648ce1d454
commit
2aa2097b6c
3 changed files with 49 additions and 28 deletions
|
@ -50,6 +50,20 @@ bool Collision::test(const Triangle &t, const MathUtil::Ray &ray, float *distanc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmml::vec3f Collision::projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2) {
|
||||||
|
vmml::vec3f pVec = p - v1;
|
||||||
|
vmml::vec3f edge = v2 - v1;
|
||||||
|
|
||||||
|
float lengthSq = edge.squared_length();
|
||||||
|
float edgeProj = vmml::dot(edge, pVec);
|
||||||
|
|
||||||
|
if(edgeProj < 0) return v1;
|
||||||
|
if(edgeProj > lengthSq) return v2;
|
||||||
|
|
||||||
|
return v1 + (edgeProj/lengthSq)*edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Collision::testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance) {
|
bool Collision::testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance) {
|
||||||
vmml::vec3f edge = v2 - v1;
|
vmml::vec3f edge = v2 - v1;
|
||||||
|
|
||||||
|
@ -116,16 +130,19 @@ bool Collision::testVertex(const vmml::vec3f &v, const vmml::vec3f &m, float r,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance) {
|
bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance, vmml::vec3f *normal) {
|
||||||
if(move.squared_length() == 0)
|
if(move.squared_length() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float d;
|
float d;
|
||||||
|
|
||||||
if(test(t, MathUtil::Ray(m - r*t.computeNormal(), move), &d) && d > -MathUtil::EPSILON) {
|
vmml::vec3f triangleNormal = t.computeNormal();
|
||||||
|
if(test(t, MathUtil::Ray(m - r*triangleNormal, move), &d) && d > -MathUtil::EPSILON) {
|
||||||
if(d < 1) {
|
if(d < 1) {
|
||||||
if(distance)
|
if(distance)
|
||||||
*distance = d;
|
*distance = d;
|
||||||
|
if(normal)
|
||||||
|
*normal = triangleNormal;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +159,12 @@ bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmm
|
||||||
if(!collision || d < minDistance) {
|
if(!collision || d < minDistance) {
|
||||||
collision = true;
|
collision = true;
|
||||||
minDistance = d;
|
minDistance = d;
|
||||||
|
|
||||||
|
if(normal) {
|
||||||
|
vmml::vec3f p = m + move*d;
|
||||||
|
|
||||||
|
*normal = (p - projectToEdge(p, t.getVertex(i), t.getVertex((i+1)%3)))/r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +183,12 @@ bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmm
|
||||||
collision = true;
|
collision = true;
|
||||||
minDistance = d;
|
minDistance = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(normal) {
|
||||||
|
vmml::vec3f p = m + move*d;
|
||||||
|
|
||||||
|
*normal = (p - t.getVertex(i))/r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,13 @@ namespace Zoom {
|
||||||
class Collision {
|
class Collision {
|
||||||
public:
|
public:
|
||||||
static bool test(const Triangle &t, const MathUtil::Ray &ray, float *distance = 0);
|
static bool test(const Triangle &t, const MathUtil::Ray &ray, float *distance = 0);
|
||||||
static bool test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance = 0);
|
static bool test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance = 0, vmml::vec3f *normal = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Collision();
|
Collision();
|
||||||
|
|
||||||
|
static vmml::vec3f projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2);
|
||||||
|
|
||||||
static bool testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance);
|
static bool testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance);
|
||||||
static bool testVertex(const vmml::vec3f &v, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance);
|
static bool testVertex(const vmml::vec3f &v, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance);
|
||||||
};
|
};
|
||||||
|
|
40
src/Game.cpp
40
src/Game.cpp
|
@ -136,43 +136,32 @@ void Game::run(int delta) {
|
||||||
while(collision) {
|
while(collision) {
|
||||||
collision = false;
|
collision = false;
|
||||||
|
|
||||||
MathUtil::Plane nearestPlane;
|
|
||||||
float nearestDistance;
|
float nearestDistance;
|
||||||
|
vmml::vec3f nearestNormal;
|
||||||
|
|
||||||
for(std::vector<TriangleRecord>::iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
for(std::vector<TriangleRecord>::iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS, playerMove)) {
|
float distance;
|
||||||
vmml::vec3f normal = t->getTriangle().computeNormal();
|
vmml::vec3f normal;
|
||||||
|
|
||||||
|
if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS, playerMove, &distance, &normal)) {
|
||||||
|
normal.y() = 0;
|
||||||
|
|
||||||
if(normal.dot(playerMove) >= 0)
|
if(normal.dot(playerMove) >= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MathUtil::Plane p(normal, vmml::dot(normal, t->getTriangle().getVertex(0)+PLAYER_RADIUS*normal));
|
if(!collision || distance < nearestDistance) {
|
||||||
if(p.isInFront(playerPos) || p.contains(playerPos)) {
|
collision = true;
|
||||||
vmml::vec3f intersection = p.intersection(MathUtil::Ray(playerPos, playerMove));
|
|
||||||
float distance = intersection.squared_distance(playerPos);
|
|
||||||
|
|
||||||
if(!collision || distance < nearestDistance) {
|
|
||||||
collision = true;
|
|
||||||
|
|
||||||
nearestPlane = p;
|
|
||||||
nearestDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO Edge collision
|
|
||||||
|
|
||||||
|
nearestDistance = distance;
|
||||||
|
nearestNormal = normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(collision) {
|
if(collision) {
|
||||||
vmml::vec3f move;
|
vmml::vec3f move = playerMove*nearestDistance;
|
||||||
|
|
||||||
if(playerMove.dot(nearestPlane.getNormal()) == 0)
|
if(move.dot(origMove) <= 0 && move.squared_length() > 0) {
|
||||||
move = playerMove;
|
|
||||||
else
|
|
||||||
move = nearestPlane.intersection(MathUtil::Ray(playerPos, playerMove)) - playerPos;
|
|
||||||
|
|
||||||
if(move.dot(origMove) <= 0 && move.squared_length() > MathUtil::EPSILON) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +171,8 @@ void Game::run(int delta) {
|
||||||
playerPos += move;
|
playerPos += move;
|
||||||
|
|
||||||
vmml::vec3f restMove = playerMove - move;
|
vmml::vec3f restMove = playerMove - move;
|
||||||
playerMove = restMove - nearestPlane.getNormal() * (nearestPlane.getNormal().dot(restMove));
|
|
||||||
|
playerMove = restMove - nearestNormal * (nearestNormal.dot(restMove));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue