diff --git a/src/maths/aabb.hpp b/src/maths/aabb.hpp index 471441951..d5dc9493b 100644 --- a/src/maths/aabb.hpp +++ b/src/maths/aabb.hpp @@ -38,6 +38,14 @@ struct AABB { return AABB(a + pos, b + pos); } + AABB operator+(const glm::vec3& offset) const { + return translated(offset); + } + + AABB operator-(const glm::vec3& offset) const { + return translated(-offset); + } + /// @brief Multiply AABB size from center inline void scale(const glm::vec3 mul) { glm::vec3 center = (a + b) * 0.5f; @@ -91,14 +99,14 @@ struct AABB { addPoint(matrix * glm::vec4(pb.x, pa.y, pb.z, 1.0f)); } - inline bool intersect(const AABB& aabb) { + inline bool intersects(const AABB& aabb) const { return ( a.x <= aabb.b.x && b.x >= aabb.a.x && a.y <= aabb.b.y && b.y >= aabb.a.y && a.z <= aabb.b.z && b.z >= aabb.a.z ); } - inline bool intersect(const AABB& aabb, float margin) { + inline bool intersects(const AABB& aabb, float margin) const { return ( a.x <= aabb.b.x + margin && b.x >= aabb.a.x - margin && a.y <= aabb.b.y + margin && b.y >= aabb.a.y - margin && diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index cbb507c89..a41ab7798 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -450,7 +450,7 @@ void Entities::render( bool Entities::hasBlockingInside(AABB aabb) { auto view = registry->view(); for (auto [entity, eid, body] : view.each()) { - if (eid.def.blocking && aabb.intersect(body.hitbox.getAABB(), -0.05f)) { + if (eid.def.blocking && aabb.intersects(body.hitbox.getAABB(), -0.05f)) { return true; } } diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index e20bafacd..1a33952f7 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -5,8 +5,8 @@ #include "voxels/Block.hpp" #include "voxels/GlobalChunks.hpp" #include "voxels/voxel.hpp" +#include "debug/Logger.hpp" -#include #include #define GLM_ENABLE_EXPERIMENTAL #include @@ -14,8 +14,12 @@ inline const float E = 0.03f; inline const float MAX_FIX = 0.1f; +static debug::Logger logger("physics-solver"); + PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) {} +static int samples_count = 0; + void PhysicsSolver::step( const GlobalChunks& chunks, Hitbox& hitbox, @@ -23,9 +27,9 @@ void PhysicsSolver::step( uint substeps, entityid_t entity ) { + samples_count = 0; float dt = delta / static_cast(substeps); float linearDamping = hitbox.linearDamping * hitbox.friction; - float s = 2.0f/BLOCK_AABB_GRID; auto half = hitbox.getHalfSize(); glm::vec3& pos = hitbox.position; @@ -53,11 +57,12 @@ void PhysicsSolver::step( if (hitbox.crouching && hitbox.grounded){ float y = (pos.y-half.y-E); hitbox.grounded = false; - for (int ix = 0; ix <= (half.x-E)*2/s; ix++) { - float x = (px-half.x+E) + ix * s; - for (int iz = 0; iz <= (half.z-E)*2/s; iz++){ - float z = (pos.z-half.z+E) + iz * s; - if (chunks.isObstacleAt(x,y,z)){ + for (int ix = 0; ix <= glm::ceil((half.x-E)*2); ix++) { + float x = (px-half.x+E) + ix; + for (int iz = 0; iz <= glm::ceil((half.z-E)*2); iz++){ + float z = (pos.z-half.z+E) + iz; + samples_count++; + if (chunks.isObstacleAt(x,y,z, AABB(pos - half, pos + half))){ hitbox.grounded = true; break; } @@ -68,11 +73,12 @@ void PhysicsSolver::step( vel.z = 0.0f; } hitbox.grounded = false; - for (int ix = 0; ix <= (half.x-E)*2/s; ix++) { - float x = (pos.x-half.x+E) + ix * s; - for (int iz = 0; iz <= (half.z-E)*2/s; iz++){ - float z = (pz-half.z+E) + iz * s; - if (chunks.isObstacleAt(x,y,z)){ + for (int ix = 0; ix <= glm::ceil((half.x-E)*2); ix++) { + float x = (pos.x-half.x+E) + ix; + for (int iz = 0; iz <= glm::ceil((half.z-E)*2); iz++){ + float z = (pz-half.z+E) + iz; + samples_count++; + if (chunks.isObstacleAt(x,y,z, AABB(pos - half, pos + half))){ hitbox.grounded = true; break; } @@ -103,7 +109,7 @@ void PhysicsSolver::step( bool triggered = false; switch (sensor.type) { case SensorType::AABB: - triggered = aabb.intersect(sensor.calculated.aabb); + triggered = aabb.intersects(sensor.calculated.aabb); break; case SensorType::RADIUS: triggered = glm::distance2( @@ -118,21 +124,23 @@ void PhysicsSolver::step( sensor.nextEntered.insert(entity); } } + logger.info() << "total samples: " << samples_count; } static float calc_step_height( const GlobalChunks& chunks, const glm::vec3& pos, const glm::vec3& half, - float stepHeight, - float s + float stepHeight ) { + AABB aabb(pos - half, pos + half); if (stepHeight > 0.0f) { - for (int ix = 0; ix <= (half.x-E)*2/s; ix++) { - float x = (pos.x-half.x+E) + ix * s; - for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { - float z = (pos.z-half.z+E) + iz * s; - if (chunks.isObstacleAt(x, pos.y+half.y+stepHeight, z)) { + for (int ix = 0; ix <= glm::ceil((half.x-E) * 2); ix++) { + float x = (pos.x-half.x+E) + ix; + for (int iz = 0; iz <= glm::ceil((half.z-E)*2); iz++) { + float z = (pos.z-half.z+E) + iz; + samples_count++; + if (chunks.isObstacleAt(x, pos.y+half.y+stepHeight, z, aabb)) { return 0.0f; } } @@ -147,20 +155,26 @@ static bool calc_collision_neg( glm::vec3& pos, glm::vec3& vel, const glm::vec3& half, - float stepHeight, - float s + float stepHeight ) { if (vel[nx] >= 0.0f) { return false; } glm::vec3 offset(0.0f, stepHeight, 0.0f); - for (int iy = 0; iy <= std::max(1, ((half-offset*0.5f)[ny]-E)*2/s); iy++) { + for (int iy = 0; iy <= glm::ceil(((half-offset*0.5f)[ny]-E)*2); iy++) { glm::vec3 coord; - coord[ny] = ((pos+offset)[ny]-half[ny]+E) + iy * s; - for (int iz = 0; iz <= (half[nz]-E)*2/s; iz++){ - coord[nz] = (pos[nz]-half[nz]+E) + iz * s; + coord[ny] = ((pos+offset)[ny]-half[ny]+E) + iy; + for (int iz = 0; iz <= glm::ceil((half[nz]-E)*2); iz++){ + coord[nz] = (pos[nz]-half[nz]+E) + iz; coord[nx] = (pos[nx]-half[nx]-E); - if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z)) { + samples_count++; + + auto boxAABB = AABB(pos - half, pos + half); + glm::vec3 scale(1.0f); + scale[nz] = 1.0f - E * 2.0f; + boxAABB.scale(scale); + + if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z, boxAABB)) { vel[nx] = 0.0f; float newx = std::floor(coord[nx]) + half[nx] + aabb->max()[nx] + E; if (newx - pos[nx] <= E) { @@ -179,23 +193,29 @@ static void calc_collision_pos( glm::vec3& pos, glm::vec3& vel, const glm::vec3& half, - float stepHeight, - float s + float stepHeight ) { if (vel[nx] <= 0.0f) { return; } glm::vec3 offset(0.0f, stepHeight, 0.0f); - for (int iy = 0; iy <= std::max(1, ((half-offset*0.5f)[ny]-E)*2/s); iy++) { + for (int iy = 0; iy <= glm::ceil(((half-offset*0.5f)[ny]-E)*2); iy++) { glm::vec3 coord; - coord[ny] = ((pos+offset)[ny]-half[ny]+E) + iy * s; - for (int iz = 0; iz <= (half[nz]-E)*2/s; iz++) { - coord[nz] = (pos[nz]-half[nz]+E) + iz * s; + coord[ny] = ((pos+offset)[ny]-half[ny]+E) + iy; + for (int iz = 0; iz <= glm::ceil((half[nz]-E)*2); iz++) { + coord[nz] = (pos[nz]-half[nz]+E) + iz; coord[nx] = (pos[nx]+half[nx]+E); - if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z)) { + samples_count++; + + auto boxAABB = AABB(pos - half, pos + half); + glm::vec3 scale(1.0f); + scale[nz] = 1.0f - E * 2.0f; + boxAABB.scale(scale); + + if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z, boxAABB)) { vel[nx] = 0.0f; float newx = std::floor(coord[nx]) - half[nx] + aabb->min()[nx] - E; - if (newx - pos[nx] <= E) { + if (newx - pos[nx] >= -E) { pos[nx] = newx; } return; @@ -212,30 +232,28 @@ void PhysicsSolver::colisionCalc( const glm::vec3 half, float stepHeight ) { - // step size (smaller - more accurate, but slower) // TODO: GET RID OF THIS - float s = 2.0f/BLOCK_AABB_GRID; - - stepHeight = calc_step_height(chunks, pos, half, stepHeight, s); + stepHeight = calc_step_height(chunks, pos, half, stepHeight); const AABB* aabb; - calc_collision_neg<0, 1, 2>(chunks, pos, vel, half, stepHeight, s); - calc_collision_pos<0, 1, 2>(chunks, pos, vel, half, stepHeight, s); + calc_collision_neg<0, 1, 2>(chunks, pos, vel, half, stepHeight); + calc_collision_pos<0, 1, 2>(chunks, pos, vel, half, stepHeight); - calc_collision_neg<2, 1, 0>(chunks, pos, vel, half, stepHeight, s); - calc_collision_pos<2, 1, 0>(chunks, pos, vel, half, stepHeight, s); + calc_collision_neg<2, 1, 0>(chunks, pos, vel, half, stepHeight); + calc_collision_pos<2, 1, 0>(chunks, pos, vel, half, stepHeight); - if (calc_collision_neg<1, 0, 2>(chunks, pos, vel, half, 0.0f, s)) { + if (calc_collision_neg<1, 0, 2>(chunks, pos, vel, half, 0.0f)) { hitbox.grounded = true; } if (stepHeight > 0.0 && vel.y <= 0.0f){ - for (int ix = 0; ix <= (half.x-E)*2/s; ix++) { - float x = (pos.x-half.x+E) + ix * s; - for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { - float z = (pos.z-half.z+E) + iz * s; + for (int ix = 0; ix <= glm::ceil((half.x-E)*2); ix++) { + float x = (pos.x-half.x+E) + ix; + for (int iz = 0; iz <= glm::ceil((half.z-E)*2); iz++) { + float z = (pos.z-half.z+E) + iz; float y = (pos.y-half.y+E); - if ((aabb = chunks.isObstacleAt(x,y,z))){ + samples_count++; + if ((aabb = chunks.isObstacleAt(x,y,z, AABB(pos - half, pos + half)))){ vel.y = 0.0f; float newy = std::floor(y) + aabb->max().y + half.y; if (std::abs(newy-pos.y) <= MAX_FIX+stepHeight) { @@ -247,12 +265,13 @@ void PhysicsSolver::colisionCalc( } } if (vel.y > 0.0f){ - for (int ix = 0; ix <= (half.x-E)*2/s; ix++) { - float x = (pos.x-half.x+E) + ix * s; - for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { - float z = (pos.z-half.z+E) + iz * s; + for (int ix = 0; ix <= glm::ceil((half.x-E)*2); ix++) { + float x = (pos.x-half.x+E) + ix; + for (int iz = 0; iz <= glm::ceil((half.z-E)*2); iz++) { + float z = (pos.z-half.z+E) + iz; float y = (pos.y+half.y+E); - if ((aabb = chunks.isObstacleAt(x,y,z))){ + samples_count++; + if ((aabb = chunks.isObstacleAt(x,y,z, AABB(pos - half, pos + half)))){ vel.y = 0.0f; float newy = std::floor(y) - half.y + aabb->min().y - E; if (std::abs(newy-pos.y) <= MAX_FIX) { diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index dc3f6153f..2a85b38bd 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -1,11 +1,5 @@ #include "Chunks.hpp" -#include - -#include -#include -#include - #include "data/StructLayout.hpp" #include "coders/byte_utils.hpp" #include "content/Content.hpp" @@ -20,6 +14,11 @@ #include "VoxelsVolume.hpp" #include "blocks_agent.hpp" +#include +#include +#include +#include + Chunks::Chunks( int32_t w, int32_t d, @@ -67,20 +66,21 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z) const { } } const auto& def = indices.blocks.require(v->id); - if (def.obstacle) { - glm::ivec3 offset {}; - if (v->state.segment) { - glm::ivec3 point(ix, iy, iz); - offset = seekOrigin(point, def, v->state) - point; - } - const auto& boxes = - def.rotatable ? def.rt.hitboxes[v->state.rotation] : def.hitboxes; - for (const auto& hitbox : boxes) { - if (hitbox.contains( - {x - ix - offset.x, y - iy - offset.y, z - iz - offset.z} - )) { - return &hitbox; - } + if (!def.obstacle) { + return nullptr; + } + glm::ivec3 offset {}; + if (v->state.segment) { + glm::ivec3 point(ix, iy, iz); + offset = seekOrigin(point, def, v->state) - point; + } + const auto& boxes = + def.rotatable ? def.rt.hitboxes[v->state.rotation] : def.hitboxes; + for (const auto& hitbox : boxes) { + if (hitbox.contains( + {x - ix - offset.x, y - iy - offset.y, z - iz - offset.z} + )) { + return &hitbox; } } return nullptr; diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index 4fe24f289..9fdebff1c 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -1,17 +1,16 @@ #pragma once -#include - -#include -#include -#include -#include - #include "typedefs.hpp" #include "voxel.hpp" #include "constants.hpp" #include "util/AreaMap2D.hpp" +#include +#include +#include +#include +#include + class VoxelRenderer; struct AABB; diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 032ae17e2..11e9d5b5e 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -214,6 +214,6 @@ void GlobalChunks::putChunk(std::shared_ptr chunk) { chunksMap[keyfrom(chunk->x, chunk->z)] = std::move(chunk); } -const AABB* GlobalChunks::isObstacleAt(float x, float y, float z) const { - return blocks_agent::is_obstacle_at(*this, x, y, z); +const AABB* GlobalChunks::isObstacleAt(float x, float y, float z, const AABB& aabb) const { + return blocks_agent::is_obstacle_at(*this, x, y, z, aabb); } diff --git a/src/voxels/GlobalChunks.hpp b/src/voxels/GlobalChunks.hpp index 7120658c2..83b6c17bc 100644 --- a/src/voxels/GlobalChunks.hpp +++ b/src/voxels/GlobalChunks.hpp @@ -57,7 +57,7 @@ public: void putChunk(std::shared_ptr chunk); - const AABB* isObstacleAt(float x, float y, float z) const; + const AABB* isObstacleAt(float x, float y, float z, const AABB& aabb) const; inline Chunk* getChunk(int cx, int cz) const { const auto& found = chunksMap.find(keyfrom(cx, cz)); diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index 9ffac7f93..2dc80d14b 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -461,7 +461,7 @@ void get_voxels(const Chunks& chunks, VoxelsVolume* volume, bool backlight=false void get_voxels(const GlobalChunks& chunks, VoxelsVolume* volume, bool backlight=false); template -inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float z) { +inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float z, const AABB& aabb) { int ix = std::floor(x); int iy = std::floor(y); int iz = std::floor(z); @@ -475,23 +475,28 @@ inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float } } const auto& def = chunks.getContentIndices().blocks.require(v->id); - if (def.obstacle) { - glm::ivec3 offset {}; - if (v->state.segment) { - glm::ivec3 point(ix, iy, iz); - offset = seek_origin(chunks, point, def, v->state) - point; - } - const auto& boxes = - def.rotatable ? def.rt.hitboxes[v->state.rotation] : def.hitboxes; - for (const auto& hitbox : boxes) { - if (hitbox.contains( - {x - ix - offset.x, y - iy - offset.y, z - iz - offset.z} - )) { - return &hitbox; - } + if (!def.obstacle) { + return nullptr; + } + glm::ivec3 offset {}; + if (v->state.segment) { + glm::ivec3 point(ix, iy, iz); + offset = seek_origin(chunks, point, def, v->state) - point; + } + const auto& boxes = + def.rotatable ? def.rt.hitboxes[v->state.rotation] : def.hitboxes; + + for (const auto& hitbox : boxes) { + if (hitbox.intersects(aabb - glm::ivec3(ix, iy, iz))) { + return &hitbox; } } return nullptr; } +template +inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float z) { + return is_obstacle_at(chunks, x, y, z, AABB({x, y, z}, {x + 1, y + 1, z + 1})); +} + } // blocks_agent diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 1f9a2241d..260a28e3c 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -173,7 +173,7 @@ void WorldGenerator::placeStructure( } auto& otherPrototype = *found->second; auto chunkAABB = gen_chunk_aabb(chunkX + lcx, chunkZ + lcz); - if (chunkAABB.intersect(aabb)) { + if (chunkAABB.intersects(aabb)) { otherPrototype.placements.emplace_back( priority, StructurePlacement {