From 5dc3e727e0fc470d344da8b18c3588104585496f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 26 Dec 2009 03:19:49 +0100 Subject: Added collision detection --- src/Collision.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/Collision.cpp (limited to 'src/Collision.cpp') diff --git a/src/Collision.cpp b/src/Collision.cpp new file mode 100644 index 0000000..7c72922 --- /dev/null +++ b/src/Collision.cpp @@ -0,0 +1,97 @@ +/* + * Collision.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Collision.h" + +namespace Zoom { + +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; +} + +vmml::vec3f Collision::projectToNearestEdge(const vmml::vec3f& p, const Triangle &t) { + vmml::vec3f p1 = projectToEdge(p, t.getVertex(0), t.getVertex(1)); + vmml::vec3f p2 = projectToEdge(p, t.getVertex(1), t.getVertex(2)); + vmml::vec3f p3 = projectToEdge(p, t.getVertex(2), t.getVertex(0)); + + if(p.squared_distance(p1) < p.squared_distance(p2) && p.squared_distance(p1) < p.squared_distance(p3)) + return p1; + else if(p.squared_distance(p2) < p.squared_distance(p3)) + return p2; + else + return p3; +} + + +bool Collision::test(const Triangle &t, const MathUtil::Ray &ray, float *distance) { + vmml::vec3f edge1 = t.getVertex(1) - t.getVertex(0); + vmml::vec3f edge2 = t.getVertex(2) - t.getVertex(0); + + vmml::vec3f pvec = ray.getDirection().cross(edge2); + + float det = vmml::dot(edge1, pvec); + if(det < MathUtil::EPSILON) + return false; + + vmml::vec3f tvec = ray.getVertex() - t.getVertex(0); + float u = vmml::dot(pvec, tvec); + + if(u < 0 || u > det) + return false; + + vmml::vec3f qvec = tvec.cross(edge1); + float v = vmml::dot(ray.getDirection(), qvec); + if(v < 0 || u+v > det) + return false; + + if(distance) + *distance = vmml::dot(edge2, qvec) / det; + + return true; +} + +bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move) { + float distance; + + if(test(t, MathUtil::Ray(m - r*t.computeNormal(), move), &distance) && distance > -MathUtil::EPSILON) { + if(distance < 1) + return true; + else + return false; + } + + vmml::vec3f collisionPoint = projectToNearestEdge(m, t); + vmml::vec3f movedPoint = projectToEdge(m, collisionPoint, collisionPoint - move); + + if(m.squared_distance(movedPoint) < r*r) + return true; + else + return false; +} + +} -- cgit v1.2.3