From 27722e2f97560b4c04c4d024cc4916455a218a72 Mon Sep 17 00:00:00 2001 From: Lamakaio Date: Mon, 24 Jun 2024 13:46:57 +0200 Subject: [PATCH] Add optimization for many bodies + build fixes --- .gitignore | 1 + .gitmodules | 2 +- CMakeLists.txt | 2 ++ src/ospjolt/activescene/joltinteg.h | 9 +----- src/ospjolt/activescene/joltinteg_fn.cpp | 18 ++++++------ src/ospjolt/activescene/joltinteg_fn.h | 4 +-- src/testapp/sessions/jolt.cpp | 37 +++++++++++++++++------- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index e5babb84..d638450a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ out/ .vs/ build/ .vscode/ +.cache \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 8a480c16..1713c4b9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -39,4 +39,4 @@ url = https://github.com/freetype/freetype [submodule "3rdparty/JoltPhysics"] path = 3rdparty/JoltPhysics - url = git@github.com:jrouwe/JoltPhysics.git + url = https://github.com/jrouwe/JoltPhysics.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 80a0fd24..06f4dc94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,8 @@ IF(MSVC) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$ CACHE PATH "") # Force multiprocessor compilation for all projects add_compile_options($<$:/MP>) + # Force dynamic runtime library to be in debug mode in debug mode. + add_compile_options($<$:$<$:/MDd>>) # Don't generate a blah.manifest file for each build target. add_link_options(LINKER:/MANIFEST:NO) ELSEIF(UNIX) diff --git a/src/ospjolt/activescene/joltinteg.h b/src/ospjolt/activescene/joltinteg.h index d7a31828..54be7724 100644 --- a/src/ospjolt/activescene/joltinteg.h +++ b/src/ospjolt/activescene/joltinteg.h @@ -37,22 +37,18 @@ JPH_SUPPRESS_WARNINGS #include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include #include #include #include -#include JPH_SUPPRESS_WARNING_POP @@ -65,10 +61,7 @@ JPH_SUPPRESS_WARNING_POP #include #include -#include #include -#include -#include #include "osp/core/strong_id.h" @@ -240,7 +233,7 @@ class PhysicsStepListenerImpl : public PhysicsStepListener { public: PhysicsStepListenerImpl(ACtxJoltWorld* pContext) : m_context(pContext) {}; - void OnStep(float inDeltaTime, PhysicsSystem& inPhysicsSystem) override; + void OnStep(float inDeltaTime, PhysicsSystem& rPhysicsSystem) override; private: ACtxJoltWorld* m_context; diff --git a/src/ospjolt/activescene/joltinteg_fn.cpp b/src/ospjolt/activescene/joltinteg_fn.cpp index ceea14a2..81102b1c 100644 --- a/src/ospjolt/activescene/joltinteg_fn.cpp +++ b/src/ospjolt/activescene/joltinteg_fn.cpp @@ -1,6 +1,6 @@ /** * Open Space Program - * Copyright © 2019-2020 Open Space Program Project + * Copyright © 2019-2024 Open Space Program Project * * MIT License * @@ -99,7 +99,7 @@ void SysJolt::update_world( rCtxWorld.m_pTransform = std::addressof(rTf); - uint collisionSteps = 1; + int collisionSteps = 1; pJoltWorld->Update(timestep, collisionSteps, &rCtxWorld.m_temp_allocator, rCtxWorld.m_joltJobSystem.get()); } @@ -135,7 +135,7 @@ Ref SysJolt::create_primitive(ACtxJoltWorld &rCtxWorld, osp::EShape shape return RotatedTranslatedShapeSettings( Vec3Arg::sZero(), Quat::sRotation(Vec3::sAxisX(), JPH_PI/2), - new CylinderShapeSettings(scale.GetY(), 2.0f * scale.GetX()) + new CylinderShapeSettings(scale.GetZ(), 2.0f * scale.GetX()) ).Create().Get(); default: @@ -146,7 +146,7 @@ Ref SysJolt::create_primitive(ACtxJoltWorld &rCtxWorld, osp::EShape shape void SysJolt::scale_shape(Ref rShape, Vec3Arg scale) { if (rShape->GetSubType() == EShapeSubType::Scaled) { ScaledShape* rScaledShape = dynamic_cast(rShape.GetPtr()); - if (rScaledShape) + if (rScaledShape != nullptr) { rShape = new ScaledShape(rScaledShape->GetInnerShape(), scale * rScaledShape->GetScale()); } @@ -180,7 +180,7 @@ void SysJolt::find_shapes_recurse( ACompTransformStorage_t const& rTf, ActiveEnt ent, Matrix4 const& transform, - CompoundShapeSettings& pCompound) noexcept + CompoundShapeSettings& rCompound) noexcept { // Add jolt shape if exists if (rCtxWorld.m_shapes.contains(ent)) @@ -189,7 +189,7 @@ void SysJolt::find_shapes_recurse( // Set transform relative to root body SysJolt::scale_shape(rShape, Vec3MagnumToJolt(transform.scaling())); - pCompound.AddShape( + rCompound.AddShape( Vec3MagnumToJolt(transform.translation()), QuatMagnumToJolt(osp::Quaternion::fromMatrix(transform.rotation())), rShape); @@ -210,7 +210,7 @@ void SysJolt::find_shapes_recurse( Matrix4 const childMatrix = transform * rChildTransform.m_transform; find_shapes_recurse( - rCtxPhys, rCtxWorld, rScnGraph, rTf, child, childMatrix, pCompound); + rCtxPhys, rCtxWorld, rScnGraph, rTf, child, childMatrix, rCompound); } } @@ -220,10 +220,10 @@ void SysJolt::find_shapes_recurse( //TODO this is locking on all bodies. Is it bad ? //The easy fix is to provide multiple step listeners for disjoint sets of bodies, which can then run in parallel. //It might not be worth it considering this function should be quite fast. -void PhysicsStepListenerImpl::OnStep(float inDeltaTime, PhysicsSystem &rJoltWorld) +void PhysicsStepListenerImpl::OnStep(float inDeltaTime, PhysicsSystem &rPhysicsSystem) { //no lock as all bodies are already locked - BodyInterface &bodyInterface = rJoltWorld.GetBodyInterfaceNoLock(); + BodyInterface &bodyInterface = rPhysicsSystem.GetBodyInterfaceNoLock(); for (BodyId bodyId : m_context->m_bodyIds) { JPH::BodyID joltBodyId = BToJolt(bodyId); diff --git a/src/ospjolt/activescene/joltinteg_fn.h b/src/ospjolt/activescene/joltinteg_fn.h index 80ca224b..78766226 100644 --- a/src/ospjolt/activescene/joltinteg_fn.h +++ b/src/ospjolt/activescene/joltinteg_fn.h @@ -90,7 +90,7 @@ class SysJolt } } //Apply a scale to a shape. - static void scale_shape(Ref rJoltShap, Vec3Arg scale); + static void scale_shape(Ref rShape, Vec3Arg scale); //Get the inverse mass of a jolt body static float get_inverse_mass_no_lock(PhysicsSystem& physicsSystem, BodyId bodyId); @@ -120,4 +120,4 @@ class SysJolt }; -} \ No newline at end of file +} diff --git a/src/testapp/sessions/jolt.cpp b/src/testapp/sessions/jolt.cpp index 9274e5bd..35e22334 100644 --- a/src/testapp/sessions/jolt.cpp +++ b/src/testapp/sessions/jolt.cpp @@ -203,7 +203,16 @@ Session setup_phys_shapes_jolt( .args({ idBasic, idPhysShapes, idPhys, idJolt, idJoltFactors }) .func([] (ACtxBasic const &rBasic, ACtxPhysShapes& rPhysShapes, ACtxPhysics& rPhys, ACtxJoltWorld& rJolt, ForceFactors_t joltFactors) noexcept { - for (std::size_t i = 0; i < rPhysShapes.m_spawnRequest.size(); ++i) + + PhysicsSystem *pJoltWorld = rJolt.m_pPhysicsSystem.get(); + BodyInterface &bodyInterface = pJoltWorld->GetBodyInterface(); + + int numBodies = static_cast(rPhysShapes.m_spawnRequest.size()); + + std::vector addedBodies; + addedBodies.reserve(numBodies); + + for (std::size_t i = 0; i < numBodies; ++i) { SpawnShape const &spawn = rPhysShapes.m_spawnRequest[i]; ActiveEnt const root = rPhysShapes.m_ents[i * 2]; @@ -235,21 +244,23 @@ Session setup_phys_shapes_jolt( bodyCreation.mObjectLayer = Layers::MOVING; } //TODO helper function ? - PhysicsSystem *pJoltWorld = rJolt.m_pPhysicsSystem.get(); - BodyInterface &bodyInterface = pJoltWorld->GetBodyInterface(); + JPH::BodyID joltBodyId = BToJolt(bodyId); bodyInterface.CreateBodyWithID(joltBodyId, bodyCreation); - bodyInterface.AddBody(joltBodyId, EActivation::Activate); + addedBodies.push_back(joltBodyId); rJolt.m_bodyToEnt[bodyId] = root; rJolt.m_bodyFactors[bodyId] = joltFactors; rJolt.m_entToBody.emplace(root, bodyId); } + //Bodies are added all at once for performance reasons. + BodyInterface::AddState addState = bodyInterface.AddBodiesPrepare(addedBodies.data(), numBodies); + bodyInterface.AddBodiesFinalize(addedBodies.data(), numBodies, addState, EActivation::Activate); }); return out; -} // setup_phys_shapes_newton +} // setup_phys_shapes_jolt void compound_collect_recurse( @@ -431,6 +442,11 @@ Session setup_vehicle_spawn_jolt( auto const& itWeldOffsetsLast = std::end(rVehicleSpawn.spawnedWeldOffsets); auto itWeldOffsets = std::begin(rVehicleSpawn.spawnedWeldOffsets); + PhysicsSystem *pJoltWorld = rJolt.m_pPhysicsSystem.get(); + BodyInterface &bodyInterface = pJoltWorld->GetBodyInterface(); + + std::vector addedBodies; + for (ACtxVehicleSpawn::TmpToInit const& toInit : rVehicleSpawn.spawnRequest) { auto const itWeldOffsetsNext = std::next(itWeldOffsets); @@ -440,7 +456,7 @@ Session setup_vehicle_spawn_jolt( std::for_each(itWeldsFirst + std::ptrdiff_t{*itWeldOffsets}, itWeldsFirst + std::ptrdiff_t{weldOffsetNext}, - [&rBasic, &rScnParts, &rVehicleSpawn, &toInit, &rPhys, &rJolt] (WeldId const weld) + [&rBasic, &rScnParts, &rVehicleSpawn, &toInit, &rPhys, &rJolt, &addedBodies] (WeldId const weld) { ActiveEnt const weldEnt = rScnParts.weldToActive[weld]; @@ -494,13 +510,16 @@ Session setup_vehicle_spawn_jolt( BodyInterface &bodyInterface = pJoltWorld->GetBodyInterface(); JPH::BodyID joltBodyId = BToJolt(bodyId); bodyInterface.CreateBodyWithID(joltBodyId, bodyCreation); - bodyInterface.AddBody(joltBodyId, EActivation::Activate); - + addedBodies.push_back(joltBodyId); rPhys.m_setVelocity.emplace_back(weldEnt, toInit.velocity); }); itWeldOffsets = itWeldOffsetsNext; } + //Bodies are added all at once for performance reasons. + int numBodies = static_cast(addedBodies.size()); + BodyInterface::AddState addState = bodyInterface.AddBodiesPrepare(addedBodies.data(), numBodies); + bodyInterface.AddBodiesFinalize(addedBodies.data(), numBodies, addState, EActivation::Activate); }); return out; @@ -745,5 +764,3 @@ Session setup_rocket_thrust_jolt( } // namespace testapp::scenes - -