From fd3f981ec0263650cb31409e201170732e416b88 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Thu, 12 Feb 2026 23:15:35 +0100 Subject: [PATCH] Proper AABBs of chunks&objs, camera sweep test --- src/assets/map.cpp | 27 ++++++++++--- src/assets/model.cpp | 2 + src/assets/model.hpp | 5 ++- src/client/app.cpp | 39 ++---------------- src/client/app.hpp | 6 +-- src/collision/dynamicsworld.cpp | 24 +++-------- src/collision/dynamicsworld.hpp | 7 ++-- src/game/openworld.cpp | 2 +- src/game/world.cpp | 7 ++-- src/game/world.hpp | 4 ++ src/gameview/characterview.cpp | 2 + src/gameview/client_session.cpp | 71 ++++++++++++++++++++++++++++++--- src/gameview/client_session.hpp | 11 +++-- src/gameview/worldview.cpp | 26 ++++++++++++ src/gameview/worldview.hpp | 11 ++--- src/utils/aabb.hpp | 6 +++ 16 files changed, 163 insertions(+), 87 deletions(-) diff --git a/src/assets/map.cpp b/src/assets/map.cpp index de0bfdc..2446c49 100644 --- a/src/assets/map.cpp +++ b/src/assets/map.cpp @@ -9,6 +9,26 @@ #include "cmdfile.hpp" #include "utils/files.hpp" +static AABB3 TransformAABB(const AABB3& aabb, const glm::mat4& mat) +{ + const glm::vec3 corners[] = { + glm::vec3(aabb.min.x, aabb.min.y, aabb.min.z), glm::vec3(aabb.max.x, aabb.min.y, aabb.min.z), + glm::vec3(aabb.min.x, aabb.max.y, aabb.min.z), glm::vec3(aabb.max.x, aabb.max.y, aabb.min.z), + glm::vec3(aabb.min.x, aabb.min.y, aabb.max.z), glm::vec3(aabb.max.x, aabb.min.y, aabb.max.z), + glm::vec3(aabb.min.x, aabb.max.y, aabb.max.z), glm::vec3(aabb.max.x, aabb.max.y, aabb.max.z), + }; + + AABB3 new_aabb; + + for (size_t i = 0; i < 8; ++i) + { + glm::vec3 p = mat * glm::vec4(corners[i], 1.0f); + new_aabb.AddPoint(p); + } + + return new_aabb; +} + std::shared_ptr assets::Map::LoadFromFile(const std::string& filename) { auto map = std::make_shared(); @@ -58,8 +78,8 @@ std::shared_ptr assets::Map::LoadFromFile(const std::string& obj.node.UpdateMatrix(); - obj.aabb.min = trans.position - glm::vec3(10.0f); - obj.aabb.max = trans.position + glm::vec3(10.0f); + obj.aabb = TransformAABB(obj.model->GetAABB(), obj.node.matrix); + chunk->aabb.AddAABB(obj.aabb); std::string flag; while (iss >> flag) @@ -79,7 +99,6 @@ std::shared_ptr assets::Map::LoadFromFile(const std::string& iss >> coord.x >> coord.y; iss >> chunk->aabb.min.x >> chunk->aabb.min.y >> chunk->aabb.min.z; iss >> chunk->aabb.max.x >> chunk->aabb.max.y >> chunk->aabb.max.z; - } else if (command == "surface") { @@ -181,7 +200,6 @@ void assets::Map::Draw(const game::view::DrawArgs& args) const DrawChunk(args, mesh, chunk); } - } void assets::Map::DrawChunk(const game::view::DrawArgs& args, const Mesh& basemesh, const Chunk& chunk) const @@ -219,4 +237,3 @@ void assets::Map::DrawChunk(const game::view::DrawArgs& args, const Mesh& baseme } #endif // CLIENT - diff --git a/src/assets/model.cpp b/src/assets/model.cpp index b5b7f8c..0482e73 100644 --- a/src/assets/model.cpp +++ b/src/assets/model.cpp @@ -45,6 +45,8 @@ std::shared_ptr assets::Model::LoadFromFile(const std::stri if (temp_hull) temp_hull->addPoint(btVector3(pos.x, pos.y, pos.z), false); + + model->aabb_.AddPoint(pos); } else if (command == "f") { diff --git a/src/assets/model.hpp b/src/assets/model.hpp index 9ae103b..30825c4 100644 --- a/src/assets/model.hpp +++ b/src/assets/model.hpp @@ -5,6 +5,7 @@ #include "skeleton.hpp" #include "utils/defs.hpp" +#include "utils/aabb.hpp" #include "collision/trianglemesh.hpp" #ifdef CLIENT @@ -45,6 +46,7 @@ public: const std::shared_ptr& GetSkeleton() const { return skeleton_; } CLIENT_ONLY(const std::shared_ptr& GetMesh() const { return mesh_; }) + const AABB3& GetAABB() const { return aabb_; } private: std::unique_ptr cmesh_; @@ -52,7 +54,8 @@ private: std::unique_ptr cshape_; std::shared_ptr skeleton_; - CLIENT_ONLY(std::shared_ptr mesh_;) + CLIENT_ONLY(std::shared_ptr mesh_;); + AABB3 aabb_; }; diff --git a/src/client/app.cpp b/src/client/app.cpp index dcf18c4..293072b 100644 --- a/src/client/app.cpp +++ b/src/client/app.cpp @@ -66,7 +66,6 @@ void App::Frame() session_->Update(updinfo); } - float aspect = static_cast(viewport_size_.x) / static_cast(viewport_size_.y); renderer_.Begin(viewport_size_.x, viewport_size_.y); renderer_.ClearColor(glm::vec3(0.5f, 0.7f, 1.0f)); @@ -78,43 +77,11 @@ void App::Frame() params.screen_height = viewport_size_.y; const game::view::WorldView* world; - if (session_ && (world = session_->GetWorld())) + if (session_) { - // glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f); - glm::vec3 eye; - glm::mat4 view; - session_->GetViewInfo(eye, view); - - params.view_proj = proj * view; - params.cam_pos = eye; - - game::view::DrawArgs draw_args(dlist_, params.view_proj, eye, viewport_size_, 500.0f); - world->Draw(draw_args); - - glm::mat4 camera_world = glm::inverse(view); - audiomaster_.SetListenerOrientation(camera_world); - - if (time_ - last_send_time_ > 0.040f) - { - net::ViewYawQ yaw_q; - net::ViewPitchQ pitch_q; - yaw_q.Encode(session_->GetYaw()); - pitch_q.Encode(session_->GetPitch()); - - if (yaw_q.value != view_yaw_q_.value || pitch_q.value != view_pitch_q_.value) - { - auto msg = BeginMsg(net::MSG_VIEWANGLES); - msg.Write(yaw_q.value); - msg.Write(pitch_q.value); - - view_yaw_q_.value = yaw_q.value; - view_pitch_q_.value = pitch_q.value; - last_send_time_ = time_; - } - } + session_->Draw(dlist_, params); } - + // draw chat UpdateChat(); DrawChat(dlist_); diff --git a/src/client/app.hpp b/src/client/app.hpp index 0f8101f..7248185 100644 --- a/src/client/app.hpp +++ b/src/client/app.hpp @@ -36,7 +36,7 @@ public: void SetInput(game::PlayerInputFlags input) { input_ = input; } void MouseMove(const glm::vec2& delta); - float GetTime() const { return delta_time_; } + float GetTime() const { return time_; } float GetDeltaTime() const { return delta_time_; } audio::Master& GetAudioMaster() { return audiomaster_; } @@ -55,12 +55,10 @@ private: private: float time_ = 0.0f; - float last_send_time_ = 0.0f; glm::ivec2 viewport_size_ = {800, 600}; game::PlayerInputFlags input_ = 0; game::PlayerInputFlags prev_input_ = 0; - net::ViewYawQ view_yaw_q_; - net::ViewPitchQ view_pitch_q_; + float prev_time_ = 0.0f; float delta_time_ = 0.0f; diff --git a/src/collision/dynamicsworld.cpp b/src/collision/dynamicsworld.cpp index 94e1684..60f7fc2 100644 --- a/src/collision/dynamicsworld.cpp +++ b/src/collision/dynamicsworld.cpp @@ -2,34 +2,22 @@ #include -collision::DynamicsWorld::DynamicsWorld(std::shared_ptr map) - : map_(std::move(map)), bt_dispatcher_(&bt_cfg_), +collision::DynamicsWorld::DynamicsWorld() + : bt_dispatcher_(&bt_cfg_), bt_world_(&bt_dispatcher_, &bt_broadphase_, &bt_solver_, &bt_cfg_), bt_veh_raycaster_(&bt_world_) { bt_world_.setGravity(btVector3(0, 0, -9.81f)); bt_broadphase_.getOverlappingPairCache()->setInternalGhostPairCallback(&bt_ghost_pair_cb_); - - AddMapCollision(); - - // btTransform t; - // t.setIdentity(); - // t.setOrigin(btVector3(0,0,-12)); - - - // TODO: remove - // static btDefaultMotionState motion(t); - // static btBoxShape box(btVector3(100, 100, 2)); - // btRigidBody::btRigidBodyConstructionInfo rbInfo(0.0f, &motion, &box, btVector3(0,0,0)); - // static btRigidBody body(rbInfo); - // bt_world_.addRigidBody(&body); } -void collision::DynamicsWorld::AddMapCollision() +void collision::DynamicsWorld::AddMapCollision(std::shared_ptr map) { - if (!map_) // is perfectly possible that there is no map in this world + if (!map) return; + map_ = std::move(map); + // add basemodel const auto& basemodel = map_->GetBaseModel(); if (basemodel) diff --git a/src/collision/dynamicsworld.hpp b/src/collision/dynamicsworld.hpp index 9b5c8be..fd06478 100644 --- a/src/collision/dynamicsworld.hpp +++ b/src/collision/dynamicsworld.hpp @@ -25,16 +25,15 @@ namespace collision class DynamicsWorld { public: - DynamicsWorld(std::shared_ptr map); + DynamicsWorld(); + void AddMapCollision(std::shared_ptr map); + btDynamicsWorld& GetBtWorld() { return bt_world_; } const btDynamicsWorld& GetBtWorld() const { return bt_world_; } btVehicleRaycaster& GetVehicleRaycaster() { return bt_veh_raycaster_; } - - const std::shared_ptr& GetMap() const { return map_; } private: - void AddMapCollision(); void AddModelInstance(const assets::Model& model, const Transform& trans); private: diff --git a/src/game/openworld.cpp b/src/game/openworld.cpp index b1e1e97..93efc05 100644 --- a/src/game/openworld.cpp +++ b/src/game/openworld.cpp @@ -552,7 +552,7 @@ static const char* GetRandomCarModel() void game::OpenWorld::SpawnBot() { - auto roads = GetMap()->GetGraph("roads"); + auto roads = GetMap().GetGraph("roads"); if (!roads) { diff --git a/src/game/world.cpp b/src/game/world.cpp index fbec9f7..dc4560d 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -5,13 +5,12 @@ #include "assets/cache.hpp" #include "utils/allocnum.hpp" -static std::shared_ptr LoadMapByName(const std::string& mapname) +game::World::World(std::string mapname) : mapname_(std::move(mapname)) { - return assets::CacheManager::GetMap("data/" + mapname + ".map"); + map_ = assets::CacheManager::GetMap("data/" + mapname_ + ".map"); + AddMapCollision(map_); } -game::World::World(std::string mapname) : DynamicsWorld(LoadMapByName(mapname)), mapname_(std::move(mapname)) {} - net::EntNum game::World::GetNewEntnum() { auto entnum = utils::AllocNum(ents_, last_entnum_); diff --git a/src/game/world.hpp b/src/game/world.hpp index b92a18c..70a82df 100644 --- a/src/game/world.hpp +++ b/src/game/world.hpp @@ -46,7 +46,11 @@ public: virtual ~World() = default; +protected: + const assets::Map& GetMap() const { return *map_; } + private: + std::shared_ptr map_; std::string mapname_; std::map> ents_; net::EntNum last_entnum_ = 0; diff --git a/src/gameview/characterview.cpp b/src/gameview/characterview.cpp index 90c0c2a..a73d569 100644 --- a/src/gameview/characterview.cpp +++ b/src/gameview/characterview.cpp @@ -35,6 +35,8 @@ game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) states_[0] = states_[1]; // lerp from the read state to avoid jump + + radius_ = 2.0f; } bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& msg) diff --git a/src/gameview/client_session.cpp b/src/gameview/client_session.cpp index ac1c67d..7fe3930 100644 --- a/src/gameview/client_session.cpp +++ b/src/gameview/client_session.cpp @@ -64,18 +64,29 @@ void game::view::ClientSession::ProcessMouseMove(float delta_yaw, float delta_pi void game::view::ClientSession::Update(const UpdateInfo& info) { if (world_) + { world_->Update(info); + SendViewAngles(info.time); + } +} + +void game::view::ClientSession::Draw(gfx::DrawList& dlist, gfx::DrawListParams& params) +{ + if (world_) + { + DrawWorld(dlist, params); + } } void game::view::ClientSession::GetViewInfo(glm::vec3& eye, glm::mat4& view) const { - glm::vec3 center(0.0f, 0.0f, 2.5f); + glm::vec3 start(0.0f, 0.0f, 2.0f); - if (world_ && follow_ent_) + if (follow_ent_) { auto ent = world_->GetEntity(follow_ent_); if (ent) - center += ent->GetRoot().local.position; + start += ent->GetRoot().local.position; } float yaw_cos = glm::cos(yaw_); @@ -84,10 +95,12 @@ void game::view::ClientSession::GetViewInfo(glm::vec3& eye, glm::mat4& view) con float pitch_sin = glm::sin(pitch_); glm::vec3 dir(yaw_cos * pitch_cos, yaw_sin * pitch_cos, pitch_sin); - float distance = 8.0f; + float distance = 5.0f; + glm::vec3 end = start - dir * distance; - eye = center - dir * distance; - view = glm::lookAt(eye, center, glm::vec3(0, 0, 1)); + //start.z -= 0.5f; // shift this a bit to make it better when occluded + eye = world_->CameraSweep(start, end); + view = glm::lookAt(eye, eye + dir, glm::vec3(0, 0, 1)); } audio::Master& game::view::ClientSession::GetAudioMaster() const @@ -124,3 +137,49 @@ bool game::view::ClientSession::ProcessChatMsg(net::InMessage& msg) app_.AddChatMessagePrefix("Server", chatm); return true; } + +void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params) +{ + // glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, + // 0.0f, 1.0f)); + float aspect = static_cast(params.screen_width) / static_cast(params.screen_height); + + glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f); + glm::vec3 eye; + glm::mat4 view; + GetViewInfo(eye, view); + + params.view_proj = proj * view; + params.cam_pos = eye; + + // glm::mat4 fake_view_proj = glm::perspective(glm::radians(30.0f), aspect, 0.1f, 3000.0f) * view; + + game::view::DrawArgs draw_args(dlist, params.view_proj, eye, glm::ivec2(params.screen_width, params.screen_height), + 500.0f); + world_->Draw(draw_args); + + glm::mat4 camera_world = glm::inverse(view); + GetAudioMaster().SetListenerOrientation(camera_world); +} + +void game::view::ClientSession::SendViewAngles(float time) +{ + if (time - last_send_time_ < 0.040f) + return; + + net::ViewYawQ yaw_q; + net::ViewPitchQ pitch_q; + yaw_q.Encode(yaw_); + pitch_q.Encode(pitch_); + + if (yaw_q.value == view_yaw_q_.value && pitch_q.value == view_pitch_q_.value) + return; + + auto msg = app_.BeginMsg(net::MSG_VIEWANGLES); + msg.Write(yaw_q.value); + msg.Write(pitch_q.value); + + view_yaw_q_.value = yaw_q.value; + view_pitch_q_.value = pitch_q.value; + last_send_time_ = time; +} diff --git a/src/gameview/client_session.hpp b/src/gameview/client_session.hpp index 56a7aa9..4718de7 100644 --- a/src/gameview/client_session.hpp +++ b/src/gameview/client_session.hpp @@ -5,6 +5,7 @@ #include "worldview.hpp" #include "gfx/draw_list.hpp" +#include "gfx/renderer.hpp" #include "net/defs.hpp" #include "net/inmessage.hpp" @@ -24,6 +25,7 @@ public: void ProcessMouseMove(float delta_yaw, float delta_pitch); void Update(const UpdateInfo& info); + void Draw(gfx::DrawList& dlist, gfx::DrawListParams& params); const WorldView* GetWorld() const { return world_.get(); } @@ -31,15 +33,15 @@ public: audio::Master& GetAudioMaster() const; - float GetYaw() const { return yaw_; } - float GetPitch() const { return pitch_; } - private: // msg handlers bool ProcessWorldMsg(net::InMessage& msg); bool ProcessCameraMsg(net::InMessage& msg); bool ProcessChatMsg(net::InMessage& msg); + void DrawWorld(gfx::DrawList& dlist, gfx::DrawListParams& params); + void SendViewAngles(float time); + private: App& app_; @@ -48,6 +50,9 @@ private: float yaw_ = 0.0f, pitch_ = 0.0f; net::EntNum follow_ent_ = 0; + net::ViewYawQ view_yaw_q_; + net::ViewPitchQ view_pitch_q_; + float last_send_time_ = 0.0f; }; } // namespace game::view \ No newline at end of file diff --git a/src/gameview/worldview.cpp b/src/gameview/worldview.cpp index 2e11860..7e997ad 100644 --- a/src/gameview/worldview.cpp +++ b/src/gameview/worldview.cpp @@ -11,6 +11,7 @@ game::view::WorldView::WorldView(ClientSession& session) : audiomaster_(session_.GetAudioMaster()) { map_ = assets::CacheManager::GetMap("data/openworld.map"); + AddMapCollision(map_); } bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg) @@ -53,6 +54,31 @@ void game::view::WorldView::Draw(const DrawArgs& args) const } } +glm::vec3 game::view::WorldView::CameraSweep(const glm::vec3& start, const glm::vec3& end) +{ + const auto& bt_world = GetBtWorld(); + + static const btSphereShape shape(0.1f); + + btVector3 bt_start(start.x, start.y, start.z); + btVector3 bt_end(end.x, end.y, end.z); + + btTransform from, to; + from.setIdentity(); + from.setOrigin(bt_start); + to.setIdentity(); + to.setOrigin(bt_end); + + btCollisionWorld::ClosestConvexResultCallback cb(bt_start, bt_end); + + bt_world.convexSweepTest(&shape, from, to, cb); + + if (!cb.hasHit()) + return end; + + return glm::mix(start, end, cb.m_closestHitFraction); +} + game::view::EntityView* game::view::WorldView::GetEntity(net::EntNum entnum) { auto it = ents_.find(entnum); diff --git a/src/gameview/worldview.hpp b/src/gameview/worldview.hpp index 4fbfa0f..59bb84d 100644 --- a/src/gameview/worldview.hpp +++ b/src/gameview/worldview.hpp @@ -4,7 +4,7 @@ #include "draw_args.hpp" #include "net/defs.hpp" #include "net/inmessage.hpp" - +#include "collision/dynamicsworld.hpp" #include "entityview.hpp" namespace game::view @@ -12,7 +12,7 @@ namespace game::view class ClientSession; -class WorldView +class WorldView : public collision::DynamicsWorld { public: WorldView(ClientSession& session); @@ -22,10 +22,11 @@ public: void Update(const UpdateInfo& info); void Draw(const DrawArgs& args) const; - EntityView* GetEntity(net::EntNum entnum); - - float GetTime() const { return time_; } + glm::vec3 CameraSweep(const glm::vec3& start, const glm::vec3& end); + EntityView* GetEntity(net::EntNum entnum); + + float GetTime() const { return time_; } audio::Master& GetAudioMaster() const { return audiomaster_; } private: diff --git a/src/utils/aabb.hpp b/src/utils/aabb.hpp index fff5086..a8e7178 100644 --- a/src/utils/aabb.hpp +++ b/src/utils/aabb.hpp @@ -22,6 +22,12 @@ struct AABB max = glm::max(max, point); } + void AddAABB(const AABB& other) + { + min = glm::min(min, other.min); + max = glm::max(max, other.max); + } + bool CollidesWith(const AABB& other) const; AABB Intersection(const AABB& other) const