From 1a628d8f89d6a395d5853097c489bee248bdea22 Mon Sep 17 00:00:00 2001 From: det-fys Date: Fri, 22 Dec 2023 22:44:01 +0100 Subject: [PATCH] nejaka fyzika --- src/tsr/camera.hpp | 2 +- src/tsr/entity_cct.cpp | 154 ++++++++++++++++++++++++++++++++ src/tsr/entity_cct.hpp | 36 ++++++++ src/tsr/entity_model.cpp | 3 + src/tsr/entity_model.hpp | 2 +- src/tsr/game.cpp | 149 ++++++++++++++++++++++++------- src/tsr/game.hpp | 17 +++- src/tsr/ia.cpp | 8 +- src/tsr/ia.hpp | 2 +- src/tsr/model.cpp | 29 +++++- src/tsr/model.hpp | 18 ++++ src/tsr/physics.cpp | 187 +++++++++++++++++++++++++++++++++++++++ src/tsr/physics.hpp | 69 +++++++++++++++ src/tsr/renderer.cpp | 45 +++++++++- src/tsr/renderer.hpp | 26 ++++++ src/tsr/worldmap.cpp | 50 ++++++++++- src/tsr/worldmap.hpp | 10 ++- tsrecs.vcxproj | 4 + tsrecs.vcxproj.filters | 12 +++ 19 files changed, 774 insertions(+), 49 deletions(-) create mode 100644 src/tsr/entity_cct.cpp create mode 100644 src/tsr/entity_cct.hpp create mode 100644 src/tsr/physics.cpp create mode 100644 src/tsr/physics.hpp diff --git a/src/tsr/camera.hpp b/src/tsr/camera.hpp index f89203a..352097d 100644 --- a/src/tsr/camera.hpp +++ b/src/tsr/camera.hpp @@ -6,11 +6,11 @@ namespace TSR { class Camera { - glm::vec3 forward_backward_vector; glm::vec3 world_up; void UpdateVectors(); public: + glm::vec3 forward_backward_vector; glm::vec3 front_vector; glm::vec3 up_vector; glm::vec3 right_vector; diff --git a/src/tsr/entity_cct.cpp b/src/tsr/entity_cct.cpp new file mode 100644 index 0000000..eb95e3a --- /dev/null +++ b/src/tsr/entity_cct.cpp @@ -0,0 +1,154 @@ +#include "entity_cct.hpp" +#include "game.hpp" +#include "tsr.hpp" +#include "entity_cct.hpp" + +using namespace TSR; + +// component functions +static int CCTMove(CCTComponent& comp, const glm::vec3& disp, float dt) { + PxControllerFilters filters; + //filters.mCCTFilterCallback = nullptr; + //filters.mFilterCallback = nullptr; + + PxVec3 disp_px(disp.x, disp.y, disp.z); + auto col = comp.cct->move(disp_px, 0.001f, dt, filters); + + int ret = CCT_COLLISION_NONE; + if (col & PxControllerCollisionFlag::eCOLLISION_DOWN) + ret |= CCT_COLLISION_DOWN; + + if (col & PxControllerCollisionFlag::eCOLLISION_UP) + ret |= CCT_COLLISION_UP; + + if (col & PxControllerCollisionFlag::eCOLLISION_SIDES) + ret |= CCT_COLLISION_SIDE; + + return ret; +} + +static void CCTSetPos(CCTComponent& comp, const glm::vec3& pos) { + PxExtendedVec3 pos_px(pos.x, pos.y, pos.z); + comp.cct->setFootPosition(pos_px); +} + +static glm::vec3 CCTGetPos(CCTComponent& comp) { + auto pos_px = comp.cct->getFootPosition(); + return glm::vec3(pos_px.x, pos_px.y, pos_px.z); +} + +static bool CCTTurnToAngle(CCTComponent& comp, float target, float step) { + if (target < comp.angle) + target += glm::two_pi(); + + auto diff_angle = target - comp.angle; + if (diff_angle > glm::pi()) + diff_angle -= glm::two_pi(); + + if (glm::abs(diff_angle) <= step) { + comp.angle = target; + return true; + } + else { + comp.angle += glm::sign(diff_angle) * step; + comp.angle = glm::mod(comp.angle, glm::two_pi()); + return false; + } +} + +static bool CCTTurnTo(CCTComponent& comp, const glm::vec3& pos, float step) { + auto diff = pos - CCTGetPos(comp); + auto target = std::atan2(pos.x, pos.z); + + return CCTTurnToAngle(comp, target, step); +} + +// component +CCTComponent::CCTComponent(float radius, float height, const glm::vec3& pos) : + angle(0.0f) +{ + PxCapsuleControllerDesc desc; + + auto material = AssetMap::Get("physics/default.material.json"); + + desc.position = PxExtendedVec3(pos.x, pos.y, pos.z); + desc.radius = radius; + desc.height = height; + desc.material = material->Get(); + desc.scaleCoeff = 1.0f; + desc.contactOffset = 0.05f; + desc.slopeLimit = glm::cos(glm::radians(70.0f)); + desc.stepOffset = 0.3f; + //desc. + + desc.climbingMode = PxCapsuleClimbingMode::eCONSTRAINED; + desc.nonWalkableMode = PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING; + + Game::Physics().GetCCTManager()->setOverlapRecoveryModule(true); + + cct = Game::Physics().GetCCTManager()->createController(desc); + if (!cct) + Throw("(CCT) createController failed!"); + +} + +CCTComponent::~CCTComponent() { + cct->release(); +} + +// CCT SYSTEM + +void CCTSystem::AddCCT(entt::entity ent, float radius, float height) { + auto& reg = Game::Registry(); + const auto& trans = reg.get(ent); + auto& comp = reg.emplace_or_replace(ent, radius, height, trans.trans.pos); +} + +void CCTSystem::RemoveCCT(entt::entity ent) { + auto& reg = Game::Registry(); + reg.erase(ent); +} + +int CCTSystem::Move(entt::entity ent, const glm::vec3& disp, float dt) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + return CCTMove(comp, disp, dt); +} + +void CCTSystem::SetPos(entt::entity ent, const glm::vec3& pos) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + CCTSetPos(comp, pos); +} + +glm::vec3 TSR::CCTSystem::GetPos(entt::entity ent) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + return CCTGetPos(comp); +} + +bool CCTSystem::TurnTo(entt::entity ent, const glm::vec3& pos, float step) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + + return CCTTurnTo(comp, pos, step); +} + +bool TSR::CCTSystem::TurnToAngle(entt::entity ent, float target, float step) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + + return CCTTurnToAngle(comp, target, step); +} + +void CCTSystem::Update() { + auto& reg = Game::Registry(); + + auto v = reg.view(); + for (auto [ent, cct, trans] : v.each()) { + auto pos = cct.cct->getFootPosition(); + trans.trans.pos = glm::vec3(pos.x, pos.y, pos.z); + trans.trans.rot = glm::quat(glm::vec3(0.0f, cct.angle, 0.0f)); + } + +} diff --git a/src/tsr/entity_cct.hpp b/src/tsr/entity_cct.hpp new file mode 100644 index 0000000..5fecb3f --- /dev/null +++ b/src/tsr/entity_cct.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "entity.hpp" + +namespace TSR { + + enum { + CCT_COLLISION_NONE = 0, + CCT_COLLISION_DOWN = 1 << 0, + CCT_COLLISION_UP = 1 << 1, + CCT_COLLISION_SIDE = 1 << 2, + }; + + struct CCTComponent { + PxController* cct; + float angle; + + CCTComponent(float radius, float height, const glm::vec3& pos); + CCTComponent(const CCTComponent& other) = delete; + ~CCTComponent(); + }; + + class CCTSystem { + + public: + static void AddCCT(entt::entity ent, float radius, float height); + static void RemoveCCT(entt::entity ent); + static int Move(entt::entity ent, const glm::vec3& disp, float dt); + static void SetPos(entt::entity ent, const glm::vec3& pos); + static glm::vec3 GetPos(entt::entity ent); + static bool TurnTo(entt::entity ent, const glm::vec3& pos, float step); + static bool TurnToAngle(entt::entity ent, float target, float step); + + static void Update(); + + }; +} \ No newline at end of file diff --git a/src/tsr/entity_model.cpp b/src/tsr/entity_model.cpp index a622a9b..4b5e67a 100644 --- a/src/tsr/entity_model.cpp +++ b/src/tsr/entity_model.cpp @@ -212,6 +212,9 @@ void ModelSystem::Render(TSR::Renderer& renderer) { CreateTransMatFast(model.ctx.model_matrix, MixTransforms(trans1, trans2, frame_t)); + // temp + renderer.AddDebugLine(model.ctx.model_matrix[3], model.ctx.model_matrix[3] + glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + if (model.model->IsSkeletal() && !Window::KeyDown(GLFW_KEY_V)) { auto& sk_bones = model.model->GetSkeleton().Bones(); diff --git a/src/tsr/entity_model.hpp b/src/tsr/entity_model.hpp index 3186d94..5269543 100644 --- a/src/tsr/entity_model.hpp +++ b/src/tsr/entity_model.hpp @@ -3,7 +3,7 @@ #include "model.hpp" #include #include -#include "../tsr/renderer.hpp" +#include "renderer.hpp" namespace TSR { diff --git a/src/tsr/game.cpp b/src/tsr/game.cpp index a6e9531..0d2b001 100644 --- a/src/tsr/game.cpp +++ b/src/tsr/game.cpp @@ -1,21 +1,44 @@ #include "game.hpp" #include "entity_model.hpp" +#include "entity_cct.hpp" #include "window.hpp" #include "camera.hpp" #include "worldmap.hpp" +#include "physics.hpp" using namespace TSR; entt::registry Game::s_registry; +std::unique_ptr Game::s_physics_scene; +std::unique_ptr Game::s_map; + uint64_t Game::s_sv_frame = 0; float Game::s_frame_t = 0.0f; int Game::s_tps = 50; +bool Game::s_debug_draw = false; + static Camera cam; static entt::entity ent1; +static entt::entity player; -static WorldMap* s_map; +void Game::StartGame(const std::string& map_name) { + s_sv_frame = 0; + s_frame_t = 0.0f; + + s_registry.clear(); + + s_physics_scene = std::make_unique(); + s_map = std::make_unique(map_name, s_physics_scene.get()); + +} + +void Game::EndGame() { + s_registry.clear(); + s_map.reset(); + s_physics_scene.reset(); +} void Game::Run() { @@ -23,14 +46,17 @@ void Game::Run() { WindowWrapper ww("TSR test", 640, 480); ////Audio::Init(); + Physics::Init(); + Renderer renderer; - WorldMap map("maps/kalbatest1.mapproject.json"); + StartGame("maps/kalbatest1.mapproject.json"); - while (!map.Loaded()) - map.LoadNext(); + while (!s_map->Loaded()) + s_map->LoadNext(); - s_map = ↦ + + //s_physics_scene->EnableDebug(false); for (int i = 0; i < 20; ++i) { auto ent = Game::Registry().create(); @@ -47,16 +73,35 @@ void Game::Run() { } - ent1 = Game::Registry().create(); - ModelSystem::AddModel(ent1, "models/skrin.mdl.json"); - ModelSystem::Anim(ent1, "init"); - ModelSystem::Anim(ent1, "open_left"); - ModelSystem::Anim(ent1, "open_right"); - auto& trans = Registry().emplace_or_replace(ent1); - glm::vec3 pos(0.0f, 5.0f, 0.0f); - trans.trans.pos = pos; - trans.trans.rot = glm::quat(glm::vec3(0.0f)); - trans.trans.scl = glm::vec3(1.0f); + { + ent1 = Game::Registry().create(); + ModelSystem::AddModel(ent1, "models/skrin.mdl.json"); + ModelSystem::Anim(ent1, "init"); + ModelSystem::Anim(ent1, "open_left"); + ModelSystem::Anim(ent1, "open_right"); + auto& trans = Registry().emplace_or_replace(ent1); + glm::vec3 pos(0.0f, 5.0f, 0.0f); + trans.trans.pos = pos; + trans.trans.rot = glm::quat(glm::vec3(0.0f)); + trans.trans.scl = glm::vec3(1.0f); + } + + { + player = Game::Registry().create(); + ModelSystem::AddModel(player, "models/test_skeletal.mdl.json"); + ModelSystem::Anim(player, "init"); + ModelSystem::Anim(player, "ruce"); + auto& trans = Registry().emplace_or_replace(player); + glm::vec3 pos(0.0f, 5.0f, 0.0f); + trans.trans.pos = pos; + trans.trans.rot = glm::quat(glm::vec3(0.0f)); + trans.trans.scl = glm::vec3(1.0f); + + CCTSystem::AddCCT(player, 0.25f, 1.2f); + + } + + cam.third_person_distance = 5.0f; Window::SetInputMode(GLFW_CURSOR, GLFW_CURSOR_DISABLED); Window::SetCursorPosCallback([](GLFWwindow* window, double xpos, double ypos) { @@ -76,6 +121,12 @@ void Game::Run() { Window::SetKeyCallback([](GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) { switch (key) { + case GLFW_KEY_F1: + s_debug_draw = !s_debug_draw; + s_physics_scene->EnableDebug(s_debug_draw); + break; + + case GLFW_KEY_E: ModelSystem::Anim(ent1, "open_left"); ModelSystem::Anim(ent1, "open_right"); @@ -122,41 +173,75 @@ void Game::Run() { ClFrame(renderer, 0.0f); } + + EndGame(); + Physics::Close(); } void Game::SvFrame() { - ModelSystem::Animate(); - ++s_sv_frame; - float time = 1.0f / (float)s_tps; + //if (Window::KeyDown(GLFW_KEY_W)) + // cam.ProcessMovement(Camera::Movement::FORWARD, time); + //if (Window::KeyDown(GLFW_KEY_S)) + // cam.ProcessMovement(Camera::Movement::BACKWARD, time); + //if (Window::KeyDown(GLFW_KEY_A)) + // cam.ProcessMovement(Camera::Movement::LEFT, time); + //if (Window::KeyDown(GLFW_KEY_D)) + // cam.ProcessMovement(Camera::Movement::RIGHT, time); + //if (Window::KeyDown(GLFW_KEY_SPACE)) + // cam.ProcessMovement(Camera::Movement::UP, time); + //if (Window::KeyDown(GLFW_KEY_LEFT_SHIFT)) + // cam.ProcessMovement(Camera::Movement::DOWN, time); + + float move_forward = 0.0f; + float move_right = 0.0f; + if (Window::KeyDown(GLFW_KEY_W)) - cam.ProcessMovement(Camera::Movement::FORWARD, time); + move_forward += 1.0f; if (Window::KeyDown(GLFW_KEY_S)) - cam.ProcessMovement(Camera::Movement::BACKWARD, time); + move_forward -= 1.0f; if (Window::KeyDown(GLFW_KEY_A)) - cam.ProcessMovement(Camera::Movement::LEFT, time); + move_right -= 1.0f; if (Window::KeyDown(GLFW_KEY_D)) - cam.ProcessMovement(Camera::Movement::RIGHT, time); - if (Window::KeyDown(GLFW_KEY_SPACE)) - cam.ProcessMovement(Camera::Movement::UP, time); - if (Window::KeyDown(GLFW_KEY_LEFT_SHIFT)) - cam.ProcessMovement(Camera::Movement::DOWN, time); + move_right += 1.0f; + + if (move_forward != 0.0f || move_right != 0.0f) { + auto move_vector = cam.forward_backward_vector * move_forward + cam.right_vector * move_right; + + auto move_angle = std::atan2(move_vector.x, move_vector.z); + + CCTSystem::TurnToAngle(player, move_angle, 6.0f / TPS()); + + auto& cctcomp = Registry().get(player); + + glm::vec3 forward_vector(std::sin(cctcomp.angle), -1.0f, std::cos(cctcomp.angle)); + CCTSystem::Move(player, forward_vector * (5.0f / TPS()), time); + } + + CCTSystem::Update(); + ModelSystem::Animate(); + + s_physics_scene->StepSimulation(time); + + ++s_sv_frame; } void Game::ClFrame(Renderer& renderer, float frame_t) { - - - int w, h; Window::GetFramebufferSize(w, h); + renderer.SetProjection((float)w / (float)h, 90.0f, 0.1f, 1000.0f); - //r.SetViewMatrix(glm::lookAt(glm::vec3(-1.0f, 2.0f, 2.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f))); - renderer.SetViewMatrix(cam.GetViewMatrix()); - //r.SetViewMatrix(glm::lookAt(glm::vec3(10.0f, 5.0f, 3.0f), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f))); ModelSystem::Render(renderer); s_map->Draw(renderer); + + if (s_debug_draw) + s_physics_scene->DrawDebug(renderer); + + cam.position = glm::vec3(Registry().get(player).ctx.model_matrix[3]) + glm::vec3(0.0f, 1.0f, 0.0f); + renderer.SetViewMatrix(cam.GetViewMatrix()); + renderer.Render(w, h); Window::PollEvents(); diff --git a/src/tsr/game.hpp b/src/tsr/game.hpp index 670829c..df59f45 100644 --- a/src/tsr/game.hpp +++ b/src/tsr/game.hpp @@ -6,25 +6,40 @@ #include #include #include "renderer.hpp" +#include "worldmap.hpp" +#include "physics.hpp" namespace TSR { - class Game { + static entt::registry s_registry; + static std::unique_ptr s_map; + static std::unique_ptr s_physics_scene; + static uint64_t s_sv_frame; static float s_frame_t; static int s_tps; + static bool s_debug_draw; + + static void StartGame(const std::string& map_name); + static void EndGame(); + public: + + static void Run(); static void SvFrame(); static void ClFrame(Renderer& renderer, float frame_t); static entt::registry& Registry() { return s_registry; } + static PhysicsScene& Physics() { return *s_physics_scene; } static uint64_t FrameNum() { return s_sv_frame; } static float FrameT() { return s_frame_t; } static int TPS() { return s_tps; } + + }; struct TransformComponent { diff --git a/src/tsr/ia.cpp b/src/tsr/ia.cpp index 0d45a02..a140ca3 100644 --- a/src/tsr/ia.cpp +++ b/src/tsr/ia.cpp @@ -50,7 +50,7 @@ public: }; -IAData TSR::ParseIA(const std::string& str, std::vector& bone_list) { +IAData TSR::ParseIA(const std::string& str, std::vector* bone_list) { IAData data; ReadStream rs(str.data(), str.length()); @@ -77,14 +77,14 @@ IAData TSR::ParseIA(const std::string& str, std::vector& bone_list) { // skip reserved header rs.Seek(16); - if (data.is_skeletal) { + if (data.is_skeletal && bone_list) { auto num_bones = rs.Read(); if (num_bones >= TSR_MAX_BONES) throw ParseException("Max bones exceeded"); - bone_list.resize(num_bones); + bone_list->resize(num_bones); - for (auto& bone : bone_list) { + for (auto& bone : *bone_list) { bone.name = rs.ReadStr(); bone.offset = rs.Read(); } diff --git a/src/tsr/ia.hpp b/src/tsr/ia.hpp index 5353a54..e1c22cb 100644 --- a/src/tsr/ia.hpp +++ b/src/tsr/ia.hpp @@ -47,7 +47,7 @@ namespace TSR { bool is_skeletal; }; - IAData ParseIA(const std::string& str, std::vector& bone_list); + IAData ParseIA(const std::string& str, std::vector* bone_list = nullptr); void ParseSK(const std::string& str, std::vector& bone_list); void ParseSKAN(const std::string& str, std::vector& chan_list, size_t& duration, float& tps); } diff --git a/src/tsr/model.cpp b/src/tsr/model.cpp index e97436c..2589cc5 100644 --- a/src/tsr/model.cpp +++ b/src/tsr/model.cpp @@ -21,7 +21,11 @@ SkAnim::SkAnim(const std::string& name) { ParseSKAN(skan_str, m_channels, m_duration, m_tps); } -Model::Model(const std::string& name) { +Model::Model(const std::string& name) : + m_shape(SHAPE_NONE), + m_shape_offset(0.0f), + m_shape_size(0.0f) +{ auto model_str = Filesystem::Read(name); @@ -104,6 +108,7 @@ Model::Model(const std::string& name) { m_part_names.insert({ part_json.at("name").get(), m_parts.size() - 1 }); } + // ANIMATIONS if (model_json.contains("animations")) { const auto& anims_json = model_json.at("animations"); for (const auto& anim_json : anims_json) { @@ -133,6 +138,28 @@ Model::Model(const std::string& name) { // events } } + + // SHAPE + if (model_json.contains("shape")) { + const auto& shape_json = model_json.at("shape"); + + if (shape_json.is_string()) { + m_shape = SHAPE_TRIANGLE_MESH; + m_trimesh = AssetMap::Get(shape_json.get()); + } + else { + std::string shape_type("none"); + + if (shape_json.contains("type")) + shape_json.at("type").get_to(shape_type); + + if (shape_type == "box") { + m_shape = SHAPE_BOX; + m_shape_offset = JsonGetVec<3>(shape_json.at("offset")); + m_shape_size = JsonGetVec<3>(shape_json.at("size")); + } + } + } } catch (nlohmann::json::exception ex) { Throw(ex.what()); diff --git a/src/tsr/model.hpp b/src/tsr/model.hpp index d4eae24..996c97d 100644 --- a/src/tsr/model.hpp +++ b/src/tsr/model.hpp @@ -1,6 +1,7 @@ #pragma once #include "assets.hpp" #include "renderer.hpp" +#include "physics.hpp" namespace TSR { @@ -38,6 +39,13 @@ namespace TSR { typedef int AnimationId; typedef int PartId; + enum ModelShape { + SHAPE_NONE, + SHAPE_TRIANGLE_MESH, + SHAPE_BOX, + SHAPE_COUNT + }; + class Model : public Asset { AssetPtr m_skeleton; @@ -47,6 +55,11 @@ namespace TSR { std::vector m_animations; std::map m_anim_names; + ModelShape m_shape; + AssetPtr m_trimesh; + glm::vec3 m_shape_offset; + glm::vec3 m_shape_size; + public: Model(const std::string& name); @@ -68,6 +81,11 @@ namespace TSR { const Animation& GetAnim(int id) { return m_animations[id]; } bool IsSkeletal() const { return m_skeleton.get() != nullptr; } bool HasAnimations() const { return m_animations.size() > 0; } + ModelShape Shape() const { return m_shape; } + const glm::vec3& ShapeOffset() const { return m_shape_offset; } + const glm::vec3& ShapeSize() const { return m_shape_size; } + const PhysicsTriangleMesh& TriMesh() const { return *m_trimesh; } + }; } \ No newline at end of file diff --git a/src/tsr/physics.cpp b/src/tsr/physics.cpp new file mode 100644 index 0000000..6509e07 --- /dev/null +++ b/src/tsr/physics.cpp @@ -0,0 +1,187 @@ +#include "physics.hpp" +#include "filesystem.hpp" +#include "ia.hpp" +#include + +using namespace TSR; +using namespace nlohmann; + +PxDefaultErrorCallback Physics::s_default_error_cb; +PxDefaultAllocator Physics::s_default_allocator_cb; + +PxFoundation* Physics::s_foundation = nullptr; +PxPhysics* Physics::s_physics = nullptr; +PxCooking* Physics::s_cooking = nullptr; +PxPvd* Physics::s_pvd = nullptr; + +void Physics::Init() { + // PHYSX init + static PxDefaultErrorCallback gDefaultErrorCallback; + static PxDefaultAllocator gDefaultAllocatorCallback; + + s_foundation = PxCreateFoundation(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback); + if (!s_foundation) + Throw("(PX) PxCreateFoundation failed!"); + + bool recordMemoryAllocations = true; + + auto mPvd = PxCreatePvd(*s_foundation); + PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("localhost", 5425, 10); + mPvd->connect(*transport, PxPvdInstrumentationFlag::eALL); + + PxTolerancesScale scale; + + s_physics = PxCreatePhysics(PX_PHYSICS_VERSION, *s_foundation, scale, recordMemoryAllocations, mPvd); + if (!s_physics) + Throw("(PX) PxCreatePhysics failed!"); + + s_cooking = PxCreateCooking(PX_PHYSICS_VERSION, *s_foundation, PxCookingParams(scale)); + if (!s_cooking) + Throw("(PX) PxCreateCooking failed!"); + + PxCookingParams params(scale); + s_cooking->setParams(params); +} + +void Physics::Close() { + s_cooking->release(); + s_physics->release(); + s_foundation->release(); +} + +PhysicsScene::PhysicsScene() { + PxSceneDesc sceneDesc(Physics::GetPhysics()->getTolerancesScale()); + sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); + // create CPU dispatcher which mNbThreads worker threads + m_cpu_dispatcher = PxDefaultCpuDispatcherCreate(1); + if (!m_cpu_dispatcher) + Throw("(PX) PxDefaultCpuDispatcherCreate failed!"); + + sceneDesc.cpuDispatcher = m_cpu_dispatcher; + + if (!sceneDesc.filterShader) + sceneDesc.filterShader = &PxDefaultSimulationFilterShader; + + m_scene = Physics::GetPhysics()->createScene(sceneDesc); + if (!m_scene) + Throw("(PX) createScene failed!"); + + m_cct_manager = PxCreateControllerManager(*m_scene); + if (!m_cct_manager) + Throw("(PX) PxCreateControllerManager failed!"); + + m_scene->userData = this; +} + +PhysicsScene::~PhysicsScene() { + m_cct_manager->release(); + m_scene->release(); +} + +void PhysicsScene::StepSimulation(float time) { + m_scene->simulate(time); + m_scene->fetchResults(true); +} + +void PhysicsScene::EnableDebug(bool enable) { + m_scene->setVisualizationParameter(PxVisualizationParameter::eSCALE, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eACTOR_AXES, enable ? 2.0f : 0.0f); + ////m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_EDGES, enable ? 1.0f : 0.0f); + ////m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_COMPOUNDS, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_AABBS, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eMBP_REGIONS, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eACTOR_AXES, enable ? 0.5f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eBODY_ANG_VELOCITY, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eBODY_AXES, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eBODY_LIN_VELOCITY, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eBODY_MASS_AXES, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_AABBS, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_AXES, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_COMPOUNDS, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_DYNAMIC, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_EDGES, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_FNORMALS, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_STATIC, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCONTACT_ERROR, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCONTACT_FORCE, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCONTACT_NORMAL, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eCONTACT_POINT, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eCULL_BOX, enable ? 1.0f : 0.0f); + //m_scene->setVisualizationParameter(PxVisualizationParameter::eFORCE_DWORD, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eJOINT_LIMITS, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eJOINT_LOCAL_FRAMES, enable ? 1.0f : 0.0f); + m_scene->setVisualizationParameter(PxVisualizationParameter::eWORLD_AXES, enable ? 1.0f : 0.0f); + +} + +static glm::vec4 U32ColorToVec4(uint32_t rgba_value) { + float red = static_cast((rgba_value >> 24) & 0xFF) / 255.0f; + float green = static_cast((rgba_value >> 16) & 0xFF) / 255.0f; + float blue = static_cast((rgba_value >> 8) & 0xFF) / 255.0f; + float alpha = static_cast(rgba_value & 0xFF) / 255.0f; + + return glm::vec4(red, green, blue, alpha); +} + +void PhysicsScene::DrawDebug(Renderer& renderer) { + const PxRenderBuffer& rb = m_scene->getRenderBuffer(); + for (PxU32 i = 0; i < rb.getNbLines(); i++) { + const PxDebugLine& line = rb.getLines()[i]; + + glm::vec3 pos1(line.pos0.x, line.pos0.y, line.pos0.z); + glm::vec3 pos2(line.pos1.x, line.pos1.y, line.pos1.z); + glm::vec3 color1 = U32ColorToVec4(line.color0); + glm::vec3 color2 = U32ColorToVec4(line.color1); + + renderer.AddDebugLine(pos1, pos2, color1, color2); + } +} + +PhysicsMaterial::PhysicsMaterial(const std::string& path) { + float static_friction, dynamic_friction, restitution; + try { + auto j_material = json::parse(Filesystem::Read(path)); + + j_material.at("static_friction").get_to(static_friction); + j_material.at("dynamic_friction").get_to(dynamic_friction); + j_material.at("restitution").get_to(restitution); + } + catch (json::exception ex) { + Throw(ex.what()); + } + + m_material = Physics::GetPhysics()->createMaterial(static_friction, dynamic_friction, restitution); + m_material->userData = this; +} + +PhysicsMaterial::~PhysicsMaterial() { + m_material->release(); +} + +PhysicsTriangleMesh::PhysicsTriangleMesh(const std::string& path) { + auto ia_str = Filesystem::Read(path); + + auto mia3 = ParseIA(ia_str); + + PxTriangleMeshDesc mesh_desc; + mesh_desc.points.count = mia3.num_vertices; + mesh_desc.points.stride = sizeof(PxVec3); + mesh_desc.points.data = mia3.vertices_ptr; + + mesh_desc.triangles.count = mia3.num_indices / 3; + mesh_desc.triangles.stride = 3 * sizeof(PxU32); + mesh_desc.triangles.data = mia3.indices_ptr; + +#ifdef _DEBUG + // mesh should be validated before cooked without the mesh cleaning + bool res = Physics::GetCooking()->validateTriangleMesh(mesh_desc); + PX_ASSERT(res); +#endif + + m_mesh = Physics::GetCooking()->createTriangleMesh(mesh_desc, Physics::GetPhysics()->getPhysicsInsertionCallback()); +} + +PhysicsTriangleMesh::~PhysicsTriangleMesh() { + m_mesh->release(); +} diff --git a/src/tsr/physics.hpp b/src/tsr/physics.hpp new file mode 100644 index 0000000..53ce22e --- /dev/null +++ b/src/tsr/physics.hpp @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include +#include +#include +#include "tsr.hpp" +#include "assets.hpp" +#include "renderer.hpp" + +namespace TSR { + using namespace physx; + + class Physics { + + static PxDefaultErrorCallback s_default_error_cb; + static PxDefaultAllocator s_default_allocator_cb; + + static PxFoundation* s_foundation; + static PxPhysics* s_physics; + static PxCooking* s_cooking; + static PxPvd* s_pvd; + public: + static void Init(); + static void Close(); + + static PxPhysics* GetPhysics() { return s_physics; } + static PxCooking* GetCooking() { return s_cooking; } + }; + + class PhysicsScene { + PxDefaultCpuDispatcher* m_cpu_dispatcher; + PxScene* m_scene; + PxControllerManager* m_cct_manager; + + public: + PhysicsScene(); + ~PhysicsScene(); + + PxScene* GetScene() { return m_scene; } + PxControllerManager* GetCCTManager() { return m_cct_manager; } + + void StepSimulation(float time); + + void EnableDebug(bool enable); + void DrawDebug(Renderer& renderer); + }; + + class PhysicsMaterial : public Asset { + PxMaterial* m_material; + + public: + PhysicsMaterial(const std::string& path); + ~PhysicsMaterial(); + + PxMaterial* Get() const { return m_material; } + }; + + class PhysicsTriangleMesh : public Asset { + PxTriangleMesh* m_mesh; + + public: + PhysicsTriangleMesh(const std::string& path); + ~PhysicsTriangleMesh(); + + PxTriangleMesh* Get() const { return m_mesh; } + }; + +} \ No newline at end of file diff --git a/src/tsr/renderer.cpp b/src/tsr/renderer.cpp index bdc8a34..58ed642 100644 --- a/src/tsr/renderer.cpp +++ b/src/tsr/renderer.cpp @@ -141,7 +141,7 @@ static inline void SetAttribPointers(Size... sizes) { Mesh::Mesh(const std::string& name) { auto file_str = Filesystem::Read(name); - auto ia = ParseIA(file_str, m_bones); + auto ia = ParseIA(file_str, &m_bones); glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); @@ -181,6 +181,31 @@ Mesh::~Mesh() { glDeleteVertexArrays(1, &m_vao); } +DebugVAO::DebugVAO() { + glGenVertexArrays(1, &m_vao); + glBindVertexArray(m_vao); + + glGenBuffers(1, &m_vbo); // Generate 1 buffer + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 2, NULL, GL_STREAM_DRAW); + + SetAttribPointers(3, 3); + + glBindVertexArray(0); +} + +void DebugVAO::Draw(std::vector& vertices, bool lines) { + glBindVertexArray(m_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(DebugVertex) * vertices.size(), &vertices[0], GL_STREAM_DRAW); + glDrawArrays(lines ? GL_LINES : GL_POINTS, 0, vertices.size()); +} + +DebugVAO::~DebugVAO() { + glDeleteBuffers(1, &m_vbo); + glDeleteVertexArrays(1, &m_vao); +} + InstancedSSBO::InstancedSSBO(const std::vector& data) : m_size(data.size()) { glBindVertexArray(0); @@ -319,6 +344,7 @@ Renderer::Renderer() : m_shader_xz(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/xz.fs"), "XZ"), m_shader_xz_xz_mask_uv(Filesystem::Read("shaders/basic.vs"), Filesystem::Read("shaders/xz_xz_mask_uv.fs"), "XZ_XZ_MASK_UV"), m_shader_skeletal(Filesystem::Read("shaders/skeletal.vs"), Filesystem::Read("shaders/skeletal.fs"), "SKELETAL"), + m_shader_debug(Filesystem::Read("shaders/debug.vs"), Filesystem::Read("shaders/debug.fs"), "DEBUG"), m_proj_matrix(1.0f), m_view_matrix(1.0f), m_viewport_buf(AssetMap::Get("viewport.ia2")), @@ -541,18 +567,27 @@ void Renderer::Render(int width, int height) { } + // DEBUG + glDisable(GL_DEPTH_TEST); + if (!m_debug_lines.empty()) { + glStencilFunc(GL_ALWAYS, 0, 0xFF); + m_shader_debug.Use(); + glUniformMatrix4fv(m_shader_debug.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp)); + + m_debug_vao.Draw(m_debug_lines, true); + } + //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //glStencilFunc(GL_EQUAL, 0, 0xFF); //glStencilMask(0x00); // draw skybox + glDisable(GL_CULL_FACE); + glDisable(GL_STENCIL_TEST); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_STENCIL_TEST); m_shader_screen.Use(); @@ -582,4 +617,6 @@ void Renderer::Render(int width, int height) { for (int i = 0; i < RT_COUNT; ++i) m_draw_lists[i].clear(); + + m_debug_lines.clear(); } diff --git a/src/tsr/renderer.hpp b/src/tsr/renderer.hpp index cbb7147..26cc1df 100644 --- a/src/tsr/renderer.hpp +++ b/src/tsr/renderer.hpp @@ -74,6 +74,24 @@ namespace TSR { } }; + struct DebugVertex { + glm::vec3 pos; + glm::vec3 color; + }; + + class DebugVAO { + GLuint m_vao; + GLuint m_vbo; + + public: + DebugVAO(); + DebugVAO(const DebugVAO&) = delete; + DebugVAO(DebugVAO&&) = delete; + ~DebugVAO(); + + void Draw(std::vector& vertices, bool lines); + }; + struct Drawable { RenderType type; @@ -268,6 +286,7 @@ namespace TSR { static RenderType s_rt_instanced_map[RT_COUNT]; std::vector m_draw_lists[RT_COUNT]; + std::vector m_debug_lines; Shader m_shader_basic; Shader m_shader_basic_instanced; @@ -277,10 +296,12 @@ namespace TSR { Shader m_shader_xz_xz_mask_uv; Shader m_shader_screen; Shader m_shader_skeletal; + Shader m_shader_debug; //float m_aspect_ratio; std::unique_ptr m_fbs; std::shared_ptr m_viewport_buf; + DebugVAO m_debug_vao; int m_last_width, m_last_height; @@ -300,6 +321,11 @@ namespace TSR { m_draw_lists[s_rt_instanced_map[draw_ref.drawable->type]].push_back(draw_ref); } + void AddDebugLine(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& color1 = glm::vec3(1.0f), const glm::vec3& color2 = glm::vec3(1.0f)) { + m_debug_lines.push_back({ p1, color1 }); + m_debug_lines.push_back({ p2, color2 }); + } + void SetViewMatrix(const glm::mat4& view_matrix) { m_view_matrix = view_matrix; } diff --git a/src/tsr/worldmap.cpp b/src/tsr/worldmap.cpp index ad952e9..f6d998c 100644 --- a/src/tsr/worldmap.cpp +++ b/src/tsr/worldmap.cpp @@ -1,10 +1,16 @@ #include "worldmap.hpp" +#include using namespace TSR; static const char* color_strs[] = { "color1", "color2", "color3", "color4" }; -WorldMap::WorldMap(const std::string& map_path) : m_loading_phase(LoadingPhase::FIRST), m_map_path(map_path), m_loaded_models(0) {} +WorldMap::WorldMap(const std::string& map_path, PhysicsScene* physics_scene) : + m_loading_phase(LoadingPhase::FIRST), + m_map_path(map_path), + m_loaded_models(0), + m_physics_scene(physics_scene) +{} int WorldMap::LoadNext() { switch (m_loading_phase) { @@ -40,7 +46,11 @@ int WorldMap::LoadNext() { if (j_object.contains("scale")) j_object.at("scale").get_to(scale); - ctx.model_matrix = glm::scale(glm::rotate(glm::translate(glm::mat4(1.0f), pos), glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f)), glm::vec3(scale)); + PhysicalObject phyobj; + ctx.model_matrix = glm::rotate(glm::translate(glm::mat4(1.0f), pos), glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f)); + phyobj.m_transform = PxTransform(PxMat44(glm::value_ptr(ctx.model_matrix))); + ctx.model_matrix = glm::scale(ctx.model_matrix, glm::vec3(scale)); + phyobj.m_scale = scale; for (int i = 0; i < 4; ++i) { auto& cns = color_strs[i]; @@ -49,7 +59,7 @@ int WorldMap::LoadNext() { } model_instances.m_contexts.push_back(ctx); - + model_instances.m_physical_objects.push_back(phyobj); } m_loading_iter = m_loading_obj_data.cbegin(); @@ -93,6 +103,40 @@ int WorldMap::LoadNext() { } } + + if (s->Shape() == SHAPE_TRIANGLE_MESH) { + auto material = AssetMap::Get("physics/default.material.json"); + auto& shape = s->TriMesh(); + + for (const auto& phyobj : models.second.m_physical_objects) { + PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(phyobj.m_transform); + PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(shape.Get(), PxMeshScale(phyobj.m_scale)), *material->Get()); + + m_physics_scene->GetScene()->addActor(*actor); + + //actor->release(); + } + + } + else if (s->Shape() == SHAPE_BOX) { + auto material = AssetMap::Get("physics/default.material.json"); + + for (const auto& phyobj : models.second.m_physical_objects) { + auto transform = phyobj.m_transform; + auto size = s->ShapeSize(); + auto offset = s->ShapeOffset(); + transform.p = transform.p + PxVec3(offset.x * phyobj.m_scale, offset.y * phyobj.m_scale, offset.z * phyobj.m_scale); + + PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(transform); + + PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxBoxGeometry(size.x * phyobj.m_scale, size.y * phyobj.m_scale, size.z * phyobj.m_scale), *material->Get()); + m_physics_scene->GetScene()->addActor(*actor); + + } + + } + + return 10 + (90 * m_loaded_models / m_loading_obj_data.size()); break; diff --git a/src/tsr/worldmap.hpp b/src/tsr/worldmap.hpp index 017e17a..a7a0af9 100644 --- a/src/tsr/worldmap.hpp +++ b/src/tsr/worldmap.hpp @@ -4,12 +4,14 @@ //#include "audio.hpp" #include "window.hpp" #include "tsr.hpp" +#include "physics.hpp" namespace TSR { class WorldMap { // general std::string m_map_path; + PhysicsScene* m_physics_scene; // loading enum class LoadingPhase { @@ -19,8 +21,14 @@ namespace TSR { FINISHED, } m_loading_phase; + struct PhysicalObject { + PxTransform m_transform; + float m_scale; + }; + struct ModelInstances { std::vector m_contexts; + std::vector m_physical_objects; }; using LoadingObjData = std::map; @@ -39,7 +47,7 @@ namespace TSR { std::vector m_objects_instanced; public: - WorldMap(const std::string& map_path); + WorldMap(const std::string& map_path, PhysicsScene* physics_scene); bool Loaded() const { return m_loading_phase == LoadingPhase::FINISHED; } const std::string& Name() { return m_map_path; } diff --git a/tsrecs.vcxproj b/tsrecs.vcxproj index 4e3fe83..d8529d3 100644 --- a/tsrecs.vcxproj +++ b/tsrecs.vcxproj @@ -129,6 +129,8 @@ + + @@ -142,6 +144,8 @@ + + diff --git a/tsrecs.vcxproj.filters b/tsrecs.vcxproj.filters index e005b41..65ca523 100644 --- a/tsrecs.vcxproj.filters +++ b/tsrecs.vcxproj.filters @@ -48,6 +48,12 @@ Source Files + + Source Files + + + Source Files + @@ -89,5 +95,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file