From: Daniel Karbach Date: Thu, 5 Nov 2015 16:45:01 +0000 (+0100) Subject: tentative optimization of chunk intersection test X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=ee920127d653b8a3cfbee1efefde909ffa177662;p=blank.git tentative optimization of chunk intersection test that really gets used a lot °° --- diff --git a/src/geometry/distance.hpp b/src/geometry/distance.hpp index d4bec9b..b53fcd7 100644 --- a/src/geometry/distance.hpp +++ b/src/geometry/distance.hpp @@ -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 inline bool iszero(const T &v) noexcept { return length_squared(v) < std::numeric_limits::epsilon(); diff --git a/src/geometry/primitive.hpp b/src/geometry/primitive.hpp index 351a3a4..7da1096 100644 --- a/src/geometry/primitive.hpp +++ b/src/geometry/primitive.hpp @@ -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 { diff --git a/src/world/Chunk.hpp b/src/world/Chunk.hpp index 6e87a09..e8773fa 100644 --- a/src/world/Chunk.hpp +++ b/src/world/Chunk.hpp @@ -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 diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index 3bcc21f..b3eb1f4 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -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 diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index cedc532..a6f1521 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -400,13 +400,20 @@ bool Chunk::Intersection( const glm::mat4 &Mchunk, std::vector &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; } diff --git a/src/world/world.cpp b/src/world/world.cpp index 51c060c..3a1aac2 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -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 &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(