JoltPhysics3D: Rework RigidBody wrapper

- Add a clear way to setup dynamic/kinematic or static bodies
- Body registration to the world is batched (all bodies created before a physics step are added together, which is what Jolt is optimized for)
- Added support for empty shapes (= rigid bodies without collision) using a very small shape and tagging the body as sensor
This commit is contained in:
SirLynix
2023-04-05 08:50:39 +02:00
committed by Jérôme Leclercq
parent 67b1710adb
commit d610baf920
14 changed files with 472 additions and 157 deletions

View File

@@ -17,46 +17,57 @@
namespace Nz
{
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, const Matrix4f& mat) :
JoltRigidBody3D(world, nullptr, mat)
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D& world, const DynamicSettings& settings) :
m_geom(settings.geom),
m_world(&world),
m_isSimulationEnabled(false),
m_isTrigger(settings.isTrigger)
{
}
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, std::shared_ptr<JoltCollider3D> geom, const Matrix4f& mat) :
m_geom(std::move(geom)),
m_world(world)
{
NazaraAssert(m_world, "Invalid world");
if (!m_geom)
m_geom = std::make_shared<JoltSphereCollider3D>(std::numeric_limits<float>::epsilon());
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
JPH::Vec3 position = ToJolt(mat.GetTranslation());
JPH::Quat rotation = ToJolt(mat.GetRotation().Normalize());
JPH::BodyCreationSettings settings(m_geom->GetShapeSettings(), position, rotation, JPH::EMotionType::Dynamic, 1);
m_body = bodyInterface.CreateBody(settings);
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
JPH::BodyCreationSettings creationSettings;
BuildSettings(settings, creationSettings);
m_body = bodyInterface.CreateBody(creationSettings);
JPH::BodyID bodyId = m_body->GetID();
bodyInterface.AddBody(bodyId, JPH::EActivation::Activate);
m_bodyIndex = bodyId.GetIndex();
if (settings.isSimulationEnabled)
m_world->RegisterBody(bodyId, !settings.initiallySleeping, false);
}
JoltRigidBody3D::JoltRigidBody3D(JoltRigidBody3D&& object) noexcept :
m_geom(std::move(object.m_geom)),
m_body(object.m_body),
m_bodyIndex(object.m_bodyIndex),
m_world(object.m_world)
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D& world, const StaticSettings& settings) :
m_geom(settings.geom),
m_world(&world),
m_isSimulationEnabled(false),
m_isTrigger(settings.isTrigger)
{
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
object.m_body = nullptr;
object.m_bodyIndex = std::numeric_limits<UInt32>::max();
JPH::BodyCreationSettings creationSettings;
BuildSettings(settings, creationSettings);
m_body = bodyInterface.CreateBody(creationSettings);
JPH::BodyID bodyId = m_body->GetID();
m_bodyIndex = bodyId.GetIndex();
if (settings.isSimulationEnabled)
m_world->RegisterBody(bodyId, false, false); //< static bodies cannot be activated
}
JoltRigidBody3D::JoltRigidBody3D(JoltRigidBody3D&& body) noexcept :
m_geom(std::move(body.m_geom)),
m_body(body.m_body),
m_world(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)
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
}
JoltRigidBody3D::~JoltRigidBody3D()
@@ -69,10 +80,8 @@ namespace Nz
switch (coordSys)
{
case CoordSys::Global:
{
m_body->AddForce(ToJolt(force));
break;
}
case CoordSys::Local:
m_body->AddForce(m_body->GetRotation() * ToJolt(force));
@@ -80,21 +89,17 @@ namespace Nz
}
}
#if 0
void JoltRigidBody3D::AddForce(const Vector3f& force, const Vector3f& point, CoordSys coordSys)
{
switch (coordSys)
{
case CoordSys::Global:
WakeUp();
m_body->applyForce(ToJolt(force), ToJolt(point));
m_body->AddForce(ToJolt(force), ToJolt(point));
break;
case CoordSys::Local:
{
Matrix4f transformMatrix = GetMatrix();
return AddForce(transformMatrix.Transform(force, 0.f), point, CoordSys::Global);
}
m_body->AddForce(m_body->GetRotation() * ToJolt(force), ToJolt(ToWorld(point)));
break;
}
}
@@ -103,74 +108,83 @@ namespace Nz
switch (coordSys)
{
case CoordSys::Global:
WakeUp();
m_body->applyTorque(ToJolt(torque));
m_body->AddTorque(ToJolt(torque));
break;
case CoordSys::Local:
Matrix4f transformMatrix = GetMatrix();
WakeUp();
m_body->applyTorque(ToJolt(transformMatrix.Transform(torque, 0.f)));
m_body->AddTorque(m_body->GetRotation() * ToJolt(torque));
break;
}
}
#endif
void JoltRigidBody3D::EnableSimulation(bool enable)
{
if (m_isSimulationEnabled == enable)
return;
if (enable)
m_world->RegisterBody(m_body->GetID(), true, true);
else
m_world->UnregisterBody(m_body->GetID(), false, true);
m_isSimulationEnabled = enable;
}
void JoltRigidBody3D::EnableSleeping(bool enable)
{
m_body->SetAllowSleeping(enable);
}
#if 0
void JoltRigidBody3D::FallAsleep()
{
if (m_body->getActivationState() != DISABLE_DEACTIVATION)
m_body->setActivationState(ISLAND_SLEEPING);
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
bodyInterface.DeactivateBody(m_body->GetID());
}
Boxf JoltRigidBody3D::GetAABB() const
{
btVector3 min, max;
m_body->getAabb(min, max);
return Boxf(FromJolt(min), FromJolt(max));
const JPH::AABox& aabb = m_body->GetWorldSpaceBounds();
return Boxf(FromJolt(aabb.mMin), FromJolt(aabb.GetSize()));
}
float JoltRigidBody3D::GetAngularDamping() const
{
return m_body->getAngularDamping();
if NAZARA_UNLIKELY(IsStatic())
return 0.f;
return m_body->GetMotionProperties()->GetAngularDamping();
}
Vector3f JoltRigidBody3D::GetAngularVelocity() const
{
return FromJolt(m_body->getAngularVelocity());
return FromJolt(m_body->GetAngularVelocity());
}
float JoltRigidBody3D::GetLinearDamping() const
{
return m_body->getLinearDamping();
if NAZARA_UNLIKELY(IsStatic())
return 0.f;
return m_body->GetMotionProperties()->GetLinearDamping();
}
Vector3f JoltRigidBody3D::GetLinearVelocity() const
{
return FromJolt(m_body->getLinearVelocity());
return FromJolt(m_body->GetLinearVelocity());
}
#endif
float JoltRigidBody3D::GetMass() const
{
if NAZARA_UNLIKELY(IsStatic())
return 0.f;
return 1.f / m_body->GetMotionProperties()->GetInverseMass();
}
#if 0
Vector3f JoltRigidBody3D::GetMassCenter(CoordSys coordSys) const
{
return FromJolt(m_body->getCenterOfMassPosition());
}
Matrix4f JoltRigidBody3D::GetMatrix() const
{
return FromJolt(m_body->getWorldTransform());
return FromJolt(m_body->GetCenterOfMassTransform());
}
#endif
Vector3f JoltRigidBody3D::GetPosition() const
{
@@ -190,13 +204,6 @@ namespace Nz
return FromJolt(m_body->GetRotation());
}
#if 0
bool JoltRigidBody3D::IsSimulationEnabled() const
{
return m_body->isActive();
}
#endif
bool JoltRigidBody3D::IsSleeping() const
{
return m_body->IsActive();
@@ -207,30 +214,42 @@ namespace Nz
return m_body->GetAllowSleeping();
}
#if 0
bool JoltRigidBody3D::IsStatic() const
{
return m_body->GetMotionType() == JPH::EMotionType::Static;
}
void JoltRigidBody3D::SetAngularDamping(float angularDamping)
{
m_body->setDamping(m_body->getLinearDamping(), angularDamping);
if NAZARA_UNLIKELY(IsStatic())
return;
m_body->GetMotionProperties()->SetAngularDamping(angularDamping);
}
void JoltRigidBody3D::SetAngularVelocity(const Vector3f& angularVelocity)
{
m_body->setAngularVelocity(ToJolt(angularVelocity));
m_body->SetAngularVelocity(ToJolt(angularVelocity));
}
#endif
void JoltRigidBody3D::SetGeom(std::shared_ptr<JoltCollider3D> geom, bool recomputeInertia)
{
if (m_geom != geom)
{
float mass = GetMass();
if (geom)
m_geom = std::move(geom);
const JPH::Shape* shape;
m_geom = std::move(geom);
if (m_geom)
shape = m_geom->GetShapeSettings()->Create().Get();
else
m_geom = std::make_shared<JoltSphereCollider3D>(std::numeric_limits<float>::epsilon());
{
m_body->SetIsSensor(true);
shape = m_world->GetNullShape();
}
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
bodyInterface.SetShape(m_body->GetID(), m_geom->GetShapeSettings()->Create().Get(), false, JPH::EActivation::Activate);
bodyInterface.SetShape(m_body->GetID(), m_geom->GetShapeSettings()->Create().Get(), false, (ShouldActivate()) ? JPH::EActivation::Activate : JPH::EActivation::DontActivate);
if (recomputeInertia)
{
JPH::MassProperties massProperties = m_body->GetShape()->GetMassProperties();
@@ -242,6 +261,9 @@ namespace Nz
void JoltRigidBody3D::SetLinearDamping(float damping)
{
if NAZARA_UNLIKELY(IsStatic())
return;
m_body->GetMotionProperties()->SetLinearDamping(damping);
}
@@ -270,34 +292,28 @@ namespace Nz
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
bodyInterface.DeactivateBody(m_body->GetID());
m_body->SetMotionType(JPH::EMotionType::Static);
m_body->SetMotionType(JPH::EMotionType::Kinematic);
}
}
void JoltRigidBody3D::SetMassCenter(const Vector3f& center)
{
//m_body->GetMotionProperties()->set
}
void JoltRigidBody3D::SetPosition(const Vector3f& position)
{
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
bodyInterface.SetPosition(m_body->GetID(), ToJolt(position), JPH::EActivation::Activate);
bodyInterface.SetPosition(m_body->GetID(), ToJolt(position), (ShouldActivate()) ? JPH::EActivation::Activate : JPH::EActivation::DontActivate);
}
void JoltRigidBody3D::SetRotation(const Quaternionf& rotation)
{
JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
body_interface.SetRotation(m_body->GetID(), ToJolt(rotation), JPH::EActivation::Activate);
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
bodyInterface.SetRotation(m_body->GetID(), ToJolt(rotation), (ShouldActivate()) ? JPH::EActivation::Activate : JPH::EActivation::DontActivate);
}
void JoltRigidBody3D::TeleportTo(const Vector3f& position, const Quaternionf& rotation)
{
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterfaceNoLock();
bodyInterface.SetPositionAndRotation(m_body->GetID(), ToJolt(position), ToJolt(rotation), JPH::EActivation::Activate);
bodyInterface.SetPositionAndRotation(m_body->GetID(), ToJolt(position), ToJolt(rotation), (ShouldActivate()) ? JPH::EActivation::Activate : JPH::EActivation::DontActivate);
}
#if 0
Quaternionf JoltRigidBody3D::ToLocal(const Quaternionf& worldRotation)
{
return GetRotation().Conjugate() * worldRotation;
@@ -305,8 +321,7 @@ namespace Nz
Vector3f JoltRigidBody3D::ToLocal(const Vector3f& worldPosition)
{
btTransform worldTransform = m_body->getWorldTransform();
return GetMatrix().InverseTransform() * worldPosition;
return FromJolt(m_body->GetInverseCenterOfMassTransform() * ToJolt(worldPosition));
}
Quaternionf JoltRigidBody3D::ToWorld(const Quaternionf& localRotation)
@@ -316,45 +331,100 @@ namespace Nz
Vector3f JoltRigidBody3D::ToWorld(const Vector3f& localPosition)
{
return GetMatrix() * localPosition;
return FromJolt(m_body->GetCenterOfMassTransform() * ToJolt(localPosition));
}
#endif
void JoltRigidBody3D::WakeUp()
{
JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface();
body_interface.ActivateBody(m_body->GetID());
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
bodyInterface.ActivateBody(m_body->GetID());
}
JoltRigidBody3D& JoltRigidBody3D::operator=(JoltRigidBody3D&& object) noexcept
JoltRigidBody3D& JoltRigidBody3D::operator=(JoltRigidBody3D&& body) noexcept
{
Destroy();
m_body = object.m_body;
m_bodyIndex = object.m_bodyIndex;
m_geom = std::move(object.m_geom);
m_world = object.m_world;
m_body = body.m_body;
m_bodyIndex = body.m_bodyIndex;
m_geom = std::move(body.m_geom);
m_world = body.m_world;
m_isSimulationEnabled = body.m_isSimulationEnabled;
m_isTrigger = body.m_isTrigger;
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
body.m_body = nullptr;
body.m_bodyIndex = std::numeric_limits<UInt32>::max();
object.m_body = nullptr;
object.m_bodyIndex = std::numeric_limits<UInt32>::max();
if (m_body)
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
return *this;
}
void JoltRigidBody3D::Destroy()
void JoltRigidBody3D::Destroy(bool worldDestruction)
{
if (m_body)
{
JPH::BodyID bodyId = m_body->GetID();
JPH::BodyInterface& bodyInterface = m_world->GetPhysicsSystem()->GetBodyInterface();
bodyInterface.RemoveBody(bodyId);
bodyInterface.DestroyBody(bodyId);
m_world->UnregisterBody(m_body->GetID(), true, !worldDestruction);
m_body = nullptr;
}
m_geom.reset();
}
void JoltRigidBody3D::BuildSettings(const DynamicSettings& settings, JPH::BodyCreationSettings& creationSettings)
{
BuildSettings(static_cast<const CommonSettings&>(settings), creationSettings);
creationSettings.mAngularDamping = settings.angularDamping;
creationSettings.mAngularVelocity = ToJolt(settings.angularVelocity);
creationSettings.mLinearDamping = settings.linearDamping;
creationSettings.mLinearVelocity = ToJolt(settings.linearVelocity);
creationSettings.mFriction = settings.friction;
creationSettings.mGravityFactor = settings.gravityFactor;
creationSettings.mMaxAngularVelocity = settings.maxAngularVelocity;
creationSettings.mMaxLinearVelocity = settings.maxLinearVelocity;
creationSettings.mObjectLayer = 1;
creationSettings.mRestitution = settings.restitution;
creationSettings.mUserData = SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this));
creationSettings.mMassPropertiesOverride = creationSettings.GetShape()->GetMassProperties();
creationSettings.mMassPropertiesOverride.ScaleToMass(settings.mass);
creationSettings.mMotionType = (settings.mass > 0.f) ? JPH::EMotionType::Dynamic : JPH::EMotionType::Kinematic;
switch (settings.motionQuality)
{
case JoltMotionQuality::Discrete: creationSettings.mMotionQuality = JPH::EMotionQuality::Discrete; break;
case JoltMotionQuality::LinearCast: creationSettings.mMotionQuality = JPH::EMotionQuality::LinearCast; break;
}
}
void JoltRigidBody3D::BuildSettings(const StaticSettings& settings, JPH::BodyCreationSettings& creationSettings)
{
BuildSettings(static_cast<const CommonSettings&>(settings), creationSettings);
creationSettings.mMotionType = JPH::EMotionType::Static;
}
void JoltRigidBody3D::BuildSettings(const CommonSettings& settings, JPH::BodyCreationSettings& creationSettings)
{
if (settings.geom)
{
creationSettings.SetShapeSettings(settings.geom->GetShapeSettings());
creationSettings.mIsSensor = settings.isTrigger;
}
else
{
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);
}
}
bool JoltRigidBody3D::ShouldActivate() const
{
return m_isSimulationEnabled && m_world->IsBodyRegistered(m_bodyIndex);
}
}