1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
/*
* Collision.cpp
*
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}
}
|