From 7577e86ec70e46bf1860dd77a22f5ff3618c3149 Mon Sep 17 00:00:00 2001 From: Hongyu Wei <102242553+hyv1001@users.noreply.github.com> Date: Mon, 30 May 2022 20:41:31 +0800 Subject: [PATCH] Integrate Jolt Physics Engine (#215) Integrate Jolt Physics Engine, - RigidBody creation and destroy (only support static object currently) - Scene Query: raycast, sweep, overlap - Simulation - Physics Debug Renderer: (work in progress) Co-authored-by: Olorin --- engine/3rdparty/CMakeLists.txt | 29 ++ engine/CMakeLists.txt | 10 + .../environment/floor/floor.object.json | 36 ++ engine/source/runtime/CMakeLists.txt | 6 + engine/source/runtime/engine.cpp | 6 + .../controller/character_controller.cpp | 10 +- .../rigidbody/rigidbody_component.cpp | 24 +- .../function/framework/level/level.cpp | 17 +- .../runtime/function/framework/level/level.h | 5 + .../framework/world/world_manager.cpp | 20 +- .../function/framework/world/world_manager.h | 3 + .../function/global/global_context.cpp | 10 +- .../runtime/function/global/global_context.h | 22 +- .../runtime/function/physics/jolt/utils.cpp | 157 +++++++++ .../runtime/function/physics/jolt/utils.h | 89 +++++ .../function/physics/physics_aabb_shape.h | 2 +- .../runtime/function/physics/physics_actor.h | 5 + .../runtime/function/physics/physics_config.h | 27 ++ .../function/physics/physics_manager.cpp | 115 +++++++ .../function/physics/physics_manager.h | 45 +++ .../function/physics/physics_obb_shape.h | 2 +- .../function/physics/physics_scene.cpp | 315 ++++++++++++++++++ .../runtime/function/physics/physics_scene.h | 91 +++++ .../function/physics/physics_shape_base.h | 6 +- .../function/physics/physics_sphere_shape.h | 2 +- .../runtime/function/physics/physics_system.h | 1 + .../runtime/function/render/render_system.cpp | 9 + .../runtime/function/render/render_system.h | 10 + 28 files changed, 1047 insertions(+), 27 deletions(-) create mode 100644 engine/source/runtime/function/physics/jolt/utils.cpp create mode 100644 engine/source/runtime/function/physics/jolt/utils.h create mode 100644 engine/source/runtime/function/physics/physics_config.h create mode 100644 engine/source/runtime/function/physics/physics_manager.cpp create mode 100644 engine/source/runtime/function/physics/physics_manager.h create mode 100644 engine/source/runtime/function/physics/physics_scene.cpp create mode 100644 engine/source/runtime/function/physics/physics_scene.h diff --git a/engine/3rdparty/CMakeLists.txt b/engine/3rdparty/CMakeLists.txt index babc4af6b..b2a13de7a 100644 --- a/engine/3rdparty/CMakeLists.txt +++ b/engine/3rdparty/CMakeLists.txt @@ -42,3 +42,32 @@ if(NOT TARGET tinyobjloader) set_target_properties(tinyobjloader PROPERTIES FOLDER ${third_party_folder}/tinyobjloader) set_target_properties(uninstall PROPERTIES FOLDER ${third_party_folder}/tinyobjloader) endif() + +if(NOT TARGET Jolt) + option(TARGET_HELLO_WORLD "" OFF) + option(TARGET_PERFORMANCE_TEST "" OFF) + option(TARGET_SAMPLES "" OFF) + option(TARGET_UNIT_TESTS "" OFF) + option(TARGET_VIEWER "" OFF) + + if(ENABLE_PHYSICS_DEBUG_RENDERER) + option(TARGET_TEST_FRAMEWORK "" ON) + else() + option(TARGET_TEST_FRAMEWORK "" OFF) + endif() + + add_subdirectory(JoltPhysics/Build) + + if(ENABLE_PHYSICS_DEBUG_RENDERER) + set_target_properties(Jolt TestFramework + PROPERTIES + FOLDER ${third_party_folder}/JoltPhysics + MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + else() + set_target_properties(Jolt + PROPERTIES + FOLDER ${third_party_folder}/JoltPhysics + MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + endif() + +endif() \ No newline at end of file diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index ca22dba9d..2f7f7278f 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -4,6 +4,16 @@ set(THIRD_PARTY_DIR "${ENGINE_ROOT_DIR}/3rdparty") set(ENGINE_ASSET_DIR "/asset") set(ENGINE_SCHEMA_DIR "/schema") +option(ENABLE_PHYSICS_DEBUG_RENDERER "Enable Physics Debug Renderer" OFF) + +# only support physics debug render at windows platform +if(NOT WIN32) + if(ENABLE_PHYSICS_DEBUG_RENDERER) + message(WARNING "Disable Physics Debug Renderer") + set(ENABLE_PHYSICS_DEBUG_RENDERER OFF CACHE BOOL "" FORCE) + endif() +endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_compile_options("/MP") set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT PilotEditor) diff --git a/engine/asset/objects/environment/floor/floor.object.json b/engine/asset/objects/environment/floor/floor.object.json index 12bcc4214..84f043582 100644 --- a/engine/asset/objects/environment/floor/floor.object.json +++ b/engine/asset/objects/environment/floor/floor.object.json @@ -53,6 +53,42 @@ } }, "$typeName": "MeshComponent" + }, + { + "$typeName": "RigidBodyComponent", + "$context": { + "rigidbody_res": { + "actor_type": 1, + "inverse_mass": 0, + "shapes": [ + { + "geometry": { + "$context": { + "half_extents": { + "x": 43, + "y": 24, + "z": 0.5 + } + }, + "$typeName": "Box" + }, + "local_transform": { + "position": { + "x": 0, + "y": 0, + "z": -0.5 + }, + "rotate": {}, + "scale": { + "x": 1, + "y": 1, + "z": 1 + } + } + } + ] + } + } } ] } \ No newline at end of file diff --git a/engine/source/runtime/CMakeLists.txt b/engine/source/runtime/CMakeLists.txt index 20c557d41..61d48cc3c 100644 --- a/engine/source/runtime/CMakeLists.txt +++ b/engine/source/runtime/CMakeLists.txt @@ -47,9 +47,15 @@ target_link_libraries(${TARGET_NAME} PRIVATE tinyobjloader stb) target_link_libraries(${TARGET_NAME} PUBLIC glm) target_link_libraries(${TARGET_NAME} PUBLIC glfw) target_link_libraries(${TARGET_NAME} PUBLIC imgui) +target_link_libraries(${TARGET_NAME} PUBLIC Jolt) target_link_libraries(${TARGET_NAME} PUBLIC ${vulkan_lib}) target_link_libraries(${TARGET_NAME} PRIVATE $) +if(ENABLE_PHYSICS_DEBUG_RENDERER) + add_compile_definitions(ENABLE_PHYSICS_DEBUG_RENDERER) + target_link_libraries(${TARGET_NAME} PUBLIC TestFramework d3d12.lib shcore.lib) +endif() + target_include_directories( ${TARGET_NAME} PUBLIC $) diff --git a/engine/source/runtime/engine.cpp b/engine/source/runtime/engine.cpp index 4d10fd91f..c18f0175d 100644 --- a/engine/source/runtime/engine.cpp +++ b/engine/source/runtime/engine.cpp @@ -6,6 +6,7 @@ #include "runtime/function/framework/world/world_manager.h" #include "runtime/function/global/global_context.h" #include "runtime/function/input/input_system.h" +#include "runtime/function/physics/physics_manager.h" #include "runtime/function/render/render_system.h" #include "runtime/function/render/window_system.h" @@ -88,8 +89,13 @@ namespace Pilot rendererTick(); +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + g_runtime_global_context.m_physics_manager->renderPhysicsWorld(delta_time); +#endif + g_runtime_global_context.m_window_system->pollEvents(); + g_runtime_global_context.m_window_system->setTile( std::string("Pilot - " + std::to_string(getFPS()) + " FPS").c_str()); diff --git a/engine/source/runtime/function/controller/character_controller.cpp b/engine/source/runtime/function/controller/character_controller.cpp index e67e3ea81..d7cf46b6a 100644 --- a/engine/source/runtime/function/controller/character_controller.cpp +++ b/engine/source/runtime/function/controller/character_controller.cpp @@ -1,15 +1,21 @@ #include "runtime/function/controller/character_controller.h" #include "runtime/function/framework/component/motor/motor_component.h" -#include "runtime/function/physics/physics_system.h" #include "runtime/function/global/global_context.h" +#include "runtime/function/physics/physics_system.h" namespace Pilot { Vector3 CharacterController::move(const Vector3& current_position, const Vector3& displacement) { + const float gap = 0.1f; + + Capsule test_capsule; + test_capsule.m_half_height = m_capsule.m_half_height - gap; + test_capsule.m_radius = m_capsule.m_radius - gap; + Vector3 desired_position = current_position + displacement; - if (g_runtime_global_context.m_physics_system->overlapByCapsule(desired_position, m_capsule)) + if (g_runtime_global_context.m_legacy_physics_system->overlapByCapsule(desired_position, test_capsule)) { desired_position = current_position; } diff --git a/engine/source/runtime/function/framework/component/rigidbody/rigidbody_component.cpp b/engine/source/runtime/function/framework/component/rigidbody/rigidbody_component.cpp index 34b2b2758..5b4a4837d 100644 --- a/engine/source/runtime/function/framework/component/rigidbody/rigidbody_component.cpp +++ b/engine/source/runtime/function/framework/component/rigidbody/rigidbody_component.cpp @@ -4,8 +4,10 @@ #include "runtime/function/framework/component/transform/transform_component.h" #include "runtime/function/framework/object/object.h" -#include "runtime/function/physics/physics_system.h" +#include "runtime/function/framework/world/world_manager.h" #include "runtime/function/global/global_context.h" +#include "runtime/function/physics/physics_scene.h" +#include "runtime/function/physics/physics_system.h" namespace Pilot { @@ -20,15 +22,31 @@ namespace Pilot return; } - m_physics_actor = g_runtime_global_context.m_physics_system->createPhysicsActor( + m_physics_actor = g_runtime_global_context.m_legacy_physics_system->createPhysicsActor( parent_object, parent_transform->getTransformConst(), m_rigidbody_res); + + std::shared_ptr physics_scene = + g_runtime_global_context.m_world_manager->getCurrentActivePhysicsScene().lock(); + ASSERT(physics_scene); + + const uint32_t body_id = physics_scene->createRigidBody(parent_transform->getTransformConst(), m_rigidbody_res); + m_physics_actor->setBodyID(body_id); } RigidBodyComponent::~RigidBodyComponent() { if (m_physics_actor) { - g_runtime_global_context.m_physics_system->removePhyicsActor(m_physics_actor); + g_runtime_global_context.m_legacy_physics_system->removePhyicsActor(m_physics_actor); + + const uint32_t body_id = m_physics_actor->getBodyID(); + + std::shared_ptr physics_scene = + g_runtime_global_context.m_world_manager->getCurrentActivePhysicsScene().lock(); + ASSERT(physics_scene); + + physics_scene->removeRigidBody(body_id); + m_physics_actor = nullptr; } } diff --git a/engine/source/runtime/function/framework/level/level.cpp b/engine/source/runtime/function/framework/level/level.cpp index d6b11670c..e7c94eff6 100644 --- a/engine/source/runtime/function/framework/level/level.cpp +++ b/engine/source/runtime/function/framework/level/level.cpp @@ -8,6 +8,8 @@ #include "runtime/engine.h" #include "runtime/function/character/character.h" #include "runtime/function/framework/object/object.h" +#include "runtime/function/physics/physics_manager.h" +#include "runtime/function/physics/physics_scene.h" #include @@ -19,6 +21,9 @@ namespace Pilot { m_current_active_character.reset(); m_gobjects.clear(); + + ASSERT(g_runtime_global_context.m_physics_manager); + g_runtime_global_context.m_physics_manager->deletePhysicsScene(m_physics_scene); } GObjectID Level::createObject(const ObjectInstanceRes& object_instance_res) @@ -62,6 +67,9 @@ namespace Pilot return false; } + ASSERT(g_runtime_global_context.m_physics_manager); + m_physics_scene = g_runtime_global_context.m_physics_manager->createPhysicsScene(); + for (const ObjectInstanceRes& object_instance_res : level_res.m_objects) { createObject(object_instance_res); @@ -113,7 +121,8 @@ namespace Pilot } } - const bool is_save_success = g_runtime_global_context.m_asset_manager->saveAsset(output_level_res, m_level_res_url); + const bool is_save_success = + g_runtime_global_context.m_asset_manager->saveAsset(output_level_res, m_level_res_url); if (is_save_success == false) { @@ -146,6 +155,12 @@ namespace Pilot { m_current_active_character->tick(delta_time); } + + std::shared_ptr physics_scene = m_physics_scene.lock(); + if (physics_scene) + { + physics_scene->tick(delta_time); + } } std::weak_ptr Level::getGObjectByID(GObjectID go_id) const diff --git a/engine/source/runtime/function/framework/level/level.h b/engine/source/runtime/function/framework/level/level.h index a5c1bf876..80c501aa3 100644 --- a/engine/source/runtime/function/framework/level/level.h +++ b/engine/source/runtime/function/framework/level/level.h @@ -11,6 +11,7 @@ namespace Pilot class Character; class GObject; class ObjectInstanceRes; + class PhysicsScene; using LevelObjectsMap = std::unordered_map>; @@ -37,6 +38,8 @@ namespace Pilot GObjectID createObject(const ObjectInstanceRes& object_instance_res); void deleteGObjectByID(GObjectID go_id); + std::weak_ptr getPhysicsScene() const { return m_physics_scene; } + protected: void clear(); @@ -47,5 +50,7 @@ namespace Pilot LevelObjectsMap m_gobjects; std::shared_ptr m_current_active_character; + + std::weak_ptr m_physics_scene; }; } // namespace Pilot diff --git a/engine/source/runtime/function/framework/world/world_manager.cpp b/engine/source/runtime/function/framework/world/world_manager.cpp index 49af3f4d6..25172338f 100644 --- a/engine/source/runtime/function/framework/world/world_manager.cpp +++ b/engine/source/runtime/function/framework/world/world_manager.cpp @@ -52,6 +52,17 @@ namespace Pilot } } + std::weak_ptr WorldManager::getCurrentActivePhysicsScene() const + { + std::shared_ptr active_level = m_current_active_level.lock(); + if (!active_level) + { + return std::weak_ptr(); + } + + return active_level->getPhysicsScene(); + } + bool WorldManager::loadWorld(const std::string& world_url) { LOG_INFO("loading world: {}", world_url); @@ -84,14 +95,17 @@ namespace Pilot bool WorldManager::loadLevel(const std::string& level_url) { - std::unique_ptr level(new Level); - const bool is_level_load_success = level->load(level_url); + std::shared_ptr level = std::make_shared(); + // set current level temporary + m_current_active_level = level; + + const bool is_level_load_success = level->load(level_url); if (is_level_load_success == false) { return false; } - m_loaded_levels.emplace(level_url, std::move(level)); + m_loaded_levels.emplace(level_url, level); return true; } diff --git a/engine/source/runtime/function/framework/world/world_manager.h b/engine/source/runtime/function/framework/world/world_manager.h index 06d53aa64..5ce72b892 100644 --- a/engine/source/runtime/function/framework/world/world_manager.h +++ b/engine/source/runtime/function/framework/world/world_manager.h @@ -8,6 +8,7 @@ namespace Pilot { class Level; + class PhysicsScene; /// Manage all game worlds, it should be support multiple worlds, including game world and editor world. /// Currently, the implement just supports one active world and one active level @@ -25,6 +26,8 @@ namespace Pilot void tick(float delta_time); std::weak_ptr getCurrentActiveLevel() const { return m_current_active_level; } + std::weak_ptr getCurrentActivePhysicsScene() const; + private: bool loadWorld(const std::string& world_url); bool loadLevel(const std::string& level_url); diff --git a/engine/source/runtime/function/global/global_context.cpp b/engine/source/runtime/function/global/global_context.cpp index 82c67b30d..36609a953 100644 --- a/engine/source/runtime/function/global/global_context.cpp +++ b/engine/source/runtime/function/global/global_context.cpp @@ -13,6 +13,7 @@ #include "runtime/function/framework/world/world_manager.h" #include "runtime/function/input/input_system.h" #include "runtime/function/physics/physics_system.h" +#include "runtime/function/physics/physics_manager.h" #include "runtime/function/render/render_system.h" #include "runtime/function/render/window_system.h" @@ -31,7 +32,10 @@ namespace Pilot m_asset_manager = std::make_shared(); - m_physics_system = std::make_shared(); + m_legacy_physics_system = std::make_shared(); + + m_physics_manager = std::make_shared(); + m_physics_manager->initialize(); m_world_manager = std::make_shared(); m_world_manager->initialize(); @@ -59,7 +63,9 @@ namespace Pilot m_world_manager.reset(); - m_physics_system.reset(); + m_legacy_physics_system.reset(); + + m_physics_manager.reset(); m_input_system.reset(); diff --git a/engine/source/runtime/function/global/global_context.h b/engine/source/runtime/function/global/global_context.h index 8c7f2c350..d8d64bdce 100644 --- a/engine/source/runtime/function/global/global_context.h +++ b/engine/source/runtime/function/global/global_context.h @@ -7,6 +7,7 @@ namespace Pilot class LogSystem; class InputSystem; class PhysicsSystem; + class PhysicsManager; class FileService; class AssetManager; class ConfigManager; @@ -27,16 +28,17 @@ namespace Pilot void shutdownSystems(); public: - std::shared_ptr m_logger_system; - std::shared_ptr m_input_system; - std::shared_ptr m_file_servcie; - std::shared_ptr m_asset_manager; - std::shared_ptr m_config_manager; - std::shared_ptr m_world_manager; - std::shared_ptr m_scene_manager; - std::shared_ptr m_physics_system; - std::shared_ptr m_window_system; - std::shared_ptr m_render_system; + std::shared_ptr m_logger_system; + std::shared_ptr m_input_system; + std::shared_ptr m_file_servcie; + std::shared_ptr m_asset_manager; + std::shared_ptr m_config_manager; + std::shared_ptr m_world_manager; + std::shared_ptr m_scene_manager; + std::shared_ptr m_legacy_physics_system; + std::shared_ptr m_physics_manager; + std::shared_ptr m_window_system; + std::shared_ptr m_render_system; }; extern RuntimeGlobalContext g_runtime_global_context; diff --git a/engine/source/runtime/function/physics/jolt/utils.cpp b/engine/source/runtime/function/physics/jolt/utils.cpp new file mode 100644 index 000000000..8a72de0ef --- /dev/null +++ b/engine/source/runtime/function/physics/jolt/utils.cpp @@ -0,0 +1,157 @@ +#include "runtime/function/physics/jolt/utils.h" + +#include "runtime/resource/res_type/components/rigid_body.h" + +#include "Jolt/Physics/Collision/Shape/BoxShape.h" +#include "Jolt/Physics/Collision/Shape/CapsuleShape.h" +#include "Jolt/Physics/Collision/Shape/SphereShape.h" +#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h" + +namespace Pilot +{ + BPLayerInterfaceImpl::BPLayerInterfaceImpl() + { + // Create a mapping table from object to broad phase layer + m_object_to_broad_phase[Layers::UNUSED1] = BroadPhaseLayers::UNUSED; + m_object_to_broad_phase[Layers::UNUSED2] = BroadPhaseLayers::UNUSED; + m_object_to_broad_phase[Layers::UNUSED3] = BroadPhaseLayers::UNUSED; + m_object_to_broad_phase[Layers::UNUSED4] = BroadPhaseLayers::UNUSED; + m_object_to_broad_phase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING; + m_object_to_broad_phase[Layers::MOVING] = BroadPhaseLayers::MOVING; + m_object_to_broad_phase[Layers::DEBRIS] = BroadPhaseLayers::DEBRIS; + m_object_to_broad_phase[Layers::SENSOR] = BroadPhaseLayers::SENSOR; + } + +#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED) + const char* BPLayerInterfaceImpl::GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const + { + switch ((JPH::BroadPhaseLayer::Type)inLayer) + { + case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING: + return "NON_MOVING"; + case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::MOVING: + return "MOVING"; + case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::DEBRIS: + return "DEBRIS"; + case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::SENSOR: + return "SENSOR"; + case (JPH::BroadPhaseLayer::Type)BroadPhaseLayers::UNUSED: + return "UNUSED"; + default: + ASSERT(false); + return "INVALID"; + } + } +#endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED + + bool ObjectCanCollide(JPH::ObjectLayer inObject1, JPH::ObjectLayer inObject2) + { + switch (inObject1) + { + case Layers::UNUSED1: + case Layers::UNUSED2: + case Layers::UNUSED3: + case Layers::UNUSED4: + return false; + case Layers::NON_MOVING: + return inObject2 == Layers::MOVING || inObject2 == Layers::DEBRIS; + case Layers::MOVING: + return inObject2 == Layers::NON_MOVING || inObject2 == Layers::MOVING || inObject2 == Layers::SENSOR; + case Layers::DEBRIS: + return inObject2 == Layers::NON_MOVING; + case Layers::SENSOR: + return inObject2 == Layers::MOVING; + default: + ASSERT(false); + return false; + } + } + + bool BroadPhaseCanCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) + { + switch (inLayer1) + { + case Layers::NON_MOVING: + return inLayer2 == BroadPhaseLayers::MOVING; + case Layers::MOVING: + return inLayer2 == BroadPhaseLayers::NON_MOVING || inLayer2 == BroadPhaseLayers::MOVING || + inLayer2 == BroadPhaseLayers::SENSOR; + case Layers::DEBRIS: + return inLayer2 == BroadPhaseLayers::NON_MOVING; + case Layers::SENSOR: + return inLayer2 == BroadPhaseLayers::MOVING; + case Layers::UNUSED1: + case Layers::UNUSED2: + case Layers::UNUSED3: + return false; + default: + ASSERT(false); + return false; + } + } + + JPH::Mat44 toMat44(const Matrix4x4& m) + { + JPH::Vec4 cols[4]; + for (int i = 0; i < 4; i++) + { + cols[i] = JPH::Vec4(m.m_mat[0][i], m.m_mat[1][i], m.m_mat[2][i], m.m_mat[3][i]); + } + + return {cols[0], cols[1], cols[2], cols[3]}; + } + + Matrix4x4 toMat44(const JPH::Mat44& m) + { + Vector4 cols[4]; + for (int i = 0; i < 4; i++) + { + cols[i] = toVec4(m.GetColumn4(i)); + } + + return Matrix4x4(cols[0], cols[1], cols[2], cols[3]).transpose(); + } + + JPH::Shape* toShape(const RigidBodyShape& shape, const Vector3& scale) + { + JPH::Shape* jph_shape = nullptr; + + const std::string shape_type_str = shape.m_geometry.getTypeName(); + if (shape_type_str == "Box") + { + const Box* box_geometry = static_cast(shape.m_geometry.getPtr()); + if (box_geometry) + { + JPH::Vec3 jph_box(scale.x * box_geometry->m_half_extents.x, + scale.y * box_geometry->m_half_extents.y, + scale.z * box_geometry->m_half_extents.z); + jph_shape = new JPH::BoxShape(jph_box, 0.f); + } + } + else if (shape_type_str == "Sphere") + { + const Sphere* sphere_geometry = static_cast(shape.m_geometry.getPtr()); + if (sphere_geometry) + { + jph_shape = new JPH::SphereShape((scale.x + scale.y + scale.z) / 3 * + sphere_geometry->m_radius); + } + } + else if (shape_type_str == "Capsule") + { + const Capsule* capsule_geometry = static_cast(shape.m_geometry.getPtr()); + if (capsule_geometry) + { + jph_shape = new JPH::CapsuleShape(scale.z * capsule_geometry->m_half_height, + (scale.x + scale.y) / 2 * capsule_geometry->m_radius); + } + } + else + { + LOG_ERROR("Unsupported Shape") + } + + return jph_shape; + } + +} // namespace Pilot diff --git a/engine/source/runtime/function/physics/jolt/utils.h b/engine/source/runtime/function/physics/jolt/utils.h new file mode 100644 index 000000000..5174bbd4d --- /dev/null +++ b/engine/source/runtime/function/physics/jolt/utils.h @@ -0,0 +1,89 @@ +#pragma once + +#include "core/base/macro.h" +#include "core/math/matrix4.h" +#include "core/math/quaternion.h" +#include "core/math/vector3.h" + +#include "Jolt/Jolt.h" + +#include "Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h" + +namespace JPH +{ + class Shape; +} + +namespace Pilot +{ + class RigidBodyShape; + + namespace Layers + { + static constexpr uint8_t UNUSED1 = 0; // 4 unused values so that broadphase layers values don't match with + // object layer values (for testing purposes) + static constexpr uint8_t UNUSED2 = 1; + static constexpr uint8_t UNUSED3 = 2; + static constexpr uint8_t UNUSED4 = 3; + static constexpr uint8_t NON_MOVING = 4; + static constexpr uint8_t MOVING = 5; + static constexpr uint8_t DEBRIS = 6; // Example: Debris collides only with NON_MOVING + static constexpr uint8_t SENSOR = 7; // Sensors only collide with MOVING objects + static constexpr uint8_t NUM_LAYERS = 8; + }; // namespace Layers + + /// Broadphase layers + namespace BroadPhaseLayers + { + static constexpr JPH::BroadPhaseLayer NON_MOVING(0); + static constexpr JPH::BroadPhaseLayer MOVING(1); + static constexpr JPH::BroadPhaseLayer DEBRIS(2); + static constexpr JPH::BroadPhaseLayer SENSOR(3); + static constexpr JPH::BroadPhaseLayer UNUSED(4); + static constexpr uint32_t NUM_LAYERS(5); + }; // namespace BroadPhaseLayers + + /// BroadPhaseLayerInterface implementation + class BPLayerInterfaceImpl final : public JPH::BroadPhaseLayerInterface + { + public: + BPLayerInterfaceImpl(); + + uint32_t GetNumBroadPhaseLayers() const override { return BroadPhaseLayers::NUM_LAYERS; } + + JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const override + { + ASSERT(inLayer < Layers::NUM_LAYERS); + return m_object_to_broad_phase[inLayer]; + } + +#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED) + const char* GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override; +#endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED + + private: + JPH::BroadPhaseLayer m_object_to_broad_phase[Layers::NUM_LAYERS]; + }; + + /// Function that determines if two object layers can collide + bool ObjectCanCollide(JPH::ObjectLayer inObject1, JPH::ObjectLayer inObject2); + + /// Function that determines if two broadphase layers can collide + bool BroadPhaseCanCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2); + + inline JPH::Vec3 toVec3(Vector3 v) { return {v.x, v.y, v.z}; } + inline Vector3 toVec3(JPH::Vec3 v) { return {v.GetX(), v.GetY(), v.GetZ()}; } + + inline JPH::Vec4 toVec4(Vector4 v) { return {v.x, v.y, v.z, v.w}; } + inline Vector4 toVec4(JPH::Vec4 v) { return {v.GetX(), v.GetY(), v.GetZ(), v.GetW()}; } + + inline JPH::Quat toQuat(Quaternion q) { return {q.x, q.y, q.z, q.w}; } + inline Quaternion toQuat(JPH::Quat q) { return {q.GetW(), q.GetX(), q.GetY(), q.GetZ()}; } + + JPH::Mat44 toMat44(const Matrix4x4& m); + + Matrix4x4 toMat44(const JPH::Mat44& m); + + JPH::Shape* toShape(const RigidBodyShape& shape, const Vector3& scale); + +} // namespace Pilot \ No newline at end of file diff --git a/engine/source/runtime/function/physics/physics_aabb_shape.h b/engine/source/runtime/function/physics/physics_aabb_shape.h index 78f5b9cc2..655092d34 100644 --- a/engine/source/runtime/function/physics/physics_aabb_shape.h +++ b/engine/source/runtime/function/physics/physics_aabb_shape.h @@ -9,7 +9,7 @@ namespace Pilot class PhysicsAABBShape : public PhysicsShapeBase { public: - PhysicsAABBShape(Transform* transform, const Vector3 half_dimensions) : + PhysicsAABBShape(const Transform& transform, const Vector3 half_dimensions) : PhysicsShapeBase(transform), m_half_dimensions(half_dimensions) {} diff --git a/engine/source/runtime/function/physics/physics_actor.h b/engine/source/runtime/function/physics/physics_actor.h index dbc85ee43..0fbd3cd07 100644 --- a/engine/source/runtime/function/physics/physics_actor.h +++ b/engine/source/runtime/function/physics/physics_actor.h @@ -55,6 +55,9 @@ namespace Pilot void setGlobalTransform(const Transform& global_transform); + void setBodyID(uint32_t body_id) { m_body_id = body_id; } + uint32_t getBodyID() const { return m_body_id; } + protected: std::vector m_rigidbody_shapes; @@ -75,5 +78,7 @@ namespace Pilot Matrix3x3 m_inverse_inertia_tensor; int m_actor_type {0}; + + uint32_t m_body_id{0xffffffff}; }; }; // namespace Pilot diff --git a/engine/source/runtime/function/physics/physics_config.h b/engine/source/runtime/function/physics/physics_config.h new file mode 100644 index 000000000..ee25f0aa8 --- /dev/null +++ b/engine/source/runtime/function/physics/physics_config.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "core/math/vector3.h" + +namespace Pilot +{ + class PhysicsConfig + { + public: + // scene setting + uint32_t m_max_body_count {10240}; + uint32_t m_body_mutex_count {0} ; + uint32_t m_max_body_pairs {65536}; + uint32_t m_max_contact_constraints {10240}; + + // job setting + uint32_t m_max_job_count {1024}; + uint32_t m_max_barrier_count {8}; + uint32_t m_max_concurrent_job_count {4}; + + Vector3 m_gravity {0.f, 0.f, -9.8f}; + + float m_update_frequency {60.f}; + }; +} // namespace Pilot diff --git a/engine/source/runtime/function/physics/physics_manager.cpp b/engine/source/runtime/function/physics/physics_manager.cpp new file mode 100644 index 000000000..20697abf0 --- /dev/null +++ b/engine/source/runtime/function/physics/physics_manager.cpp @@ -0,0 +1,115 @@ +#include "runtime/function/physics/physics_manager.h" + +#include "runtime/function/framework/world/world_manager.h" +#include "runtime/function/global/global_context.h" +#include "runtime/function/physics/jolt/utils.h" +#include "runtime/function/physics/physics_scene.h" +#include "runtime/function/render/render_system.h" + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER +#include "TestFramework.h" + +#include "TestFramework/Renderer/DebugRendererImp.h" +#include "TestFramework/Renderer/Font.h" +#include "TestFramework/Renderer/Renderer.h" +#include "TestFramework/Utils/Log.h" +#endif + +namespace Pilot +{ + void PhysicsManager::initialize() + { +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + Trace = TraceImpl; + + m_renderer = new Renderer; + m_renderer->Initialize(); + + m_font = new Font(m_renderer); + m_font->Create("Arial", 24); + + m_debug_renderer = new DebugRendererImp(m_renderer, m_font); +#endif + } + + void PhysicsManager::clear() + { + m_scenes.clear(); + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + delete m_debug_renderer; + delete m_font; + delete m_renderer; +#endif + } + + std::weak_ptr PhysicsManager::createPhysicsScene() + { + + std::shared_ptr physics_scene = std::make_shared(); + + m_scenes.push_back(physics_scene); + + return physics_scene; + } + + void PhysicsManager::deletePhysicsScene(std::weak_ptr physics_scene) + { + std::shared_ptr deleted_scene = physics_scene.lock(); + + auto iter = std::find(m_scenes.begin(), m_scenes.end(), deleted_scene); + if (iter != m_scenes.end()) + { + m_scenes.erase(iter); + } + } + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + void PhysicsManager::renderPhysicsWorld(float delta_time) + { + std::shared_ptr physics_scene = + g_runtime_global_context.m_world_manager->getCurrentActivePhysicsScene().lock(); + + std::shared_ptr render_camera = g_runtime_global_context.m_render_system->getRenderCamera(); + const Vector2& fov = render_camera->getFOV(); + + const EngineContentViewport& engine_viewport = + g_runtime_global_context.m_render_system->getEngineContentViewport(); + + HWND window_handle = m_renderer->GetWindowHandle(); + RECT rc; + GetClientRect(window_handle, &rc); + + const float current_width = static_cast(rc.right - rc.left); + const float current_height = static_cast(rc.bottom - rc.top); + + if (!Math::realEqual(engine_viewport.width, current_width, 1e-1) || + !Math::realEqual(engine_viewport.height, current_height, 1e-1)) + { + ::SetWindowPos(window_handle, + NULL, + rc.left, + rc.top, + engine_viewport.width, + engine_viewport.height, + SWP_NOMOVE | SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOOWNERZORDER); + } + + CameraState world_camera; + world_camera.mPos = toVec3(render_camera->position()); + world_camera.mForward = toVec3(render_camera->forward()); + world_camera.mUp = toVec3(render_camera->up()); + world_camera.mFOVY = fov.y; + world_camera.mFarPlane = render_camera->m_zfar; + world_camera.mNearPlane = render_camera->m_znear; + + m_renderer->BeginFrame(world_camera, 1.f); + + physics_scene->drawPhysicsScene(m_debug_renderer); + + static_cast(m_debug_renderer)->Draw(); + + m_renderer->EndFrame(); + } +#endif +} // namespace Pilot \ No newline at end of file diff --git a/engine/source/runtime/function/physics/physics_manager.h b/engine/source/runtime/function/physics/physics_manager.h new file mode 100644 index 000000000..4091e9169 --- /dev/null +++ b/engine/source/runtime/function/physics/physics_manager.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER +class Renderer; +class Font; + +namespace JPH +{ + class DebugRenderer; +} +#endif + +namespace Pilot +{ + class PhysicsScene; + + class PhysicsManager + { + public: + void initialize(); + void clear(); + + std::weak_ptr createPhysicsScene(); + void deletePhysicsScene(std::weak_ptr physics_scene); + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + void renderPhysicsWorld(float delta_time); +#endif + + + protected: + std::vector> m_scenes; + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + Renderer* m_renderer {nullptr}; + Font* m_font {nullptr}; + + JPH::DebugRenderer* m_debug_renderer {nullptr}; +#endif + + }; +} // namespace Pilot diff --git a/engine/source/runtime/function/physics/physics_obb_shape.h b/engine/source/runtime/function/physics/physics_obb_shape.h index 3be9aede9..340b4db4f 100644 --- a/engine/source/runtime/function/physics/physics_obb_shape.h +++ b/engine/source/runtime/function/physics/physics_obb_shape.h @@ -9,7 +9,7 @@ namespace Pilot class PhysicsOBBShape : public PhysicsShapeBase { public: - PhysicsOBBShape(Transform* transform, const Vector3 half_dimensions) : + PhysicsOBBShape(const Transform& transform, const Vector3 half_dimensions) : PhysicsShapeBase(transform), m_half_dimensions(half_dimensions) {} ~PhysicsOBBShape() override {} diff --git a/engine/source/runtime/function/physics/physics_scene.cpp b/engine/source/runtime/function/physics/physics_scene.cpp new file mode 100644 index 000000000..0c44ecd34 --- /dev/null +++ b/engine/source/runtime/function/physics/physics_scene.cpp @@ -0,0 +1,315 @@ +#include "runtime/function/physics/physics_scene.h" + +#include "core/base/macro.h" + +#include "runtime/resource/res_type/components/rigid_body.h" + +#include "runtime/function/physics/jolt/utils.h" +#include "runtime/function/physics/physics_config.h" + +#include "Jolt/Jolt.h" + +#include "Jolt/Core/JobSystem.h" +#include "Jolt/Core/JobSystemThreadPool.h" +#include "Jolt/Core/TempAllocator.h" + +#include "Jolt/Physics/Body/BodyCreationSettings.h" +#include "Jolt/Physics/Collision/CastResult.h" +#include "Jolt/Physics/Collision/CollideShape.h" +#include "Jolt/Physics/Collision/CollisionCollectorImpl.h" +#include "Jolt/Physics/Collision/NarrowPhaseQuery.h" +#include "Jolt/Physics/Collision/RayCast.h" +#include "Jolt/Physics/Collision/Shape/BoxShape.h" +#include "Jolt/Physics/Collision/Shape/CapsuleShape.h" +#include "Jolt/Physics/Collision/Shape/SphereShape.h" +#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h" +#include "Jolt/Physics/Collision/ShapeCast.h" +#include "Jolt/Physics/PhysicsSystem.h" + +namespace Pilot +{ + PhysicsScene::PhysicsScene() + { + + static_assert(k_invalid_rigidbody_id == JPH::BodyID::cInvalidBodyID); + + m_physics.m_jolt_physics_system = new JPH::PhysicsSystem(); + m_physics.m_jolt_broad_phase_layer_interface = new BPLayerInterfaceImpl(); + + m_physics.m_jolt_job_system = + new JPH::JobSystemThreadPool(m_config.m_max_job_count, + m_config.m_max_barrier_count, + static_cast(m_config.m_max_concurrent_job_count)); + + // 16M temp memory + m_physics.m_temp_allocator = new JPH::TempAllocatorImpl(16 * 1024 * 1024); + + m_physics.m_jolt_physics_system->Init(m_config.m_max_body_count, + m_config.m_body_mutex_count, + m_config.m_max_body_pairs, + m_config.m_max_contact_constraints, + *(m_physics.m_jolt_broad_phase_layer_interface), + BroadPhaseCanCollide, + ObjectCanCollide); + // use the default setting + m_physics.m_jolt_physics_system->SetPhysicsSettings(JPH::PhysicsSettings()); + + m_physics.m_jolt_physics_system->SetGravity( + JPH::Vec3(m_config.m_gravity.x, m_config.m_gravity.y, m_config.m_gravity.z)); + } + + PhysicsScene::~PhysicsScene() + { + delete m_physics.m_jolt_physics_system; + delete m_physics.m_jolt_job_system; + delete m_physics.m_temp_allocator; + delete m_physics.m_jolt_broad_phase_layer_interface; + } + + uint32_t PhysicsScene::createRigidBody(const Transform& global_transform, + const RigidBodyComponentRes& rigidbody_actor_res) + { + JPH::BodyInterface& body_interface = m_physics.m_jolt_physics_system->GetBodyInterface(); + + struct JPHShapeData + { + JPH::Shape* shape {nullptr}; + Transform local_transform; + Vector3 global_position; + Vector3 global_scale; + Quaternion global_rotation; + }; + + std::vector jph_shapes; + + for (size_t shape_index = 0; shape_index < rigidbody_actor_res.m_shapes.size(); shape_index++) + { + const RigidBodyShape& shape = rigidbody_actor_res.m_shapes[shape_index]; + + const Matrix4x4 shape_global_transform = global_transform.getMatrix() * shape.m_local_transform.getMatrix(); + + Vector3 global_position, global_scale; + Quaternion global_rotation; + + shape_global_transform.decomposition(global_position, global_scale, global_rotation); + + JPH::Shape* jph_shape = toShape(shape, global_scale); + + if (jph_shape) + { + jph_shapes.push_back( + {jph_shape, shape.m_local_transform, global_position, global_scale, global_rotation}); + } + } + + if (jph_shapes.empty()) + { + LOG_ERROR("Create JPH Shapes Failed"); + return JPH::BodyID::cInvalidBodyID; + } + + //$TODO: currently just support static object + JPH::EMotionType motion_type = JPH::EMotionType::Static; + JPH::ObjectLayer layer = Layers::NON_MOVING; + + JPH::Body* jph_body = nullptr; + if (jph_shapes.size() == 1) + { + jph_body = body_interface.CreateBody(JPH::BodyCreationSettings(jph_shapes[0].shape, + toVec3(jph_shapes[0].global_position), + toQuat(jph_shapes[0].global_rotation), + motion_type, + layer)); + } + else + { + JPH::Ref compund_shape_setting = new JPH::StaticCompoundShapeSettings; + + for (const JPHShapeData& shape_data : jph_shapes) + { + compund_shape_setting->AddShape(toVec3(shape_data.local_transform.m_position), + toQuat(shape_data.local_transform.m_rotation), + shape_data.shape); + } + + jph_body = body_interface.CreateBody(JPH::BodyCreationSettings(compund_shape_setting, + toVec3(global_transform.m_position), + toQuat(global_transform.m_rotation), + motion_type, + layer)); + } + + if (jph_body == nullptr) + { + LOG_ERROR("Create JPH Body Failed"); + for (const JPHShapeData& shape_data : jph_shapes) + { + delete shape_data.shape; + } + + return JPH::BodyID::cInvalidBodyID; + } + + body_interface.AddBody(jph_body->GetID(), JPH::EActivation::Activate); + + return jph_body->GetID().GetIndexAndSequenceNumber(); + } + + void PhysicsScene::removeRigidBody(uint32_t body_id) + { + JPH::BodyInterface& body_interface = m_physics.m_jolt_physics_system->GetBodyInterface(); + body_interface.RemoveBody(JPH::BodyID(body_id)); + } + + void PhysicsScene::tick(float delta_time) + { + const float time_step = 1.f / m_config.m_update_frequency; + + m_physics.m_jolt_physics_system->Update(time_step, + m_physics.m_collision_steps, + m_physics.m_integration_substeps, + m_physics.m_temp_allocator, + m_physics.m_jolt_job_system); + } + + bool PhysicsScene::raycast(Vector3 ray_origin, + Vector3 ray_directory, + float ray_length, + std::vector& out_hits) + { + const JPH::NarrowPhaseQuery& scene_query = m_physics.m_jolt_physics_system->GetNarrowPhaseQuery(); + + JPH::RayCast ray; + ray.mOrigin = toVec3(ray_origin); + ray.mDirection = toVec3(ray_directory.normalisedCopy() * ray_length); + + JPH::RayCastSettings raycast_setting; + + JPH::AllHitCollisionCollector collector; + + scene_query.CastRay(ray, raycast_setting, collector); + + if (!collector.HadHit()) + { + return false; + } + + collector.Sort(); + + std::vector raycast_results(collector.mHits.begin(), collector.mHits.end()); + + out_hits.clear(); + out_hits.resize(raycast_results.size()); + + for (size_t index = 0; index < raycast_results.size(); index++) + { + const JPH::RayCastResult& cast_result = raycast_results[index]; + + PhysicsHitInfo& hit = out_hits[index]; + hit.hit_position = toVec3(ray.mOrigin + cast_result.mFraction * ray.mDirection); + hit.hit_distance = cast_result.mFraction * ray_length; + hit.body_id = cast_result.mBodyID.GetIndexAndSequenceNumber(); + + // get hit normal + JPH::BodyLockRead body_lock(m_physics.m_jolt_physics_system->GetBodyLockInterface(), cast_result.mBodyID); + const JPH::Body& hit_body = body_lock.GetBody(); + + hit.hit_normal = + toVec3(hit_body.GetWorldSpaceSurfaceNormal(cast_result.mSubShapeID2, toVec3(hit.hit_position))); + } + + return true; + } + + bool PhysicsScene::sweep(const RigidBodyShape& shape, + const Matrix4x4& shape_transform, + Vector3 sweep_direction, + float sweep_length, + std::vector& out_hits) + { + const JPH::NarrowPhaseQuery& scene_query = m_physics.m_jolt_physics_system->GetNarrowPhaseQuery(); + + const Matrix4x4 shape_global_transform = shape_transform * shape.m_local_transform.getMatrix(); + + Vector3 global_position, global_scale; + Quaternion global_rotation; + + shape_global_transform.decomposition(global_position, global_scale, global_rotation); + + JPH::Shape* jph_shape = toShape(shape, global_scale); + + if (jph_shape == nullptr) + { + return false; + } + + JPH::ShapeCast shape_cast = + JPH::ShapeCast::sFromWorldTransform(jph_shape, + JPH::Vec3::sReplicate(1.f), + toMat44(shape_global_transform), + toVec3(sweep_direction.normalisedCopy() * sweep_length)); + + JPH::AllHitCollisionCollector collector; + scene_query.CastShape(shape_cast, JPH::ShapeCastSettings(), collector); + if (!collector.HadHit()) + { + return false; + } + + collector.Sort(); + + std::vector sweep_results(collector.mHits.begin(), collector.mHits.end()); + + out_hits.clear(); + out_hits.resize(sweep_results.size()); + + for (size_t index = 0; index < sweep_results.size(); index++) + { + const JPH::ShapeCastResult& sweep_result = sweep_results[index]; + + PhysicsHitInfo& hit = out_hits[index]; + hit.hit_position = toVec3(sweep_result.mContactPointOn2); + hit.hit_normal = toVec3(sweep_result.mPenetrationAxis.Normalized()); + hit.hit_distance = (hit.hit_position - global_position).length(); + hit.body_id = sweep_result.mBodyID2.GetIndexAndSequenceNumber(); + } + + return true; + } + + bool PhysicsScene::isOverlap(const RigidBodyShape& shape, const Matrix4x4& global_transform) + { + const JPH::NarrowPhaseQuery& scene_query = m_physics.m_jolt_physics_system->GetNarrowPhaseQuery(); + + const Matrix4x4 shape_global_transform = global_transform * shape.m_local_transform.getMatrix(); + + Vector3 global_position, global_scale; + Quaternion global_rotation; + + shape_global_transform.decomposition(global_position, global_scale, global_rotation); + + JPH::Shape* jph_shape = toShape(shape, global_scale); + + if (jph_shape == nullptr) + { + return false; + } + + JPH::AllHitCollisionCollector collector; + scene_query.CollideShape( + jph_shape, JPH::Vec3::sReplicate(1.0f), toMat44(global_transform), JPH::CollideShapeSettings(), collector); + + return !collector.mHits.empty(); + } + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + void PhysicsScene::drawPhysicsScene(JPH::DebugRenderer* debug_renderer) + { +#ifdef JPH_DEBUG_RENDERER + m_physics.m_jolt_physics_system->DrawBodies(JPH::BodyManager::DrawSettings(), debug_renderer); + +#endif + } +#endif + +} // namespace Pilot \ No newline at end of file diff --git a/engine/source/runtime/function/physics/physics_scene.h b/engine/source/runtime/function/physics/physics_scene.h new file mode 100644 index 000000000..638eb24a9 --- /dev/null +++ b/engine/source/runtime/function/physics/physics_scene.h @@ -0,0 +1,91 @@ +#pragma once + +#include "runtime/function/physics/physics_config.h" + +namespace JPH +{ + class PhysicsSystem; + class JobSystem; + class TempAllocator; + class BroadPhaseLayerInterface; +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + class DebugRenderer; +#endif +} // namespace JPH + +namespace Pilot +{ + class Transform; + class RigidBodyComponentRes; + class RigidBodyShape; + + static constexpr uint32_t k_invalid_rigidbody_id = 0xffffffff; + + struct PhysicsHitInfo + { + Vector3 hit_position; + Vector3 hit_normal; + float hit_distance {0.f}; + uint32_t body_id {k_invalid_rigidbody_id}; + }; + + class PhysicsScene + { + struct JoltPhysics + { + JPH::PhysicsSystem* m_jolt_physics_system {nullptr}; + JPH::JobSystem* m_jolt_job_system {nullptr}; + JPH::TempAllocator* m_temp_allocator {nullptr}; + JPH::BroadPhaseLayerInterface* m_jolt_broad_phase_layer_interface {nullptr}; + + int m_collision_steps {1}; + int m_integration_substeps {1}; + }; + + public: + PhysicsScene(); + virtual ~PhysicsScene(); + + uint32_t createRigidBody(const Transform& global_transform, const RigidBodyComponentRes& rigidbody_actor_res); + void removeRigidBody(uint32_t body_id); + + void tick(float delta_time); + + /// cast a ray and find the hits + /// @ray_origin: origin of ray + /// @ray_directory: ray directory + /// @ray_length: ray length, anything beyond this length will not be reported as a hit + /// @out_hits: the found hits, sorted by distance + /// @return: true if any hits found, else false + bool + raycast(Vector3 ray_origin, Vector3 ray_directory, float ray_length, std::vector& out_hits); + + /// cast a shape and find the hits + /// @shape: the casted rigidbody shape + /// @shape_transform: the initial global transform of the casted shape + /// @sweep_directory: sweep directory + /// @sweep_length: sweep length, anything beyond this length will not be reported as a hit + /// @out_hits: the found hits, sorted by distance + /// @return: true if any hits found, else false + bool sweep(const RigidBodyShape& shape, + const Matrix4x4& shape_transform, + Vector3 sweep_directory, + float sweep_length, + std::vector& out_hits); + + /// overlap test + /// @shape: rigidbody shape + /// @return: true if overlapped with any rigidbodies + bool isOverlap(const RigidBodyShape& shape, const Matrix4x4& global_transform); + +#ifdef ENABLE_PHYSICS_DEBUG_RENDERER + void drawPhysicsScene(JPH::DebugRenderer* debug_renderer); +#endif + + protected: + // we use single Jolt physics system for each scene + JoltPhysics m_physics; + + PhysicsConfig m_config; + }; +} // namespace Pilot \ No newline at end of file diff --git a/engine/source/runtime/function/physics/physics_shape_base.h b/engine/source/runtime/function/physics/physics_shape_base.h index 375df6545..08045b875 100644 --- a/engine/source/runtime/function/physics/physics_shape_base.h +++ b/engine/source/runtime/function/physics/physics_shape_base.h @@ -15,17 +15,17 @@ namespace Pilot class PhysicsShapeBase { public: - PhysicsShapeBase(Transform* local_tarnsform) : m_local_transform(local_tarnsform) {} + PhysicsShapeBase(const Transform& local_tarnsform) : m_local_transform(local_tarnsform) {} PhysicsShapeBase() {} virtual ~PhysicsShapeBase() {} ShapeType getType() const { return m_type; } void setType(ShapeType type) { m_type = type; } - Transform* getLocalTransform() const { return m_local_transform; } + const Transform& getLocalTransform() const { return m_local_transform; } private: ShapeType m_type {ShapeType::invalid}; - Transform* m_local_transform {nullptr}; + Transform m_local_transform ; }; } // namespace Pilot \ No newline at end of file diff --git a/engine/source/runtime/function/physics/physics_sphere_shape.h b/engine/source/runtime/function/physics/physics_sphere_shape.h index 2748f4bda..7e3551fe2 100644 --- a/engine/source/runtime/function/physics/physics_sphere_shape.h +++ b/engine/source/runtime/function/physics/physics_sphere_shape.h @@ -7,7 +7,7 @@ namespace Pilot class PhysicsSphereShape : public PhysicsShapeBase { public: - PhysicsSphereShape(Transform* transform, float radius) : PhysicsShapeBase(transform), m_radius(radius) + PhysicsSphereShape(const Transform& transform, float radius) : PhysicsShapeBase(transform), m_radius(radius) { // PhysicsShapeBase::PhysicsShapeBase(transform); } diff --git a/engine/source/runtime/function/physics/physics_system.h b/engine/source/runtime/function/physics/physics_system.h index 59faf767f..c6a06ca6c 100644 --- a/engine/source/runtime/function/physics/physics_system.h +++ b/engine/source/runtime/function/physics/physics_system.h @@ -11,6 +11,7 @@ namespace Pilot { + /// This Physics System is legacy, will be removed lated class PhysicsSystem { public: diff --git a/engine/source/runtime/function/render/render_system.cpp b/engine/source/runtime/function/render/render_system.cpp index fbfacf4e6..ccc64b827 100644 --- a/engine/source/runtime/function/render/render_system.cpp +++ b/engine/source/runtime/function/render/render_system.cpp @@ -137,6 +137,15 @@ namespace Pilot m_render_camera->setAspect(width / height); } + EngineContentViewport RenderSystem::getEngineContentViewport() const + { + float x = std::static_pointer_cast(m_rhi)->_viewport.x; + float y = std::static_pointer_cast(m_rhi)->_viewport.y; + float width = std::static_pointer_cast(m_rhi)->_viewport.width; + float height = std::static_pointer_cast(m_rhi)->_viewport.height; + return {x, y, width, height}; + } + uint32_t RenderSystem::getGuidOfPickedMesh(const Vector2& picked_uv) { return m_render_pipeline->getGuidOfPickedMesh(picked_uv); diff --git a/engine/source/runtime/function/render/render_system.h b/engine/source/runtime/function/render/render_system.h index c1cccdf1b..e39cfeddb 100644 --- a/engine/source/runtime/function/render/render_system.h +++ b/engine/source/runtime/function/render/render_system.h @@ -26,6 +26,14 @@ namespace Pilot std::shared_ptr window_system; }; + struct EngineContentViewport + { + float x { 0.f}; + float y { 0.f}; + float width { 0.f}; + float height { 0.f}; + }; + class RenderSystem { public: @@ -45,6 +53,8 @@ namespace Pilot uint32_t getGuidOfPickedMesh(const Vector2& picked_uv); GObjectID getGObjectIDByMeshID(uint32_t mesh_id) const; + EngineContentViewport getEngineContentViewport() const; + void createAxis(std::array axis_entities, std::array mesh_datas); void setVisibleAxis(std::optional axis); void setSelectedAxis(size_t selected_axis);