]> git.localhorst.tv Git - blank.git/commitdiff
tentative optimization of chunk intersection test
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 5 Nov 2015 16:45:01 +0000 (17:45 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 5 Nov 2015 16:45:01 +0000 (17:45 +0100)
that really gets used a lot °°

src/geometry/distance.hpp
src/geometry/primitive.hpp
src/world/Chunk.hpp
src/world/Entity.hpp
src/world/chunk.cpp
src/world/world.cpp

index d4bec9b94f5dbdbc98fa8a84120a07d631efa964..b53fcd7c679c7630051ba7911ecdd35818161b48 100644 (file)
@@ -16,6 +16,10 @@ inline float distance_squared(const glm::vec3 &a, const glm::vec3 &b) noexcept {
        return length_squared(a - b);
 }
 
+inline float distance(const glm::vec3 &a, const glm::vec3 &b) noexcept {
+       return length(a - b);
+}
+
 template <class T>
 inline bool iszero(const T &v) noexcept {
        return length_squared(v) < std::numeric_limits<typename T::value_type>::epsilon();
index 351a3a432e1c17d3662b9544012e5c997c22328c..7da1096b38ddd528546748d232289a7e30fefa3a 100644 (file)
@@ -20,6 +20,12 @@ struct AABB {
        glm::vec3 Center() const noexcept {
                return min + (max - min) * 0.5f;
        }
+
+       /// return distance between origin and farthest vertex
+       float OriginRadius() const noexcept {
+               glm::vec3 high(glm::max(abs(min), abs(max)));
+               return length(high);
+       }
 };
 
 struct Ray {
index 6e87a0907d15059cea8b15e5255022b333b4c12b..e8773faa5dbf84691d9fbbcf054c796c6e1a6bcc 100644 (file)
@@ -30,6 +30,8 @@ public:
        static constexpr int size = side * side * side;
 
        static AABB Bounds() noexcept { return AABB{ { 0.0f, 0.0f, 0.0f }, ExactLocation::FExtent() }; }
+       static glm::vec3 Center() noexcept { return glm::vec3(8.0f); }
+       static float Radius() noexcept { return 27.71281292110203669632f; /* 16 * √3 */ }
 
        static constexpr bool InBounds(const ExactLocation::Fine &pos) noexcept {
                return
index 3bcc21f65f2573a456d094bb3a0656c1b1001e99..b3eb1f4360e57c5f95fd14039cd4669eacd33ee8 100644 (file)
@@ -49,7 +49,9 @@ public:
        void Name(const std::string &n) { name = n; }
 
        const AABB &Bounds() const noexcept { return bounds; }
-       void Bounds(const AABB &b) noexcept { bounds = b; }
+       // get distance between local origin and farthest vertex
+       float Radius() const noexcept { return radius; }
+       void Bounds(const AABB &b) noexcept { bounds = b; radius = b.OriginRadius(); }
 
        bool WorldCollidable() const noexcept { return world_collision; }
        void WorldCollidable(bool b) noexcept { world_collision = b; }
@@ -136,6 +138,7 @@ private:
        std::string name;
 
        AABB bounds;
+       float radius;
        EntityState state;
 
        /// chunk to model space
index cedc532aed726a838d2b9ad10b7ea04be16eafb5..a6f1521eeeafc39bdacf7478475f21b725007104 100644 (file)
@@ -400,13 +400,20 @@ bool Chunk::Intersection(
        const glm::mat4 &Mchunk,
        std::vector<WorldCollision> &col
 ) noexcept {
+       // box's origin relative to the chunk
+       const glm::vec3 box_coords(Mbox[3] - Mchunk[3]);
+       const float box_rad = box.OriginRadius();
+
+       if (distance_squared(box_coords, Center()) > (box_rad + Radius()) * (box_rad + Radius())) {
+               return false;
+       }
+
        bool any = false;
        float penetration;
        glm::vec3 normal;
 
-       if (!blank::Intersection(box, Mbox, Bounds(), Mchunk, penetration, normal)) {
-               return false;
-       }
+       // assume a bounding radius of 2 for blocks
+       constexpr float block_rad = 2.0f;
        for (int idx = 0, z = 0; z < side; ++z) {
                for (int y = 0; y < side; ++y) {
                        for (int x = 0; x < side; ++x, ++idx) {
@@ -414,7 +421,11 @@ bool Chunk::Intersection(
                                if (!type.collision || !type.shape) {
                                        continue;
                                }
-                               if (type.shape->Intersects(Mchunk * ToTransform(RoughLocation::Fine(x, y, z), idx), box, Mbox, penetration, normal)) {
+                               const RoughLocation::Fine block_pos(x, y, z);
+                               const ExactLocation::Fine block_coords(ToCoords(block_pos));
+                               if (distance_squared(box_coords, block_coords) <= (box_rad + block_rad) * (box_rad + block_rad)
+                                       && type.shape->Intersects(Mchunk * ToTransform(block_pos, idx), box, Mbox, penetration, normal)
+                               ) {
                                        col.emplace_back(this, idx, penetration, normal);
                                        any = true;
                                }
index 51c060c1c5bf411c183e01da278f2ab12422e451..3a1aac251f0bbb71cb9cd1414b9e55533ce9bd86 100644 (file)
@@ -33,6 +33,7 @@ Entity::Entity() noexcept
 , id(-1)
 , name("anonymous")
 , bounds()
+, radius(0.0f)
 , state()
 , heading(0.0f, 0.0f, -1.0f)
 , max_vel(5.0f)
@@ -520,10 +521,24 @@ bool World::Intersection(
 }
 
 bool World::Intersection(const Entity &e, const EntityState &s, std::vector<WorldCollision> &col) {
+       // TODO: make special case for entities here and in Chunk::Intersection so entity's bounding radius
+       //       doesn't have to be calculated over and over again (sqrt)
        AABB box = e.Bounds();
        glm::ivec3 reference = s.pos.chunk;
        glm::mat4 M = s.Transform(reference);
-       return Intersection(box, M, reference, col);
+
+       bool any = false;
+       for (Chunk &cur_chunk : chunks) {
+               if (manhattan_radius(cur_chunk.Position() - reference) > 1) {
+                       // chunk is not one of the 3x3x3 surrounding the entity
+                       // since there's no entity which can extent over 16 blocks, they can be skipped
+                       continue;
+               }
+               if (cur_chunk.Intersection(box, M, cur_chunk.Transform(reference), col)) {
+                       any = true;
+               }
+       }
+       return any;
 }
 
 bool World::Intersection(