JoltPhysics3D: Rework Character class

This commit is contained in:
SirLynix
2023-05-15 19:03:28 +02:00
parent 14c9c7fffd
commit 6f15400d01
19 changed files with 339 additions and 70 deletions

View File

@@ -5,7 +5,6 @@
#include <Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp>
#include <Nazara/Core/Components/DisabledComponent.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <iostream>
#include <Nazara/BulletPhysics3D/Debug.hpp>
namespace Nz
@@ -37,11 +36,13 @@ namespace Nz
if (m_stepCount == 0)
m_stepCount = 1;
/*
std::cout << "Physics time: " << (m_physicsTime / Time::Nanoseconds(m_stepCount)) << std::endl;
std::cout << "Update time: " << (m_updateTime / Time::Nanoseconds(m_stepCount)) << std::endl;
std::cout << "Active body count: " << m_activeObjectCount << std::endl;
std::cout << "--" << std::endl;
*/
m_stepCount = 0;
m_physicsTime = Time::Zero();
m_updateTime = Time::Zero();

View File

@@ -16,7 +16,7 @@ namespace Nz
{
JoltCharacter::JoltCharacter(JoltPhysWorld3D& physWorld, std::shared_ptr<JoltCollider3D> collider, const Vector3f& position, const Quaternionf& rotation) :
m_collider(std::move(collider)),
m_physicsWorld(physWorld)
m_world(&physWorld)
{
auto shapeResult = m_collider->GetShapeSettings()->Create();
if (!shapeResult.IsValid())
@@ -26,22 +26,35 @@ namespace Nz
settings.mShape = shapeResult.Get();
settings.mLayer = 1;
m_character = std::make_unique<JPH::Character>(&settings, ToJolt(position), ToJolt(rotation), 0, m_physicsWorld.GetPhysicsSystem());
m_character = std::make_unique<JPH::Character>(&settings, ToJolt(position), ToJolt(rotation), 0, m_world->GetPhysicsSystem());
m_character->AddToPhysicsSystem();
m_physicsWorld.RegisterCharacter(this);
m_bodyIndex = m_character->GetBodyID().GetIndex();
m_world->RegisterStepListener(this);
}
JoltCharacter::JoltCharacter(JoltCharacter&& character) noexcept :
m_impl(std::move(character.m_impl)),
m_collider(std::move(character.m_collider)),
m_character(std::move(character.m_character)),
m_world(std::move(character.m_world)),
m_bodyIndex(character.m_bodyIndex)
{
character.m_bodyIndex = std::numeric_limits<UInt32>::max();
if (m_world)
m_world->RegisterStepListener(this);
}
JoltCharacter::~JoltCharacter()
{
m_character->RemoveFromPhysicsSystem();
m_physicsWorld.UnregisterCharacter(this);
Destroy();
}
void JoltCharacter::EnableSleeping(bool enable)
{
const JPH::BodyLockInterfaceNoLock& bodyInterface = m_physicsWorld.GetPhysicsSystem()->GetBodyLockInterfaceNoLock();
const JPH::BodyLockInterfaceNoLock& bodyInterface = m_world->GetPhysicsSystem()->GetBodyLockInterfaceNoLock();
JPH::BodyLockWrite bodyLock(bodyInterface, m_character->GetBodyID());
if (!bodyLock.Succeeded())
return;
@@ -85,7 +98,7 @@ namespace Nz
void JoltCharacter::SetFriction(float friction)
{
JPH::BodyInterface& bodyInterface = m_physicsWorld.GetPhysicsSystem()->GetBodyInterfaceNoLock();
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
bodyInterface.SetFriction(m_character->GetBodyID(), friction);
}
@@ -104,17 +117,71 @@ namespace Nz
m_character->SetUp(ToJolt(up));
}
void JoltCharacter::TeleportTo(const Vector3f& position, const Quaternionf& rotation)
{
m_character->SetPositionAndRotation(ToJolt(position), ToJolt(rotation), JPH::EActivation::Activate, false);
}
void JoltCharacter::WakeUp()
{
m_character->Activate(false);
}
void JoltCharacter::PreSimulate(float /*elapsedTime*/)
JoltCharacter& JoltCharacter::operator=(JoltCharacter&& character) noexcept
{
if (m_world)
m_world->UnregisterStepListener(this);
m_impl = std::move(character.m_impl);
m_collider = std::move(character.m_collider);
m_character = std::move(character.m_character);
m_bodyIndex = character.m_bodyIndex;
m_world = std::move(character.m_world);
if (m_world)
m_world->RegisterStepListener(this);
character.m_bodyIndex = std::numeric_limits<UInt32>::max();
return *this;
}
void JoltCharacter::Destroy()
{
if (m_character)
{
m_character->RemoveFromPhysicsSystem();
m_character = nullptr;
}
if (m_world)
{
m_world->UnregisterStepListener(this);
m_world = nullptr;
}
m_collider.reset();
}
void JoltCharacter::PostSimulate()
{
m_character->PostSimulation(0.05f);
m_impl->PostSimulate(*this);
}
void JoltCharacter::PreSimulate(float elapsedTime)
{
m_impl->PreSimulate(*this, elapsedTime);
}
JoltCharacterImpl::~JoltCharacterImpl() = default;
void JoltCharacterImpl::PostSimulate(JoltCharacter& /*character*/)
{
}
void JoltCharacterImpl::PreSimulate(JoltCharacter& /*character*/, float /*elapsedTime*/)
{
}
}

View File

@@ -3,9 +3,9 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/JoltPhysics3D/JoltCharacter.hpp>
#include <Nazara/JoltPhysics3D/JoltHelper.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysics3D.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysicsStepListener.hpp>
#include <NazaraUtils/MemoryPool.hpp>
#include <NazaraUtils/StackVector.hpp>
#include <Jolt/Jolt.h>
@@ -469,8 +469,8 @@ namespace Nz
{
m_world->physicsSystem.Update(stepSize, 1, 1, &m_world->tempAllocator, &jobSystem);
for (JoltCharacter* character : m_characters)
character->PostSimulate();
for (JoltPhysicsStepListener* stepListener : m_stepListeners)
stepListener->PostSimulate();
m_timestepAccumulator -= m_stepSize;
stepCount++;
@@ -523,6 +523,14 @@ namespace Nz
}
}
std::shared_ptr<JoltCharacterImpl> JoltPhysWorld3D::GetDefaultCharacterImpl()
{
if (!m_defaultCharacterImpl)
m_defaultCharacterImpl = std::make_shared<JoltCharacterImpl>();
return m_defaultCharacterImpl;
}
const JPH::Shape* JoltPhysWorld3D::GetNullShape() const
{
if (!m_world->nullShape)
@@ -536,7 +544,7 @@ namespace Nz
void JoltPhysWorld3D::OnPreStep(float deltatime)
{
for (JoltCharacter* character : m_characters)
character->PreSimulate(deltatime);
for (JoltPhysicsStepListener* stepListener : m_stepListeners)
stepListener->PreSimulate(deltatime);
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - JoltPhysics3D module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/JoltPhysics3D/JoltPhysicsStepListener.hpp>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
JoltPhysicsStepListener::~JoltPhysicsStepListener() = default;
void JoltPhysicsStepListener::PostSimulate()
{
}
void JoltPhysicsStepListener::PreSimulate(float /*elapsedTime*/)
{
}
}

View File

@@ -56,13 +56,12 @@ namespace Nz
JoltRigidBody3D::JoltRigidBody3D(JoltRigidBody3D&& body) noexcept :
m_geom(std::move(body.m_geom)),
m_body(body.m_body),
m_world(body.m_world),
m_body(std::move(body.m_body)),
m_world(std::move(body.m_world)),
m_bodyIndex(body.m_bodyIndex),
m_isSimulationEnabled(body.m_isSimulationEnabled),
m_isTrigger(body.m_isTrigger)
{
body.m_body = nullptr;
body.m_bodyIndex = std::numeric_limits<UInt32>::max();
if (m_body)
@@ -343,14 +342,13 @@ namespace Nz
{
Destroy();
m_body = body.m_body;
m_body = std::move(body.m_body);
m_bodyIndex = body.m_bodyIndex;
m_geom = std::move(body.m_geom);
m_world = body.m_world;
m_world = std::move(body.m_world);
m_isSimulationEnabled = body.m_isSimulationEnabled;
m_isTrigger = body.m_isTrigger;
body.m_body = nullptr;
body.m_bodyIndex = std::numeric_limits<UInt32>::max();
if (m_body)
@@ -417,9 +415,10 @@ namespace Nz
{
creationSettings.SetShape(m_world->GetNullShape());
creationSettings.mIsSensor = true; //< not the best solution but enough for now
creationSettings.mPosition = ToJolt(settings.position);
creationSettings.mRotation = ToJolt(settings.rotation);
}
creationSettings.mPosition = ToJolt(settings.position);
creationSettings.mRotation = ToJolt(settings.rotation);
}
bool JoltRigidBody3D::ShouldActivate() const

View File

@@ -3,19 +3,20 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Core/Components/DisabledComponent.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <iostream>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
JoltPhysics3DSystem::JoltPhysics3DSystem(entt::registry& registry) :
m_registry(registry),
m_physicsConstructObserver(m_registry, entt::collector.group<JoltRigidBody3DComponent, NodeComponent>())
m_characterConstructObserver(m_registry, entt::collector.group<JoltCharacterComponent, NodeComponent>(entt::exclude<DisabledComponent, JoltRigidBody3DComponent>)),
m_rigidBodyConstructObserver(m_registry, entt::collector.group<JoltRigidBody3DComponent, NodeComponent>(entt::exclude<DisabledComponent, JoltCharacterComponent>))
{
m_constructConnection = registry.on_construct<JoltRigidBody3DComponent>().connect<&JoltPhysics3DSystem::OnConstruct>(this);
m_destructConnection = registry.on_destroy<JoltRigidBody3DComponent>().connect<&JoltPhysics3DSystem::OnDestruct>(this);
m_constructConnection = registry.on_construct<JoltRigidBody3DComponent>().connect<&JoltPhysics3DSystem::OnBodyConstruct>(this);
m_destructConnection = registry.on_destroy<JoltRigidBody3DComponent>().connect<&JoltPhysics3DSystem::OnBodyDestruct>(this);
m_stepCount = 0;
m_physicsTime = Time::Zero();
@@ -24,9 +25,14 @@ namespace Nz
JoltPhysics3DSystem::~JoltPhysics3DSystem()
{
m_physicsConstructObserver.disconnect();
m_characterConstructObserver.disconnect();
m_rigidBodyConstructObserver.disconnect();
// Ensure every RigidBody3D is destroyed before world is
auto characterView = m_registry.view<JoltCharacterComponent>();
for (auto [entity, characterComponent] : characterView.each())
characterComponent.Destroy();
auto rigidBodyView = m_registry.view<JoltRigidBody3DComponent>();
for (auto [entity, rigidBodyComponent] : rigidBodyView.each())
rigidBodyComponent.Destroy(true);
@@ -37,10 +43,12 @@ namespace Nz
if (m_stepCount == 0)
m_stepCount = 1;
std::cout << "Physics time: " << (m_physicsTime / Time::Nanoseconds(m_stepCount)) << std::endl;
std::cout << "Replication time: " << (m_updateTime / Time::Nanoseconds(m_stepCount)) << std::endl;
std::cout << "Active entity count: " << m_physWorld.GetActiveBodyCount() << std::endl;
std::cout << "--" << std::endl;
/*
NazaraDebug("Physics time: " << (m_physicsTime / Time::Nanoseconds(m_stepCount)));
NazaraDebug("Replication time: " << (m_updateTime / Time::Nanoseconds(m_stepCount)));
NazaraDebug("Active entity count: " << m_physWorld.GetActiveBodyCount()));
NazaraDebug("--");
*/
m_stepCount = 0;
m_physicsTime = Time::Zero();
@@ -86,14 +94,23 @@ namespace Nz
void JoltPhysics3DSystem::Update(Time elapsedTime)
{
// Move newly-created physics entities to their node position/rotation
m_physicsConstructObserver.each([&](entt::entity entity)
m_characterConstructObserver.each([this](entt::entity entity)
{
JoltRigidBody3DComponent& entityPhysics = m_registry.get<JoltRigidBody3DComponent>(entity);
JoltCharacterComponent& entityCharacter = m_registry.get<JoltCharacterComponent>(entity);
NodeComponent& entityNode = m_registry.get<NodeComponent>(entity);
entityPhysics.TeleportTo(entityNode.GetPosition(), entityNode.GetRotation());
entityCharacter.TeleportTo(entityNode.GetPosition(), entityNode.GetRotation());
});
m_rigidBodyConstructObserver.each([this](entt::entity entity)
{
JoltRigidBody3DComponent& entityBody = m_registry.get<JoltRigidBody3DComponent>(entity);
NodeComponent& entityNode = m_registry.get<NodeComponent>(entity);
entityBody.TeleportTo(entityNode.GetPosition(), entityNode.GetRotation());
});
Time t1 = GetElapsedNanoseconds();
// Update the physics world
@@ -102,18 +119,36 @@ namespace Nz
Time t2 = GetElapsedNanoseconds();
// Replicate active rigid body position to their node components
auto view = m_registry.view<NodeComponent, const JoltRigidBody3DComponent>(entt::exclude<DisabledComponent>);
for (auto entity : view)
// Replicate characters to their NodeComponent
{
auto& rigidBodyComponent = view.get<const JoltRigidBody3DComponent>(entity);
if (!m_physWorld.IsBodyActive(rigidBodyComponent.GetBodyIndex()))
continue;
auto view = m_registry.view<NodeComponent, const JoltCharacterComponent>(entt::exclude<DisabledComponent>);
for (auto entity : view)
{
auto& characterComponent = view.get<const JoltCharacterComponent>(entity);
if (!m_physWorld.IsBodyActive(characterComponent.GetBodyIndex()))
continue;
auto& nodeComponent = view.get<NodeComponent>(entity);
auto& nodeComponent = view.get<NodeComponent>(entity);
auto [position, rotation] = rigidBodyComponent.GetPositionAndRotation();
nodeComponent.SetTransform(position, rotation);
auto [position, rotation] = characterComponent.GetPositionAndRotation();
nodeComponent.SetTransform(position, rotation);
}
}
// Replicate active rigid body position to their node components
{
auto view = m_registry.view<NodeComponent, const JoltRigidBody3DComponent>(entt::exclude<DisabledComponent>);
for (auto entity : m_registry.view<NodeComponent, const JoltRigidBody3DComponent>(entt::exclude<DisabledComponent>))
{
auto& rigidBodyComponent = view.get<const JoltRigidBody3DComponent>(entity);
if (!m_physWorld.IsBodyActive(rigidBodyComponent.GetBodyIndex()))
continue;
auto& nodeComponent = view.get<NodeComponent>(entity);
auto [position, rotation] = rigidBodyComponent.GetPositionAndRotation();
nodeComponent.SetTransform(position, rotation);
}
}
Time t3 = GetElapsedNanoseconds();
@@ -122,7 +157,7 @@ namespace Nz
m_updateTime += (t3 - t2);
}
void JoltPhysics3DSystem::OnConstruct(entt::registry& registry, entt::entity entity)
void JoltPhysics3DSystem::OnBodyConstruct(entt::registry& registry, entt::entity entity)
{
// Register rigid body owning entity
JoltRigidBody3DComponent& rigidBody = registry.get<JoltRigidBody3DComponent>(entity);
@@ -133,7 +168,7 @@ namespace Nz
m_physicsEntities[uniqueIndex] = entity;
}
void JoltPhysics3DSystem::OnDestruct(entt::registry& registry, entt::entity entity)
void JoltPhysics3DSystem::OnBodyDestruct(entt::registry& registry, entt::entity entity)
{
// Unregister owning entity
JoltRigidBody3DComponent& rigidBody = registry.get<JoltRigidBody3DComponent>(entity);