1 #ifndef GONG_GEOMETRY_PRIMITIVE_HPP_
2 #define GONG_GEOMETRY_PRIMITIVE_HPP_
4 #include "../graphics/glm.hpp"
8 #include <glm/gtx/norm.hpp>
18 void Adjust() noexcept {
19 if (max.x < min.x) std::swap(max.x, min.x);
20 if (max.y < min.y) std::swap(max.y, min.y);
21 if (max.z < min.z) std::swap(max.z, min.z);
24 glm::vec3 Center() const noexcept {
25 return min + (max - min) * 0.5f;
28 /// return distance between origin and farthest vertex
29 float OriginRadius() const noexcept {
30 glm::vec3 high(glm::max(glm::abs(min), glm::abs(max)));
31 return glm::length(high);
34 void Position(const glm::vec3 ¢er) noexcept {
35 const glm::vec3 halfsize((max - min) * 0.5f);
36 min = center - halfsize;
37 max = center + halfsize;
39 void Move(const glm::vec3 &delta) noexcept {
45 std::ostream &operator <<(std::ostream &, const AABB &);
47 bool Intersection(const AABB &, const AABB &) noexcept;
49 // TODO: this should really use setters/getters for dir and inv_dir so
50 // manipulating code doesn't "forget" to call Update()
57 void Update() noexcept {
61 /// get shortest distance of this ray's line to given point
62 float Distance(const glm::vec3 &point) const noexcept {
63 // d = |(x2-x1)×(x1-x0)|/|x2-x1|
64 // where x0 is point, and x1 and x2 are points on the line
65 // for derivation, see http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
67 // x2-x1 = dir, which means |x2-x1| is 1.0
68 return glm::length(glm::cross(dir, orig - point));
70 float DistanceSquared(const glm::vec3 &point) const noexcept {
71 return glm::length2(glm::cross(dir, orig - point));
75 std::ostream &operator <<(std::ostream &, const Ray &);
77 /// axis aligned boolean ray/box intersection test
78 /// if true, dist constains distance from ray's origin to intersection point
82 float &dist) noexcept;
84 /// detailed oriented ray/box intersection test
89 float *dist = nullptr,
90 glm::vec3 *normal = nullptr) noexcept;
92 /// matrices may translate and rotate, but must not scale/shear/etc
93 /// (basically the first three columns must have unit length)
100 glm::vec3 &normal) noexcept;
102 /// Plane defined by a surface norml and distance to the origin such that
103 /// the point (normal * dist) lies on the plane.
108 float &A() noexcept { return normal.x; }
109 float &B() noexcept { return normal.y; }
110 float &C() noexcept { return normal.z; }
111 float &D() noexcept { return dist; }
112 float A() const noexcept { return normal.x; }
113 float B() const noexcept { return normal.y; }
114 float C() const noexcept { return normal.z; }
115 float D() const noexcept { return dist; }
117 Plane(const glm::vec3 &n, float d)
118 : normal(n), dist(d) { }
119 explicit Plane(const glm::vec4 &abcd)
120 : normal(abcd), dist(abcd.w) { }
122 void Normalize() noexcept {
123 const float l = glm::length(normal);
129 std::ostream &operator <<(std::ostream &, const Plane &);
131 /// Shortest distance from point to plane.
132 float Distance(const glm::vec3 &point, const Plane &plane);
133 /// Shortest distance from point to plane with sign indicating whether
134 /// it's in front of (positive, in direction of normal) or behind
135 /// (negative, counter direction of normal) the surface.
136 float SignedDistance(const glm::vec3 &point, const Plane &plane);
140 Plane &Left() noexcept { return plane[0]; }
141 Plane &Right() noexcept { return plane[1]; }
142 Plane &Bottom() noexcept { return plane[2]; }
143 Plane &Top() noexcept { return plane[3]; }
144 Plane &Near() noexcept { return plane[4]; }
145 Plane &Far() noexcept { return plane[5]; }
146 const Plane &Left() const noexcept { return plane[0]; }
147 const Plane &Right() const noexcept { return plane[1]; }
148 const Plane &Bottom() const noexcept { return plane[2]; }
149 const Plane &Top() const noexcept { return plane[3]; }
150 const Plane &Near() const noexcept { return plane[4]; }
151 const Plane &Far() const noexcept { return plane[5]; }
153 /// create frustum from transposed MVP
154 explicit Frustum(const glm::mat4 &mat)
156 Plane{ mat[3] + mat[0] },
157 Plane{ mat[3] - mat[0] },
158 Plane{ mat[3] + mat[1] },
159 Plane{ mat[3] - mat[1] },
160 Plane{ mat[3] + mat[2] },
161 Plane{ mat[3] - mat[2] },
164 void Normalize() noexcept {
165 for (Plane &p : plane) {
171 std::ostream &operator <<(std::ostream &, const Plane &);
172 std::ostream &operator <<(std::ostream &, const Frustum &);
174 bool CullTest(const AABB &box, const glm::mat4 &) noexcept;
175 bool CullTest(const AABB &box, const Frustum &) noexcept;
182 void Position(const glm::vec3 ¢er) noexcept {
185 void Move(const glm::vec3 &delta) noexcept {
191 std::ostream &operator <<(std::ostream &, const Sphere &);
193 /// Two spheres intersection test.
198 glm::vec3 &norm) noexcept;
200 /// Test for intersection of sphere with double sided infinite plane.
201 /// If true, dist will hold the smaller interpenetration depth and norm
202 /// the respective contact normal.
204 const Sphere &sphere,
207 glm::vec3 &norm) noexcept;
209 /// Test for intersection of sphere with half space defined by the
210 /// backface of given plane.
211 /// In all cases, dist will hold the distance between the near points
212 /// of plane and sphere. Contact normal will always be the plane's normal.
214 const Sphere &sphere,
216 float &dist) noexcept;