From: Daniel Karbach Date: Tue, 3 Nov 2015 12:06:18 +0000 (+0100) Subject: split geometry lib X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=4fbf5a3c1b0e530706023f5fc4be2f68d30ea645;p=blank.git split geometry lib --- diff --git a/src/ai/AIController.hpp b/src/ai/AIController.hpp index 5cbfd0e..15645a2 100644 --- a/src/ai/AIController.hpp +++ b/src/ai/AIController.hpp @@ -2,7 +2,7 @@ #define BLANK_AI_AICONTROLLER_HPP_ #include "../app/IntervalTimer.hpp" -#include "../model/geometry.hpp" +#include "../geometry/primitive.hpp" #include "../world/EntityController.hpp" #include diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index c47b4d3..8386c59 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -4,7 +4,8 @@ #include "IdleState.hpp" #include "RoamState.hpp" -#include "../model/geometry.hpp" +#include "../geometry/distance.hpp" +#include "../geometry/rotation.hpp" #include "../rand/GaloisLFSR.hpp" #include "../world/Entity.hpp" #include "../world/World.hpp" diff --git a/src/client/net.cpp b/src/client/net.cpp index aba3e76..1c13f9e 100644 --- a/src/client/net.cpp +++ b/src/client/net.cpp @@ -4,6 +4,7 @@ #include "NetworkedInput.hpp" #include "../app/init.hpp" +#include "../geometry/distance.hpp" #include "../io/WorldSave.hpp" #include "../net/Packet.hpp" #include "../world/Chunk.hpp" diff --git a/src/geometry/const.hpp b/src/geometry/const.hpp new file mode 100644 index 0000000..00d33e0 --- /dev/null +++ b/src/geometry/const.hpp @@ -0,0 +1,18 @@ +#ifndef BLANK_GEOMETRY_CONST_HPP_ +#define BLANK_GEOMETRY_CONST_HPP_ + + +namespace blank { + +constexpr float PI = 3.141592653589793238462643383279502884; +constexpr float PI_0p25 = PI * 0.25f; +constexpr float PI_0p5 = PI * 0.5f; +constexpr float PI_1p5 = PI * 1.5f; +constexpr float PI_2p0 = PI * 2.0f; + +constexpr float PI_inv = 1.0f / PI; +constexpr float PI_0p5_inv = 1.0f / PI_0p5; + +} + +#endif diff --git a/src/geometry/distance.hpp b/src/geometry/distance.hpp new file mode 100644 index 0000000..d4bec9b --- /dev/null +++ b/src/geometry/distance.hpp @@ -0,0 +1,38 @@ +#ifndef BLANK_GEOMETRY_DISTANCE_HPP_ +#define BLANK_GEOMETRY_DISTANCE_HPP_ + +#include +#include +#include + + +namespace blank { + +inline float length_squared(const glm::vec3 &v) noexcept { + return dot(v, v); +} + +inline float distance_squared(const glm::vec3 &a, const glm::vec3 &b) noexcept { + return length_squared(a - b); +} + +template +inline bool iszero(const T &v) noexcept { + return length_squared(v) < std::numeric_limits::epsilon(); +} + +template +T manhattan_distance(const glm::tvec3 &a, const glm::tvec3 &b) noexcept { + glm::tvec3 diff(abs(a - b)); + return diff.x + diff.y + diff.z; +} + +template +T manhattan_radius(const glm::tvec3 &v) noexcept { + glm::tvec3 a(abs(v)); + return std::max(a.x, std::max(a.y, a.z)); +} + +} + +#endif diff --git a/src/geometry/geometry.cpp b/src/geometry/geometry.cpp new file mode 100644 index 0000000..ff28d2e --- /dev/null +++ b/src/geometry/geometry.cpp @@ -0,0 +1,214 @@ +#include "const.hpp" +#include "distance.hpp" +#include "primitive.hpp" +#include "rotation.hpp" + +#include +#include +#include +#include + + +namespace blank { + +glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept { + glm::vec3 v(cross(a, b)); + if (iszero(v)) { + // a and b are parallel + if (iszero(a - b)) { + // a and b are identical + return glm::mat3(1.0f); + } else { + // a and b are opposite + // create arbitrary unit vector perpendicular to a and + // rotate 180° around it + glm::vec3 arb(a); + if (std::abs(a.x - 1.0f) > std::numeric_limits::epsilon()) { + arb.x += 1.0f; + } else { + arb.y += 1.0f; + } + glm::vec3 axis(normalize(cross(a, arb))); + return glm::mat3(glm::rotate(PI, axis)); + } + } + float mv = length_squared(v); + float c = dot(a, b); + float f = (1 - c) / mv; + glm::mat3 vx(matrixCross3(v)); + return glm::mat3(1.0f) + vx + (pow2(vx) * f); +} + +bool Intersection( + const Ray &ray, + const AABB &aabb, + const glm::mat4 &M, + float *dist, + glm::vec3 *normal +) noexcept { + float t_min = 0.0f; + float t_max = std::numeric_limits::infinity(); + const glm::vec3 aabb_pos(M[3].x, M[3].y, M[3].z); + const glm::vec3 delta = aabb_pos - ray.orig; + + glm::vec3 t1(t_min, t_min, t_min), t2(t_max, t_max, t_max); + + for (int i = 0; i < 3; ++i) { + const glm::vec3 axis(M[i].x, M[i].y, M[i].z); + const float e = glm::dot(axis, delta); + const float f = glm::dot(axis, ray.dir); + + if (std::abs(f) > std::numeric_limits::epsilon()) { + t1[i] = (e + aabb.min[i]) / f; + t2[i] = (e + aabb.max[i]) / f; + + t_min = std::max(t_min, std::min(t1[i], t2[i])); + t_max = std::min(t_max, std::max(t1[i], t2[i])); + + if (t_max < t_min) { + return false; + } + } else { + if (aabb.min[i] - e > 0.0f || aabb.max[i] - e < 0.0f) { + return false; + } + } + } + + glm::vec3 min_all(min(t1, t2)); + + if (dist) { + *dist = t_min; + } + if (normal) { + if (min_all.x > min_all.y) { + if (min_all.x > min_all.z) { + normal->x = t2.x < t1.x ? 1 : -1; + } else { + normal->z = t2.z < t1.z ? 1 : -1; + } + } else if (min_all.y > min_all.z) { + normal->y = t2.y < t1.y ? 1 : -1; + } else { + normal->z = t2.z < t1.z ? 1 : -1; + } + } + return true; +} + + +bool Intersection( + const AABB &a_box, + const glm::mat4 &a_m, + const AABB &b_box, + const glm::mat4 &b_m, + float &depth, + glm::vec3 &normal +) noexcept { + glm::vec3 a_corners[8] = { + glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.min.y, a_box.min.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.min.y, a_box.max.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.max.y, a_box.min.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.max.y, a_box.max.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.min.y, a_box.min.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.min.y, a_box.max.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.max.y, a_box.min.z, 1)), + glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.max.y, a_box.max.z, 1)), + }; + + glm::vec3 b_corners[8] = { + glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.min.y, b_box.min.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.min.y, b_box.max.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.max.y, b_box.min.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.max.y, b_box.max.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.min.y, b_box.min.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.min.y, b_box.max.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.max.y, b_box.min.z, 1)), + glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.max.y, b_box.max.z, 1)), + }; + + glm::vec3 axes[6] = { + glm::vec3(a_m * glm::vec4(1, 0, 0, 0)), + glm::vec3(a_m * glm::vec4(0, 1, 0, 0)), + glm::vec3(a_m * glm::vec4(0, 0, 1, 0)), + glm::vec3(b_m * glm::vec4(1, 0, 0, 0)), + glm::vec3(b_m * glm::vec4(0, 1, 0, 0)), + glm::vec3(b_m * glm::vec4(0, 0, 1, 0)), + }; + + depth = std::numeric_limits::infinity(); + int min_axis = 0; + + int cur_axis = 0; + for (const glm::vec3 &axis : axes) { + float a_min = std::numeric_limits::infinity(); + float a_max = -std::numeric_limits::infinity(); + for (const glm::vec3 &corner : a_corners) { + float val = glm::dot(corner, axis); + a_min = std::min(a_min, val); + a_max = std::max(a_max, val); + } + + float b_min = std::numeric_limits::infinity(); + float b_max = -std::numeric_limits::infinity(); + for (const glm::vec3 &corner : b_corners) { + float val = glm::dot(corner, axis); + b_min = std::min(b_min, val); + b_max = std::max(b_max, val); + } + + if (a_max < b_min || b_max < a_min) return false; + + float overlap = std::min(a_max, b_max) - std::max(a_min, b_min); + if (overlap < depth) { + depth = overlap; + min_axis = cur_axis; + } + + ++cur_axis; + } + + normal = axes[min_axis]; + return true; +} + + +bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept { + // transform corners into clip space + glm::vec4 corners[8] = { + { box.min.x, box.min.y, box.min.z, 1.0f }, + { box.min.x, box.min.y, box.max.z, 1.0f }, + { box.min.x, box.max.y, box.min.z, 1.0f }, + { box.min.x, box.max.y, box.max.z, 1.0f }, + { box.max.x, box.min.y, box.min.z, 1.0f }, + { box.max.x, box.min.y, box.max.z, 1.0f }, + { box.max.x, box.max.y, box.min.z, 1.0f }, + { box.max.x, box.max.y, box.max.z, 1.0f }, + }; + for (glm::vec4 &corner : corners) { + corner = MVP * corner; + corner /= corner.w; + } + + int hits[6] = { 0, 0, 0, 0, 0, 0 }; + + // check how many corners lie outside + for (const glm::vec4 &corner : corners) { + if (corner.x > 1.0f) ++hits[0]; + if (corner.x < -1.0f) ++hits[1]; + if (corner.y > 1.0f) ++hits[2]; + if (corner.y < -1.0f) ++hits[3]; + if (corner.z > 1.0f) ++hits[4]; + if (corner.z < -1.0f) ++hits[5]; + } + + // if all corners are outside any given clip plane, the test is true + for (int hit : hits) { + if (hit == 8) return true; + } + + // otherwise the box might still get culled completely, but can't say for sure ;) + return false; +} + +} diff --git a/src/geometry/primitive.hpp b/src/geometry/primitive.hpp new file mode 100644 index 0000000..351a3a4 --- /dev/null +++ b/src/geometry/primitive.hpp @@ -0,0 +1,49 @@ +#ifndef BLANK_GEOMETRY_PRIMITIVE_HPP_ +#define BLANK_GEOMETRY_PRIMITIVE_HPP_ + +#include +#include + + +namespace blank { + +struct AABB { + glm::vec3 min; + glm::vec3 max; + + void Adjust() noexcept { + if (max.x < min.x) std::swap(max.x, min.x); + if (max.y < min.y) std::swap(max.y, min.y); + if (max.z < min.z) std::swap(max.z, min.z); + } + + glm::vec3 Center() const noexcept { + return min + (max - min) * 0.5f; + } +}; + +struct Ray { + glm::vec3 orig; + glm::vec3 dir; +}; + +bool Intersection( + const Ray &, + const AABB &, + const glm::mat4 &M, + float *dist = nullptr, + glm::vec3 *normal = nullptr) noexcept; + +bool Intersection( + const AABB &a_box, + const glm::mat4 &a_m, + const AABB &b_box, + const glm::mat4 &b_m, + float &depth, + glm::vec3 &normal) noexcept; + +bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept; + +} + +#endif diff --git a/src/geometry/rotation.hpp b/src/geometry/rotation.hpp new file mode 100644 index 0000000..ac208dc --- /dev/null +++ b/src/geometry/rotation.hpp @@ -0,0 +1,13 @@ +#ifndef BLANK_GEOMETRY_ROTATION_HPP_ +#define BLANK_GEOMETRY_ROTATION_HPP_ + +#include + + +namespace blank { + +glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept; + +} + +#endif diff --git a/src/graphics/mesh.cpp b/src/graphics/mesh.cpp index 4a63d99..5cd3883 100644 --- a/src/graphics/mesh.cpp +++ b/src/graphics/mesh.cpp @@ -4,7 +4,7 @@ #include "SkyBoxMesh.hpp" #include "SpriteMesh.hpp" -#include "../model/geometry.hpp" +#include "../geometry/primitive.hpp" #include #include diff --git a/src/graphics/viewport.cpp b/src/graphics/viewport.cpp index 9abe48f..c46ef28 100644 --- a/src/graphics/viewport.cpp +++ b/src/graphics/viewport.cpp @@ -4,7 +4,7 @@ #include "Viewport.hpp" #include "../app/init.hpp" -#include "../model/geometry.hpp" +#include "../geometry/const.hpp" #include #include diff --git a/src/model/Part.hpp b/src/model/Part.hpp index 8c1db60..9774346 100644 --- a/src/model/Part.hpp +++ b/src/model/Part.hpp @@ -1,8 +1,6 @@ #ifndef BLAMK_MODEL_PART_HPP_ #define BLAMK_MODEL_PART_HPP_ -#include "geometry.hpp" - #include #include #include diff --git a/src/model/Shape.hpp b/src/model/Shape.hpp index 9170475..fe58d01 100644 --- a/src/model/Shape.hpp +++ b/src/model/Shape.hpp @@ -2,7 +2,7 @@ #define BLANK_MODEL_SHAPE_HPP_ #include "CollisionBounds.hpp" -#include "geometry.hpp" +#include "../geometry/primitive.hpp" #include "../graphics/BlockMesh.hpp" #include "../graphics/EntityMesh.hpp" #include "../world/Block.hpp" diff --git a/src/model/bounds.hpp b/src/model/bounds.hpp index 3bbb6d7..df5f77f 100644 --- a/src/model/bounds.hpp +++ b/src/model/bounds.hpp @@ -2,7 +2,7 @@ #define BLANK_MODEL_BOUNDS_HPP_ #include "CollisionBounds.hpp" -#include "geometry.hpp" +#include "../geometry/primitive.hpp" #include #include diff --git a/src/model/geometry.cpp b/src/model/geometry.cpp deleted file mode 100644 index a4ac500..0000000 --- a/src/model/geometry.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "geometry.hpp" - -#include -#include -#include -#include - - -namespace blank { - -glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept { - glm::vec3 v(cross(a, b)); - if (iszero(v)) { - // a and b are parallel - if (iszero(a - b)) { - // a and b are identical - return glm::mat3(1.0f); - } else { - // a and b are opposite - // create arbitrary unit vector perpendicular to a and - // rotate 180° around it - glm::vec3 arb(a); - if (std::abs(a.x - 1.0f) > std::numeric_limits::epsilon()) { - arb.x += 1.0f; - } else { - arb.y += 1.0f; - } - glm::vec3 axis(normalize(cross(a, arb))); - return glm::mat3(glm::rotate(PI, axis)); - } - } - float mv = length_squared(v); - float c = dot(a, b); - float f = (1 - c) / mv; - glm::mat3 vx(matrixCross3(v)); - return glm::mat3(1.0f) + vx + (pow2(vx) * f); -} - -bool Intersection( - const Ray &ray, - const AABB &aabb, - const glm::mat4 &M, - float *dist, - glm::vec3 *normal -) noexcept { - float t_min = 0.0f; - float t_max = std::numeric_limits::infinity(); - const glm::vec3 aabb_pos(M[3].x, M[3].y, M[3].z); - const glm::vec3 delta = aabb_pos - ray.orig; - - glm::vec3 t1(t_min, t_min, t_min), t2(t_max, t_max, t_max); - - for (int i = 0; i < 3; ++i) { - const glm::vec3 axis(M[i].x, M[i].y, M[i].z); - const float e = glm::dot(axis, delta); - const float f = glm::dot(axis, ray.dir); - - if (std::abs(f) > std::numeric_limits::epsilon()) { - t1[i] = (e + aabb.min[i]) / f; - t2[i] = (e + aabb.max[i]) / f; - - t_min = std::max(t_min, std::min(t1[i], t2[i])); - t_max = std::min(t_max, std::max(t1[i], t2[i])); - - if (t_max < t_min) { - return false; - } - } else { - if (aabb.min[i] - e > 0.0f || aabb.max[i] - e < 0.0f) { - return false; - } - } - } - - glm::vec3 min_all(min(t1, t2)); - - if (dist) { - *dist = t_min; - } - if (normal) { - if (min_all.x > min_all.y) { - if (min_all.x > min_all.z) { - normal->x = t2.x < t1.x ? 1 : -1; - } else { - normal->z = t2.z < t1.z ? 1 : -1; - } - } else if (min_all.y > min_all.z) { - normal->y = t2.y < t1.y ? 1 : -1; - } else { - normal->z = t2.z < t1.z ? 1 : -1; - } - } - return true; -} - - -bool Intersection( - const AABB &a_box, - const glm::mat4 &a_m, - const AABB &b_box, - const glm::mat4 &b_m, - float &depth, - glm::vec3 &normal -) noexcept { - glm::vec3 a_corners[8] = { - glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.min.y, a_box.min.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.min.y, a_box.max.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.max.y, a_box.min.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.min.x, a_box.max.y, a_box.max.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.min.y, a_box.min.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.min.y, a_box.max.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.max.y, a_box.min.z, 1)), - glm::vec3(a_m * glm::vec4(a_box.max.x, a_box.max.y, a_box.max.z, 1)), - }; - - glm::vec3 b_corners[8] = { - glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.min.y, b_box.min.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.min.y, b_box.max.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.max.y, b_box.min.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.min.x, b_box.max.y, b_box.max.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.min.y, b_box.min.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.min.y, b_box.max.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.max.y, b_box.min.z, 1)), - glm::vec3(b_m * glm::vec4(b_box.max.x, b_box.max.y, b_box.max.z, 1)), - }; - - glm::vec3 axes[6] = { - glm::vec3(a_m * glm::vec4(1, 0, 0, 0)), - glm::vec3(a_m * glm::vec4(0, 1, 0, 0)), - glm::vec3(a_m * glm::vec4(0, 0, 1, 0)), - glm::vec3(b_m * glm::vec4(1, 0, 0, 0)), - glm::vec3(b_m * glm::vec4(0, 1, 0, 0)), - glm::vec3(b_m * glm::vec4(0, 0, 1, 0)), - }; - - depth = std::numeric_limits::infinity(); - int min_axis = 0; - - int cur_axis = 0; - for (const glm::vec3 &axis : axes) { - float a_min = std::numeric_limits::infinity(); - float a_max = -std::numeric_limits::infinity(); - for (const glm::vec3 &corner : a_corners) { - float val = glm::dot(corner, axis); - a_min = std::min(a_min, val); - a_max = std::max(a_max, val); - } - - float b_min = std::numeric_limits::infinity(); - float b_max = -std::numeric_limits::infinity(); - for (const glm::vec3 &corner : b_corners) { - float val = glm::dot(corner, axis); - b_min = std::min(b_min, val); - b_max = std::max(b_max, val); - } - - if (a_max < b_min || b_max < a_min) return false; - - float overlap = std::min(a_max, b_max) - std::max(a_min, b_min); - if (overlap < depth) { - depth = overlap; - min_axis = cur_axis; - } - - ++cur_axis; - } - - normal = axes[min_axis]; - return true; -} - - -bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept { - // transform corners into clip space - glm::vec4 corners[8] = { - { box.min.x, box.min.y, box.min.z, 1.0f }, - { box.min.x, box.min.y, box.max.z, 1.0f }, - { box.min.x, box.max.y, box.min.z, 1.0f }, - { box.min.x, box.max.y, box.max.z, 1.0f }, - { box.max.x, box.min.y, box.min.z, 1.0f }, - { box.max.x, box.min.y, box.max.z, 1.0f }, - { box.max.x, box.max.y, box.min.z, 1.0f }, - { box.max.x, box.max.y, box.max.z, 1.0f }, - }; - for (glm::vec4 &corner : corners) { - corner = MVP * corner; - corner /= corner.w; - } - - int hits[6] = { 0, 0, 0, 0, 0, 0 }; - - // check how many corners lie outside - for (const glm::vec4 &corner : corners) { - if (corner.x > 1.0f) ++hits[0]; - if (corner.x < -1.0f) ++hits[1]; - if (corner.y > 1.0f) ++hits[2]; - if (corner.y < -1.0f) ++hits[3]; - if (corner.z > 1.0f) ++hits[4]; - if (corner.z < -1.0f) ++hits[5]; - } - - // if all corners are outside any given clip plane, the test is true - for (int hit : hits) { - if (hit == 8) return true; - } - - // otherwise the box might still get culled completely, but can't say for sure ;) - return false; -} - -} diff --git a/src/model/geometry.hpp b/src/model/geometry.hpp deleted file mode 100644 index 5065124..0000000 --- a/src/model/geometry.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef BLANK_MODEL_GEOMETRY_H_ -#define BLANK_MODEL_GEOMETRY_H_ - -#include -#include -#include - - -namespace blank { - -constexpr float PI = 3.141592653589793238462643383279502884; -constexpr float PI_0p25 = PI * 0.25f; -constexpr float PI_0p5 = PI * 0.5f; -constexpr float PI_1p5 = PI * 1.5f; -constexpr float PI_2p0 = PI * 2.0f; - -constexpr float PI_inv = 1.0f / PI; -constexpr float PI_0p5_inv = 1.0f / PI_0p5; - -constexpr float DEG_RAD_FACTOR = PI / 180.0f; -constexpr float RAD_DEG_FACTOR = 180.0f / PI; - -constexpr float deg2rad(float d) noexcept { - return d * DEG_RAD_FACTOR; -} - -constexpr float rad2deg(float r) noexcept { - return r * RAD_DEG_FACTOR; -} - - -inline float length_squared(const glm::vec3 &v) noexcept { - return dot(v, v); -} - -inline float distance_squared(const glm::vec3 &a, const glm::vec3 &b) noexcept { - return length_squared(a - b); -} - - -template -inline bool iszero(const T &v) noexcept { - return length_squared(v) < std::numeric_limits::epsilon(); -} - - -template -T manhattan_distance(const glm::tvec3 &a, const glm::tvec3 &b) noexcept { - glm::tvec3 diff(abs(a - b)); - return diff.x + diff.y + diff.z; -} - -template -T manhattan_radius(const glm::tvec3 &v) noexcept { - glm::tvec3 a(abs(v)); - return std::max(a.x, std::max(a.y, a.z)); -} - - -glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept; - - -struct AABB { - glm::vec3 min; - glm::vec3 max; - - void Adjust() noexcept { - if (max.x < min.x) std::swap(max.x, min.x); - if (max.y < min.y) std::swap(max.y, min.y); - if (max.z < min.z) std::swap(max.z, min.z); - } - - glm::vec3 Center() const noexcept { - return min + (max - min) * 0.5f; - } -}; - -struct Ray { - glm::vec3 orig; - glm::vec3 dir; -}; - -bool Intersection( - const Ray &, - const AABB &, - const glm::mat4 &M, - float *dist = nullptr, - glm::vec3 *normal = nullptr) noexcept; - -bool Intersection( - const AABB &a_box, - const glm::mat4 &a_m, - const AABB &b_box, - const glm::mat4 &b_m, - float &depth, - glm::vec3 &normal) noexcept; - -bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept; - -} - -#endif diff --git a/src/net/net.cpp b/src/net/net.cpp index 1f4e0a9..9130e8e 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -5,6 +5,7 @@ #include "Packet.hpp" #include "../app/init.hpp" +#include "../geometry/const.hpp" #include "../model/Model.hpp" #include "../world/Entity.hpp" #include "../world/EntityState.hpp" diff --git a/src/server/net.cpp b/src/server/net.cpp index aa1bdeb..8eba857 100644 --- a/src/server/net.cpp +++ b/src/server/net.cpp @@ -3,6 +3,7 @@ #include "Server.hpp" #include "../app/init.hpp" +#include "../geometry/distance.hpp" #include "../io/WorldSave.hpp" #include "../model/Model.hpp" #include "../world/ChunkIndex.hpp" diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index f5664dc..c45b34b 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -13,6 +13,7 @@ #include "../app/init.hpp" #include "../audio/Audio.hpp" #include "../audio/SoundBank.hpp" +#include "../geometry/distance.hpp" #include "../graphics/Font.hpp" #include "../graphics/Viewport.hpp" #include "../io/TokenStreamReader.hpp" @@ -374,8 +375,8 @@ void HUD::UpdatePosition() { void HUD::UpdateOrientation() { std::stringstream s; - s << std::setprecision(3) << "pitch: " << rad2deg(player.GetEntity().Pitch()) - << ", yaw: " << rad2deg(player.GetEntity().Yaw()); + s << std::setprecision(3) << "pitch: " << glm::degrees(player.GetEntity().Pitch()) + << ", yaw: " << glm::degrees(player.GetEntity().Yaw()); orientation_text.Set(env.assets.small_ui_font, s.str()); } diff --git a/src/world/Chunk.hpp b/src/world/Chunk.hpp index eaed28a..b6298b3 100644 --- a/src/world/Chunk.hpp +++ b/src/world/Chunk.hpp @@ -3,7 +3,7 @@ #include "Block.hpp" #include "BlockTypeRegistry.hpp" -#include "../model/geometry.hpp" +#include "../geometry/primitive.hpp" #include #include diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index 802ea90..4b24944 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -3,8 +3,8 @@ #include "Chunk.hpp" #include "EntityState.hpp" +#include "../geometry/primitive.hpp" #include "../model/Instance.hpp" -#include "../model/geometry.hpp" #include #include diff --git a/src/world/block.cpp b/src/world/block.cpp index 7050da4..d6e5507 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -2,8 +2,6 @@ #include "BlockType.hpp" #include "BlockTypeRegistry.hpp" -#include "../model/geometry.hpp" - #include #include #include diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index ef9f578..8340d56 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -8,6 +8,7 @@ #include "Generator.hpp" #include "WorldCollision.hpp" #include "../app/Assets.hpp" +#include "../geometry/distance.hpp" #include "../graphics/BlockLighting.hpp" #include "../graphics/BlockMesh.hpp" #include "../graphics/Viewport.hpp" diff --git a/src/world/world.cpp b/src/world/world.cpp index a17b0cb..9372031 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -9,6 +9,8 @@ #include "EntityCollision.hpp" #include "WorldCollision.hpp" #include "../app/Assets.hpp" +#include "../geometry/const.hpp" +#include "../geometry/distance.hpp" #include "../graphics/Format.hpp" #include "../graphics/Viewport.hpp" @@ -204,8 +206,8 @@ void Entity::OrientBody(float dt) noexcept { std::cout << "forward: " << forward << std::endl; std::cout << "facing: " << facing << std::endl; std::cout << "direction: " << direction << std::endl; - std::cout << "difference: " << rad2deg(relative_difference) << "°" << std::endl; - std::cout << "correction: " << rad2deg(correction) << "°" << std::endl; + std::cout << "difference: " << glm::degrees(relative_difference) << "°" << std::endl; + std::cout << "correction: " << glm::degrees(correction) << "°" << std::endl; std::cout << std::endl; } // now rotate body by correction and head by -correction diff --git a/tst/geometry/IntersectionTest.cpp b/tst/geometry/IntersectionTest.cpp new file mode 100644 index 0000000..41fb81a --- /dev/null +++ b/tst/geometry/IntersectionTest.cpp @@ -0,0 +1,120 @@ +#include "IntersectionTest.hpp" + +#include "geometry/const.hpp" +#include "geometry/primitive.hpp" + +#include +#include +#include + +CPPUNIT_TEST_SUITE_REGISTRATION(blank::test::IntersectionTest); + + +namespace blank { +namespace test { + +void IntersectionTest::setUp() { +} + +void IntersectionTest::tearDown() { +} + + +void IntersectionTest::testRayBoxIntersection() { + Ray ray{ { 0, 0, 0 }, { 1, 0, 0 } }; // at origin, pointing right + AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin + glm::mat4 M(1); // no transformation + + const float delta = std::numeric_limits::epsilon(); + + float distance = 0; + glm::vec3 normal(0); + + CPPUNIT_ASSERT_MESSAGE( + "ray at origin not intersecting box at origin", + Intersection(ray, box, M, &distance) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "intersection distance way off", + 0.0f, distance, delta + ); + // normal undefined, so can't test + + // move ray outside the box, but have it still point at it + // should be 4 units to the left now + ray.orig.x = -5; + CPPUNIT_ASSERT_MESSAGE( + "ray pointing at box doesn't intersect", + Intersection(ray, box, M, &distance, &normal) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "intersection distance way off", + 4.0f, distance, delta + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong surface normal at intersection point", + glm::vec3(-1, 0, 0), normal + ); + + // move ray to the other side, so it's pointing away now + ray.orig.x = 5; + CPPUNIT_ASSERT_MESSAGE( + "ray pointing away from box still intersects", + !Intersection(ray, box, M) + ); +} + +void IntersectionTest::testBoxBoxIntersection() { + const float delta = std::numeric_limits::epsilon(); + float depth = 0; + glm::vec3 normal(0); + + AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin + glm::mat4 Ma(1); // identity + glm::mat4 Mb(1); // identity + // they're identical, so should probably intersect ^^ + + CPPUNIT_ASSERT_MESSAGE( + "identical OBBs don't intersect", + Intersection(box, Ma, box, Mb, depth, normal) + ); + // depth is two, but normal can be any + // (will probably be the first axis of box a, but any is valid) + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "penetration depth of coincidental 2x2x2 boxes is not 2", + 2.0f, depth, delta + ); + + Ma = glm::translate(glm::vec3(-2, 0, 0)); // 2 to the left + Mb = glm::translate(glm::vec3(2, 0, 0)); // 2 to the right + CPPUNIT_ASSERT_MESSAGE( + "distant OBBs intersect (2 apart, no rotation)", + !Intersection(box, Ma, box, Mb, depth, normal) + ); + // depth and normal undefined for non-intersecting objects + + Ma = glm::rotate(PI_0p25, glm::vec3(0, 0, 1)); // rotated 45° around Z + Mb = glm::translate(glm::vec3(2.4, 0, 0)); // 2.4 to the right + // they should barely touch. intersect by about sqrt(2) - 1.4 if my head works + CPPUNIT_ASSERT_MESSAGE( + "OBBs don't intersect (one rotated by 45°)", + Intersection(box, Ma, box, Mb, depth, normal) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "bad penetration depth (with rotation)", + 0.01421356237309504880f, depth, delta + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "bad intersection normal (with rotation)", + glm::vec3(1, 0, 0), abs(normal) // normal can be in + or - x, therefore abs() + ); + + Mb = glm::translate(glm::vec3(3, 0, 0)); // 3 to the right + CPPUNIT_ASSERT_MESSAGE( + "OBBs intersect (one rotated by 45°)", + !Intersection(box, Ma, box, Mb, depth, normal) + ); +} + +} +} diff --git a/tst/geometry/IntersectionTest.hpp b/tst/geometry/IntersectionTest.hpp new file mode 100644 index 0000000..7922290 --- /dev/null +++ b/tst/geometry/IntersectionTest.hpp @@ -0,0 +1,32 @@ +#ifndef BLANK_TEST_GEOMETRY_INTERSECTIONTEST_H_ +#define BLANK_TEST_GEOMETRY_INTERSECTIONTEST_H_ + +#include + + +namespace blank { +namespace test { + +class IntersectionTest +: public CppUnit::TestFixture { + +CPPUNIT_TEST_SUITE(IntersectionTest); + +CPPUNIT_TEST(testRayBoxIntersection); +CPPUNIT_TEST(testBoxBoxIntersection); + +CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testRayBoxIntersection(); + void testBoxBoxIntersection(); + +}; + +} +} + +#endif diff --git a/tst/model/GeometryTest.cpp b/tst/model/GeometryTest.cpp deleted file mode 100644 index 82f88ee..0000000 --- a/tst/model/GeometryTest.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "GeometryTest.hpp" - -#include "model/geometry.hpp" - -#include -#include -#include - -CPPUNIT_TEST_SUITE_REGISTRATION(blank::test::GeometryTest); - - -namespace blank { -namespace test { - -void GeometryTest::setUp() { -} - -void GeometryTest::tearDown() { -} - - -void GeometryTest::testRayBoxIntersection() { - Ray ray{ { 0, 0, 0 }, { 1, 0, 0 } }; // at origin, pointing right - AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin - glm::mat4 M(1); // no transformation - - const float delta = std::numeric_limits::epsilon(); - - float distance = 0; - glm::vec3 normal(0); - - CPPUNIT_ASSERT_MESSAGE( - "ray at origin not intersecting box at origin", - Intersection(ray, box, M, &distance) - ); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( - "intersection distance way off", - 0.0f, distance, delta - ); - // normal undefined, so can't test - - // move ray outside the box, but have it still point at it - // should be 4 units to the left now - ray.orig.x = -5; - CPPUNIT_ASSERT_MESSAGE( - "ray pointing at box doesn't intersect", - Intersection(ray, box, M, &distance, &normal) - ); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( - "intersection distance way off", - 4.0f, distance, delta - ); - CPPUNIT_ASSERT_EQUAL_MESSAGE( - "wrong surface normal at intersection point", - glm::vec3(-1, 0, 0), normal - ); - - // move ray to the other side, so it's pointing away now - ray.orig.x = 5; - CPPUNIT_ASSERT_MESSAGE( - "ray pointing away from box still intersects", - !Intersection(ray, box, M) - ); -} - -void GeometryTest::testBoxBoxIntersection() { - const float delta = std::numeric_limits::epsilon(); - float depth = 0; - glm::vec3 normal(0); - - AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin - glm::mat4 Ma(1); // identity - glm::mat4 Mb(1); // identity - // they're identical, so should probably intersect ^^ - - CPPUNIT_ASSERT_MESSAGE( - "identical OBBs don't intersect", - Intersection(box, Ma, box, Mb, depth, normal) - ); - // depth is two, but normal can be any - // (will probably be the first axis of box a, but any is valid) - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( - "penetration depth of coincidental 2x2x2 boxes is not 2", - 2.0f, depth, delta - ); - - Ma = glm::translate(glm::vec3(-2, 0, 0)); // 2 to the left - Mb = glm::translate(glm::vec3(2, 0, 0)); // 2 to the right - CPPUNIT_ASSERT_MESSAGE( - "distant OBBs intersect (2 apart, no rotation)", - !Intersection(box, Ma, box, Mb, depth, normal) - ); - // depth and normal undefined for non-intersecting objects - - Ma = glm::rotate(PI_0p25, glm::vec3(0, 0, 1)); // rotated 45° around Z - Mb = glm::translate(glm::vec3(2.4, 0, 0)); // 2.4 to the right - // they should barely touch. intersect by about sqrt(2) - 1.4 if my head works - CPPUNIT_ASSERT_MESSAGE( - "OBBs don't intersect (one rotated by 45°)", - Intersection(box, Ma, box, Mb, depth, normal) - ); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( - "bad penetration depth (with rotation)", - 0.01421356237309504880f, depth, delta - ); - CPPUNIT_ASSERT_EQUAL_MESSAGE( - "bad intersection normal (with rotation)", - glm::vec3(1, 0, 0), abs(normal) // normal can be in + or - x, therefore abs() - ); - - Mb = glm::translate(glm::vec3(3, 0, 0)); // 3 to the right - CPPUNIT_ASSERT_MESSAGE( - "OBBs intersect (one rotated by 45°)", - !Intersection(box, Ma, box, Mb, depth, normal) - ); -} - -} -} diff --git a/tst/model/GeometryTest.hpp b/tst/model/GeometryTest.hpp deleted file mode 100644 index 7ba2d2d..0000000 --- a/tst/model/GeometryTest.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef BLANK_TEST_MODEL_GEOMETRYTEST_H_ -#define BLANK_TEST_MODEL_GEOMETRYTEST_H_ - -#include - - -namespace blank { -namespace test { - -class GeometryTest -: public CppUnit::TestFixture { - -CPPUNIT_TEST_SUITE(GeometryTest); - -CPPUNIT_TEST(testRayBoxIntersection); -CPPUNIT_TEST(testBoxBoxIntersection); - -CPPUNIT_TEST_SUITE_END(); - -public: - void setUp(); - void tearDown(); - - void testRayBoxIntersection(); - void testBoxBoxIntersection(); - -}; - -} -} - -#endif diff --git a/tst/net/PacketTest.cpp b/tst/net/PacketTest.cpp index 248bb61..695010d 100644 --- a/tst/net/PacketTest.cpp +++ b/tst/net/PacketTest.cpp @@ -1,5 +1,6 @@ #include "PacketTest.hpp" +#include "geometry/const.hpp" #include "model/Model.hpp" #include "world/Entity.hpp" diff --git a/tst/net/PacketTest.hpp b/tst/net/PacketTest.hpp index 54839ac..25256d9 100644 --- a/tst/net/PacketTest.hpp +++ b/tst/net/PacketTest.hpp @@ -1,7 +1,7 @@ #ifndef BLANK_TEST_NET_PACKETTEST_HPP_ #define BLANK_TEST_NET_PACKETTEST_HPP_ -#include "model/geometry.hpp" +#include "geometry/primitive.hpp" #include "net/Packet.hpp" #include "world/EntityState.hpp"