forked from kevinmoran/GJK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Collider.h
125 lines (101 loc) · 3.56 KB
/
Collider.h
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#pragma once
#include "GameMaths.h"
//Kevin's simple collider objects for collision detection
//Different shapes which inherit from Collider and implement
//support() function for use in GJK
//Base struct for all collision shapes
struct Collider {
vec3 pos; //origin in world space
mat3 matRS; //rotation/scale component of model matrix
mat3 matRS_inverse;
virtual vec3 support(vec3 dir) = 0;
};
//BBox: AABB + Orientation matrix
struct BBox : Collider {
vec3 min, max; //Assume these are axis aligned!
vec3 support(vec3 dir){
dir = matRS_inverse*dir; //find support in model space
vec3 result;
result.x = (dir.x>0) ? max.x : min.x;
result.y = (dir.y>0) ? max.y : min.y;
result.z = (dir.z>0) ? max.z : min.z;
return matRS*result + pos; //convert support to world space
}
};
//Sphere: NB Does not use RS matrix, scale the radius directly!
struct Sphere : Collider {
float r;
vec3 support(vec3 dir){
return normalise(dir)*r + pos;
}
};
//Cylinder: Height-aligned with y-axis (rotate using matRS)
struct Cylinder : Collider {
float r, y_base, y_cap;
vec3 support(vec3 dir){
dir = matRS_inverse*dir; //find support in model space
vec3 dir_xz = vec3(dir.x, 0, dir.z);
vec3 result = normalise(dir_xz)*r;
result.y = (dir.y>0) ? y_cap : y_base;
return matRS*result + pos; //convert support to world space
}
};
//Capsule: Height-aligned with y-axis
struct Capsule : Collider {
float r, y_base, y_cap;
vec3 support(vec3 dir){
dir = matRS_inverse*dir; //find support in model space
vec3 result = normalise(dir)*r;
result.y += (dir.y>0) ? y_cap : y_base;
return matRS*result + pos; //convert support to world space
}
};
//Triangle: Kind of a hack
// "All physics code is an awful hack" - Will, #HandmadeDev
//Need to fake a prism for GJK to converge
//NB: Currently using world-space points, ignore matRS and pos from base class
//Don't use EPA with this! Might resolve collision along any one of prism's faces
//Only resolve around triangle normal
struct TriangleCollider : Collider {
vec3 points[3];
vec3 normal;
vec3 support(vec3 dir){
//Find which triangle vertex is furthest along dir
float dot0 = dot(points[0], dir);
float dot1 = dot(points[1], dir);
float dot2 = dot(points[2], dir);
vec3 furthest_point = points[0];
if(dot1>dot0){
furthest_point = points[1];
if(dot2>dot1)
furthest_point = points[2];
}
else if(dot2>dot0) {
furthest_point = points[2];
}
//fake some depth behind triangle so we have volume
if(dot(dir, normal)<0) furthest_point-= normal;
return furthest_point;
}
};
//Polytope: Just a set of points
struct Polytope : Collider {
float *points; //(x0 y0 z0 x1 y1 z1 etc)
int num_points;
//Dumb O(n) support function, just brute force check all points
vec3 support(vec3 dir){
dir = matRS_inverse*dir;
vec3 furthest_point = vec3(points[0], points[1], points[2]);
float max_dot = dot(furthest_point, dir);
for(int i=3; i<num_points*3; i+=3){
vec3 v = vec3(points[i], points[i+1], points[i+2]);
float d = dot(v, dir);
if(d>max_dot){
max_dot = d;
furthest_point = v;
}
}
vec3 result = matRS*furthest_point + pos; //convert support to world space
return result;
}
};