diff --git a/Source/Engine/ContentImporters/CreateCollisionData.cpp b/Source/Engine/ContentImporters/CreateCollisionData.cpp
index f2d90ea10..8409915ee 100644
--- a/Source/Engine/ContentImporters/CreateCollisionData.cpp
+++ b/Source/Engine/ContentImporters/CreateCollisionData.cpp
@@ -5,6 +5,7 @@
#if COMPILE_WITH_ASSETS_IMPORTER
#include "AssetsImportingManager.h"
+#include "Engine/Physics/CollisionData.h"
CreateAssetResult CreateCollisionData::Create(CreateAssetContext& context)
{
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index 4e411243d..f8a3a11a6 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -197,7 +197,7 @@ int32 Engine::Main(const Char* cmdLine)
}
// Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step)
- Physics::CollectResultsAll();
+ Physics::CollectResults();
}
// Call on exit event
@@ -242,7 +242,7 @@ void Engine::OnFixedUpdate()
{
PROFILE_CPU_NAMED("Fixed Update");
- Physics::FlushRequestsAll();
+ Physics::FlushRequests();
// Call event
FixedUpdate();
@@ -253,7 +253,7 @@ void Engine::OnFixedUpdate()
if (!Time::GetGamePaused())
{
const float dt = Time::Physics.DeltaTime.GetTotalSeconds();
- Physics::SimulateAll(dt);
+ Physics::Simulate(dt);
// After this point we should not modify physic objects state (rendering operations is mostly readonly)
// That's because auto-simulation mode is performing rendering during physics simulation
@@ -429,7 +429,7 @@ void Engine::OnExit()
EngineImpl::IsReady = false;
// Collect physics simulation results because we cannot exit with physics running
- Physics::CollectResultsAll();
+ Physics::CollectResults();
// Before
Application::BeforeExit();
diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp
index f2a0a3a62..ac10d3ed6 100644
--- a/Source/Engine/Level/Actor.cpp
+++ b/Source/Engine/Level/Actor.cpp
@@ -1814,9 +1814,9 @@ void Actor::FromJson(const StringAnsiView& json)
void Actor::SetPhysicsScene(PhysicsScene* scene)
{
- ASSERT(scene);
+ CHECK(scene);
- auto previous = GetPhysicsScene();
+ const auto previous = GetPhysicsScene();
_physicsScene = scene;
if (previous != _physicsScene)
@@ -1829,10 +1829,7 @@ void Actor::SetPhysicsScene(PhysicsScene* scene)
}
}
-PhysicsScene* Actor::GetPhysicsScene()
+PhysicsScene* Actor::GetPhysicsScene() const
{
- if (_physicsScene == nullptr)
- _physicsScene = Physics::DefaultScene;
-
- return _physicsScene;
+ return _physicsScene ? _physicsScene : Physics::DefaultScene;
}
diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h
index a54155e5f..ef310204c 100644
--- a/Source/Engine/Level/Actor.h
+++ b/Source/Engine/Level/Actor.h
@@ -970,10 +970,10 @@ public:
///
/// Get the physics world the controller is part of.
///
- API_PROPERTY(Attributes="HideInEditor") PhysicsScene* GetPhysicsScene();
+ API_PROPERTY(Attributes="HideInEditor") PhysicsScene* GetPhysicsScene() const;
protected:
- virtual void OnPhysicsSceneChanged(PhysicsScene* previous) {};
+ virtual void OnPhysicsSceneChanged(PhysicsScene* previous) {}
private:
diff --git a/Source/Engine/Physics/Actors/IPhysicsActor.h b/Source/Engine/Physics/Actors/IPhysicsActor.h
index 28f7fddf4..9ce642d1f 100644
--- a/Source/Engine/Physics/Actors/IPhysicsActor.h
+++ b/Source/Engine/Physics/Actors/IPhysicsActor.h
@@ -2,36 +2,27 @@
#pragma once
-namespace physx
-{
- class PxRigidActor;
- class PxTransform;
-}
-
///
/// A base interface for all physical actors types/owners that can responds on transformation changed event.
///
class FLAXENGINE_API IPhysicsActor
{
public:
-
///
/// Finalizes an instance of the class.
///
virtual ~IPhysicsActor() = default;
///
- /// Gets the rigid actor (PhysX object) may be null.
+ /// Gets the native physics backend object.
///
- /// PhysX rigid actor or null if not using
- virtual physx::PxRigidActor* GetRigidActor() = 0;
+ virtual void* GetPhysicsActor() const = 0;
///
- /// Called when actor's active transformation gets changed after the physics simulation step.
+ /// Called when actor's active transformation gets changed after the physics simulation step during.
///
///
/// This event is called internally by the Physics service and should not be used by the others.
///
- /// The current transformation.
- virtual void OnActiveTransformChanged(const physx::PxTransform& transform) = 0;
+ virtual void OnActiveTransformChanged() = 0;
};
diff --git a/Source/Engine/Physics/Actors/PhysicsActor.cpp b/Source/Engine/Physics/Actors/PhysicsActor.cpp
index 8e92ea902..b0adcf09d 100644
--- a/Source/Engine/Physics/Actors/PhysicsActor.cpp
+++ b/Source/Engine/Physics/Actors/PhysicsActor.cpp
@@ -1,10 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "PhysicsActor.h"
-#include "Engine/Physics/Utilities.h"
-#include "Engine/Physics/Physics.h"
-#include
-#include
+#include "../PhysicsBackend.h"
PhysicsActor::PhysicsActor(const SpawnParams& params)
: Actor(params)
@@ -13,28 +10,23 @@ PhysicsActor::PhysicsActor(const SpawnParams& params)
{
}
-void PhysicsActor::OnActiveTransformChanged(const PxTransform& transform)
+void PhysicsActor::OnActiveTransformChanged()
{
// Change actor transform (but with locking)
ASSERT(!_isUpdatingTransform);
_isUpdatingTransform = true;
- //SetTransform(Transform(P2C(transform.p), P2C(transform.q), GetScale()));
+ Transform transform;
+ PhysicsBackend::GetRigidActorPose(GetPhysicsActor(), transform.Translation, transform.Orientation);
+ transform.Scale = _transform.Scale;
+ if (_parent)
{
- Transform v;
- v.Translation = P2C(transform.p);
- v.Orientation = P2C(transform.q);
- v.Scale = _transform.Scale;
-
- if (_parent)
- {
- _parent->GetTransform().WorldToLocal(v, _localTransform);
- }
- else
- {
- _localTransform = v;
- }
- OnTransformChanged();
+ _parent->GetTransform().WorldToLocal(transform, _localTransform);
}
+ else
+ {
+ _localTransform = transform;
+ }
+ OnTransformChanged();
_isUpdatingTransform = false;
}
@@ -48,31 +40,11 @@ void PhysicsActor::OnTransformChanged()
void PhysicsActor::UpdateBounds()
{
- const auto actor = GetPhysXActor();
- const float boundsScale = 1.02f;
- if (actor && actor->getScene() != nullptr)
- {
- if (actor->is())
- {
- const auto rigidActor = (PxRigidActor*)actor;
- if (rigidActor->getNbShapes() != 0)
- {
- _box = P2C(actor->getWorldBounds(boundsScale));
- }
- else
- {
- _box = BoundingBox(_transform.Translation);
- }
- }
- else
- {
- _box = P2C(actor->getWorldBounds(boundsScale));
- }
- }
+ void* actor = GetPhysicsActor();
+ if (actor)
+ PhysicsBackend::GetActorBounds(actor, _box);
else
- {
_box = BoundingBox(_transform.Translation);
- }
BoundingSphere::FromBox(_box, _sphere);
}
diff --git a/Source/Engine/Physics/Actors/PhysicsActor.h b/Source/Engine/Physics/Actors/PhysicsActor.h
index 05e015074..07d7291e3 100644
--- a/Source/Engine/Physics/Actors/PhysicsActor.h
+++ b/Source/Engine/Physics/Actors/PhysicsActor.h
@@ -6,8 +6,6 @@
#include "Engine/Physics/Types.h"
#include "IPhysicsActor.h"
-class PhysicsScene;
-
///
/// A base class for all physical actors.
///
@@ -22,12 +20,6 @@ protected:
public:
- ///
- /// Gets the native PhysX actor object.
- ///
- /// The PhysX actor.
- virtual PxActor* GetPhysXActor() = 0;
-
///
/// Updates the bounding box.
///
@@ -39,7 +31,7 @@ public:
bool IntersectsItself(const Ray& ray, float& distance, Vector3& normal) override;
// [IPhysicsActor]
- void OnActiveTransformChanged(const PxTransform& transform) override;
+ void OnActiveTransformChanged() override;
protected:
diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp
index a3047889d..fc64113cc 100644
--- a/Source/Engine/Physics/Actors/RigidBody.cpp
+++ b/Source/Engine/Physics/Actors/RigidBody.cpp
@@ -1,19 +1,11 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "RigidBody.h"
-#include "PxMaterial.h"
-
#include "Engine/Core/Log.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Colliders/Collider.h"
-#include "Engine/Physics/Physics.h"
-#include "Engine/Physics/PhysicalMaterial.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Serialization/Serialization.h"
-#include
-#include
-#include
-#include
RigidBody::RigidBody(const SpawnParams& params)
: PhysicsActor(params)
@@ -39,52 +31,38 @@ void RigidBody::SetIsKinematic(const bool value)
{
if (value == GetIsKinematic())
return;
-
_isKinematic = value;
-
if (_actor)
- _actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, value);
+ PhysicsBackend::SetRigidDynamicActorFlag(_actor, PhysicsBackend::RigidDynamicFlags::Kinematic, value);
}
void RigidBody::SetLinearDamping(float value)
{
if (Math::NearEqual(value, _linearDamping))
return;
-
_linearDamping = value;
-
if (_actor)
- {
- _actor->setLinearDamping(value);
- }
+ PhysicsBackend::SetRigidDynamicActorLinearDamping(_actor, _linearDamping);
}
void RigidBody::SetAngularDamping(float value)
{
if (Math::NearEqual(value, _angularDamping))
return;
-
_angularDamping = value;
-
if (_actor)
- {
- _actor->setAngularDamping(value);
- }
+ PhysicsBackend::SetRigidDynamicActorAngularDamping(_actor, _angularDamping);
}
void RigidBody::SetEnableSimulation(bool value)
{
if (value == GetEnableSimulation())
return;
-
_enableSimulation = value;
-
if (_actor)
{
const bool isActive = _enableSimulation && IsActiveInHierarchy();
- _actor->setActorFlag(PxActorFlag::eDISABLE_SIMULATION, !isActive);
-
- // Auto wake up
+ PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoSimulation, !isActive);
if (isActive && GetStartAwake())
WakeUp();
}
@@ -94,24 +72,19 @@ void RigidBody::SetUseCCD(bool value)
{
if (value == GetUseCCD())
return;
-
_useCCD = value;
-
if (_actor)
- _actor->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, value);
+ PhysicsBackend::SetRigidDynamicActorFlag(_actor, PhysicsBackend::RigidDynamicFlags::CCD, value);
}
void RigidBody::SetEnableGravity(bool value)
{
if (value == GetEnableGravity())
return;
-
_enableGravity = value;
-
if (_actor)
{
- _actor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !value);
-
+ PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoGravity, !value);
if (value)
WakeUp();
}
@@ -131,11 +104,9 @@ void RigidBody::SetMaxAngularVelocity(float value)
{
if (Math::NearEqual(value, _maxAngularVelocity))
return;
-
_maxAngularVelocity = value;
-
if (_actor)
- _actor->setMaxAngularVelocity(value);
+ PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(_actor, _maxAngularVelocity);
}
bool RigidBody::GetOverrideMass() const
@@ -147,9 +118,7 @@ void RigidBody::SetOverrideMass(bool value)
{
if (value == GetOverrideMass())
return;
-
_overrideMass = value;
-
UpdateMass();
}
@@ -162,12 +131,8 @@ void RigidBody::SetMass(float value)
{
if (Math::NearEqual(value, _mass))
return;
-
_mass = value;
-
- // Auto enable override
_overrideMass = true;
-
UpdateMass();
}
@@ -180,7 +145,6 @@ void RigidBody::SetMassScale(float value)
{
if (Math::NearEqual(value, _massScale))
return;
-
_massScale = value;
UpdateMass();
}
@@ -189,163 +153,102 @@ void RigidBody::SetCenterOfMassOffset(const Vector3& value)
{
if (Vector3::NearEqual(value, _centerOfMassOffset))
return;
-
_centerOfMassOffset = value;
-
if (_actor)
- {
- PxTransform pose = _actor->getCMassLocalPose();
- pose.p += C2P(_centerOfMassOffset);
- _actor->setCMassLocalPose(pose);
- }
+ PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset);
}
void RigidBody::SetConstraints(const RigidbodyConstraints value)
{
if (value == _constraints)
return;
-
_constraints = value;
-
if (_actor)
- {
- _actor->setRigidDynamicLockFlags(static_cast(value));
- }
+ PhysicsBackend::SetRigidDynamicActorConstraints(_actor, value);
}
Vector3 RigidBody::GetLinearVelocity() const
{
- return _actor ? P2C(_actor->getLinearVelocity()) : Vector3::Zero;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorLinearVelocity(_actor) : Vector3::Zero;
}
void RigidBody::SetLinearVelocity(const Vector3& value) const
{
if (_actor)
- _actor->setLinearVelocity(C2P(value), GetStartAwake());
+ PhysicsBackend::SetRigidDynamicActorLinearVelocity(_actor, value, GetStartAwake());
}
Vector3 RigidBody::GetAngularVelocity() const
{
- return _actor ? P2C(_actor->getAngularVelocity()) : Vector3::Zero;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorAngularVelocity(_actor) : Vector3::Zero;
}
void RigidBody::SetAngularVelocity(const Vector3& value) const
{
if (_actor)
- _actor->setAngularVelocity(C2P(value), GetStartAwake());
+ PhysicsBackend::SetRigidDynamicActorAngularVelocity(_actor, value, GetStartAwake());
}
float RigidBody::GetMaxDepenetrationVelocity() const
{
- return _actor ? _actor->getMaxDepenetrationVelocity() : 0;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorMaxDepenetrationVelocity(_actor) : 0;
}
void RigidBody::SetMaxDepenetrationVelocity(const float value) const
{
if (_actor)
- _actor->setMaxDepenetrationVelocity(value);
+ PhysicsBackend::SetRigidDynamicActorMaxDepenetrationVelocity(_actor, value);
}
float RigidBody::GetSleepThreshold() const
{
- return _actor ? _actor->getSleepThreshold() : 0;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorSleepThreshold(_actor) : 0;
}
void RigidBody::SetSleepThreshold(const float value) const
{
if (_actor)
- _actor->setSleepThreshold(value);
+ PhysicsBackend::SetRigidDynamicActorSleepThreshold(_actor, value);
}
Vector3 RigidBody::GetCenterOfMass() const
{
- return _actor ? P2C(_actor->getCMassLocalPose().p) : Vector3::Zero;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorCenterOfMass(_actor) : Vector3::Zero;
}
bool RigidBody::IsSleeping() const
{
- return _actor ? _actor->isSleeping() : false;
+ return _actor ? PhysicsBackend::GetRigidDynamicActorIsSleeping(_actor) : false;
}
void RigidBody::Sleep() const
{
- if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy() && _actor->getScene())
- {
- _actor->putToSleep();
- }
+ if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy())
+ PhysicsBackend::GetRigidActorSleep(_actor);
}
void RigidBody::WakeUp() const
{
- if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy() && _actor->getScene())
- {
- _actor->wakeUp();
- }
+ if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy())
+ PhysicsBackend::GetRigidDynamicActorWakeUp(_actor);
}
void RigidBody::UpdateMass()
{
- if (_actor == nullptr)
- return;
-
- if (_overrideMass)
- {
- // Use fixed mass
- PxRigidBodyExt::setMassAndUpdateInertia(*_actor, Math::Max(_mass * _massScale, 0.001f));
- }
- else
- {
- // Calculate per-shape densities (convert kg/m^3 into engine units)
- const float minDensity = 0.08375f; // Hydrogen density
- const float defaultDensity = 1000.0f; // Water density
- Array> densities;
- for (uint32 i = 0; i < _actor->getNbShapes(); i++)
- {
- PxShape* shape;
- _actor->getShapes(&shape, 1, i);
- if (shape->getFlags() & PxShapeFlag::eSIMULATION_SHAPE)
- {
- float density = defaultDensity;
- PxMaterial* material;
- if (shape->getMaterials(&material, 1, 0) == 1)
- {
- if (const auto mat = (PhysicalMaterial*)material->userData)
- {
- density = Math::Max(mat->Density, minDensity);
- }
- }
- densities.Add(KgPerM3ToKgPerCm3(density));
- }
- }
- if (densities.IsEmpty())
- densities.Add(KgPerM3ToKgPerCm3(defaultDensity));
-
- // Auto calculated mass
- PxRigidBodyExt::updateMassAndInertia(*_actor, densities.Get(), densities.Count());
- _mass = _actor->getMass();
- const float massScale = Math::Max(_massScale, 0.001f);
- if (!Math::IsOne(massScale))
- {
- _mass *= massScale;
- _actor->setMass(_mass);
- }
- }
+ if (_actor)
+ PhysicsBackend::UpdateRigidDynamicActorMass(_actor, _mass, _massScale, _overrideMass == 0);
}
void RigidBody::AddForce(const Vector3& force, ForceMode mode) const
{
if (_actor && GetEnableSimulation())
- {
- _actor->addForce(C2P(force), static_cast(mode));
- }
+ PhysicsBackend::AddRigidDynamicActorForce(_actor, force, mode);
}
void RigidBody::AddForceAtPosition(const Vector3& force, const Vector3& position, ForceMode mode) const
{
if (_actor && GetEnableSimulation())
- {
- PxRigidBodyExt::addForceAtPos(*_actor, C2P(force), C2P(position), static_cast(mode));
- }
+ PhysicsBackend::AddRigidDynamicActorForceAtPosition(_actor, force, position, mode);
}
void RigidBody::AddRelativeForce(const Vector3& force, ForceMode mode) const
@@ -356,9 +259,7 @@ void RigidBody::AddRelativeForce(const Vector3& force, ForceMode mode) const
void RigidBody::AddTorque(const Vector3& torque, ForceMode mode) const
{
if (_actor && GetEnableSimulation())
- {
- _actor->addTorque(C2P(torque), static_cast(mode));
- }
+ PhysicsBackend::AddRigidDynamicActorTorque(_actor, torque, mode);
}
void RigidBody::AddRelativeTorque(const Vector3& torque, ForceMode mode) const
@@ -369,9 +270,7 @@ void RigidBody::AddRelativeTorque(const Vector3& torque, ForceMode mode) const
void RigidBody::SetSolverIterationCounts(int32 minPositionIters, int32 minVelocityIters) const
{
if (_actor)
- {
- _actor->setSolverIterationCounts(Math::Clamp(minPositionIters, 1, 255), Math::Clamp(minVelocityIters, 1, 255));
- }
+ PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(_actor, minPositionIters, minVelocityIters);
}
void RigidBody::ClosestPoint(const Vector3& position, Vector3& result) const
@@ -424,67 +323,6 @@ void RigidBody::OnColliderChanged(Collider* c)
// WakeUp();
}
-void RigidBody::CreateActor()
-{
- ASSERT(_actor == nullptr);
-
- // Create rigid body
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- _actor = CPhysX->createRigidDynamic(trans);
- _actor->userData = this;
-
- // Setup flags
-#if WITH_PVD
- PxActorFlags actorFlags = PxActorFlag::eVISUALIZATION;
-#else
- PxActorFlags actorFlags = static_cast(0);
-#endif
- const bool isActive = _enableSimulation && IsActiveInHierarchy();
- if (!isActive)
- actorFlags |= PxActorFlag::eDISABLE_SIMULATION;
- if (!_enableGravity)
- actorFlags |= PxActorFlag::eDISABLE_GRAVITY;
- _actor->setActorFlags(actorFlags);
- if (_useCCD)
- _actor->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, true);
- if (_isKinematic)
- _actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
-
- // Apply properties
- _actor->setLinearDamping(_linearDamping);
- _actor->setAngularDamping(_angularDamping);
- _actor->setMaxAngularVelocity(_maxAngularVelocity);
- _actor->setRigidDynamicLockFlags(static_cast(_constraints));
-
- // Find colliders to attach
- for (int32 i = 0; i < Children.Count(); i++)
- {
- auto collider = dynamic_cast(Children[i]);
- if (collider && collider->CanAttach(this))
- {
- collider->Attach(this);
- }
- }
-
- // Setup mass (calculate or use overriden value)
- UpdateMass();
-
- // Apply the Center Of Mass offset
- if (!_centerOfMassOffset.IsZero())
- {
- PxTransform pose = _actor->getCMassLocalPose();
- pose.p += C2P(_centerOfMassOffset);
- _actor->setCMassLocalPose(pose);
- }
-
- // Register actor
- const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy();
- GetPhysicsScene()->AddActor(_actor, putToSleep);
-
- // Update cached data
- UpdateBounds();
-}
-
void RigidBody::UpdateScale()
{
const Vector3 scale = GetScale();
@@ -546,19 +384,61 @@ void RigidBody::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
DESERIALIZE_BIT_MEMBER(UpdateMassWhenScaleChanges, _updateMassWhenScaleChanges);
}
-PxActor* RigidBody::GetPhysXActor()
+void* RigidBody::GetPhysicsActor() const
{
- return (PxActor*)_actor;
-}
-
-PxRigidActor* RigidBody::GetRigidActor()
-{
- return (PxRigidActor*)_actor;
+ return _actor;
}
void RigidBody::BeginPlay(SceneBeginData* data)
{
- CreateActor();
+ // Create rigid body
+ ASSERT(_actor == nullptr);
+ _actor = PhysicsBackend::CreateRigidDynamicActor(this, _transform.Translation, _transform.Orientation);
+
+ // Apply properties
+ auto actorFlags = PhysicsBackend::ActorFlags::None;
+ if (!_enableSimulation || !IsActiveInHierarchy())
+ actorFlags |= PhysicsBackend::ActorFlags::NoSimulation;
+ if (!_enableGravity)
+ actorFlags |= PhysicsBackend::ActorFlags::NoGravity;
+ PhysicsBackend::SetActorFlags(_actor, actorFlags);
+ auto rigidBodyFlags = PhysicsBackend::RigidDynamicFlags::None;
+ if (_isKinematic)
+ rigidBodyFlags |= PhysicsBackend::RigidDynamicFlags::Kinematic;
+ if (_useCCD)
+ rigidBodyFlags |= PhysicsBackend::RigidDynamicFlags::CCD;
+ PhysicsBackend::SetRigidDynamicActorFlags(_actor, rigidBodyFlags);
+ PhysicsBackend::SetRigidDynamicActorLinearDamping(_actor, _linearDamping);
+ PhysicsBackend::SetRigidDynamicActorAngularDamping(_actor, _angularDamping);
+ PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(_actor, _maxAngularVelocity);
+ PhysicsBackend::SetRigidDynamicActorConstraints(_actor, _constraints);
+
+ // Find colliders to attach
+ for (int32 i = 0; i < Children.Count(); i++)
+ {
+ auto collider = dynamic_cast(Children[i]);
+ if (collider && collider->CanAttach(this))
+ {
+ collider->Attach(this);
+ }
+ }
+
+ // Setup mass (calculate or use overriden value)
+ UpdateMass();
+
+ // Apply the Center Of Mass offset
+ if (!_centerOfMassOffset.IsZero())
+ PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset);
+
+ // Register actor
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _actor);
+ const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy();
+ if (putToSleep)
+ PhysicsBackend::AddSceneActorAction(scene, _actor, PhysicsBackend::ActionType::Sleep);
+
+ // Update cached data
+ UpdateBounds();
// Base
PhysicsActor::BeginPlay(data);
@@ -566,24 +446,15 @@ void RigidBody::BeginPlay(SceneBeginData* data)
void RigidBody::EndPlay()
{
- // Detach all the shapes
- PxShape* shapes[8];
- while (_actor && _actor->getNbShapes() > 0)
- {
- const uint32 count = _actor->getShapes(shapes, 8, 0);
- for (uint32 i = 0; i < count; i++)
- {
- _actor->detachShape(*shapes[i], false);
- }
- }
-
// Base
PhysicsActor::EndPlay();
if (_actor)
{
// Remove actor
- GetPhysicsScene()->RemoveActor(_actor);
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::RemoveSceneActor(scene, _actor);
+ PhysicsBackend::DestroyActor(_actor);
_actor = nullptr;
}
}
@@ -596,7 +467,7 @@ void RigidBody::OnActiveInTreeChanged()
if (_actor)
{
const bool isActive = _enableSimulation && IsActiveInHierarchy();
- _actor->setActorFlag(PxActorFlag::eDISABLE_SIMULATION, !isActive);
+ PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoSimulation, !isActive);
// Auto wake up
if (isActive && GetStartAwake())
@@ -615,11 +486,8 @@ void RigidBody::OnTransformChanged()
// Base (skip PhysicsActor call to optimize)
Actor::OnTransformChanged();
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- if (GetIsKinematic() && GetEnableSimulation())
- _actor->setKinematicTarget(trans);
- else
- _actor->setGlobalPose(trans, true);
+ const bool kinematic = GetIsKinematic() && GetEnableSimulation();
+ PhysicsBackend::SetRigidActorPose(_actor, _transform.Translation, _transform.Orientation, kinematic, true);
UpdateScale();
UpdateBounds();
@@ -633,12 +501,10 @@ void RigidBody::OnTransformChanged()
void RigidBody::OnPhysicsSceneChanged(PhysicsScene* previous)
{
- ASSERT(previous);
-
- PhysicsActor::OnPhysicsSceneChanged(previous);
-
- previous->UnlinkActor(_actor);
-
+ PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _actor);
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _actor);
const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy();
- GetPhysicsScene()->AddActor(_actor, putToSleep);
+ if (putToSleep)
+ PhysicsBackend::AddSceneActorAction(scene, _actor, PhysicsBackend::ActionType::Sleep);
}
diff --git a/Source/Engine/Physics/Actors/RigidBody.h b/Source/Engine/Physics/Actors/RigidBody.h
index 8726161da..04f253dba 100644
--- a/Source/Engine/Physics/Actors/RigidBody.h
+++ b/Source/Engine/Physics/Actors/RigidBody.h
@@ -6,6 +6,7 @@
#include "Engine/Physics/Collisions.h"
class PhysicsColliderActor;
+class Collider;
///
/// Physics simulation driven object.
@@ -16,7 +17,7 @@ API_CLASS() class FLAXENGINE_API RigidBody : public PhysicsActor
DECLARE_SCENE_OBJECT(RigidBody);
protected:
- PxRigidDynamic* _actor;
+ void* _actor;
Vector3 _cachedScale;
float _mass;
@@ -386,15 +387,6 @@ public:
///
API_FUNCTION() void UpdateMass();
- ///
- /// Gets the native PhysX rigid actor object.
- ///
- /// The PhysX dynamic rigid actor.
- FORCE_INLINE PxRigidDynamic* GetPhysXRigidActor() const
- {
- return _actor;
- }
-
///
/// Applies a force (or impulse) defined in the world space to the rigidbody at its center of mass.
///
@@ -547,11 +539,6 @@ public:
protected:
- ///
- /// Creates the physics actor.
- ///
- void CreateActor();
-
///
/// Updates the rigidbody scale dependent properties like mass (may be modified when actor transformation changes).
///
@@ -562,8 +549,7 @@ public:
// [PhysicsActor]
void Serialize(SerializeStream& stream, const void* otherObj) override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
- PxActor* GetPhysXActor() override;
- PxRigidActor* GetRigidActor() override;
+ void* GetPhysicsActor() const override;
protected:
diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp
index 5becca07e..886b6d6d4 100644
--- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp
+++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp
@@ -1,47 +1,15 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "WheeledVehicle.h"
-#include "Engine/Core/Log.h"
#include "Engine/Physics/Physics.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Level/Scene/Scene.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Serialization/Serialization.h"
#if USE_EDITOR
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Debug/DebugDraw.h"
#endif
-#if WITH_VEHICLE
-#include
-#include
-#include
-#include
-#include
-#include
-#endif
-
-#if WITH_VEHICLE
-extern void InitVehicleSDK();
-#endif
-
-namespace
-{
- void FreeDrive(WheeledVehicle::DriveTypes driveType, PxVehicleWheels* drive)
- {
- switch (driveType)
- {
- case WheeledVehicle::DriveTypes::Drive4W:
- ((PxVehicleDrive4W*)drive)->free();
- break;
- case WheeledVehicle::DriveTypes::DriveNW:
- ((PxVehicleDriveNW*)drive)->free();
- break;
- case WheeledVehicle::DriveTypes::NoDrive:
- ((PxVehicleNoDrive*)drive)->free();
- break;
- }
- }
-}
WheeledVehicle::WheeledVehicle(const SpawnParams& params)
: RigidBody(params)
@@ -101,12 +69,8 @@ WheeledVehicle::GearboxSettings WheeledVehicle::GetGearbox() const
void WheeledVehicle::SetGearbox(const GearboxSettings& value)
{
#if WITH_VEHICLE
- auto& drive = (PxVehicleDrive*&)_drive;
- if (drive)
- {
- drive->mDriveDynData.setUseAutoGears(value.AutoGear);
- drive->mDriveDynData.setAutoBoxSwitchTime(Math::Max(value.SwitchTime, 0.0f));
- }
+ if (_vehicle)
+ PhysicsBackend::SetVehicleGearbox(_vehicle, &value);
#endif
_gearbox = value;
}
@@ -142,8 +106,7 @@ void WheeledVehicle::ClearInput()
float WheeledVehicle::GetForwardSpeed() const
{
#if WITH_VEHICLE
- auto& drive = (const PxVehicleWheels*&)_drive;
- return drive ? drive->computeForwardSpeed() : 0.0f;
+ return _vehicle ? PhysicsBackend::GetVehicleForwardSpeed(_vehicle) : 0.0f;
#else
return 0.0f;
#endif
@@ -152,8 +115,7 @@ float WheeledVehicle::GetForwardSpeed() const
float WheeledVehicle::GetSidewaysSpeed() const
{
#if WITH_VEHICLE
- auto& drive = (const PxVehicleWheels*&)_drive;
- return drive ? drive->computeSidewaysSpeed() : 0.0f;
+ return _vehicle ? PhysicsBackend::GetVehicleSidewaysSpeed(_vehicle) : 0.0f;
#else
return 0.0f;
#endif
@@ -162,8 +124,7 @@ float WheeledVehicle::GetSidewaysSpeed() const
float WheeledVehicle::GetEngineRotationSpeed() const
{
#if WITH_VEHICLE
- auto& drive = (const PxVehicleDrive*&)_drive;
- return drive && _driveType != DriveTypes::NoDrive ? RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed()) : 0.0f;
+ return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleEngineRotationSpeed(_vehicle) : 0.0f;
#else
return 0.0f;
#endif
@@ -172,8 +133,7 @@ float WheeledVehicle::GetEngineRotationSpeed() const
int32 WheeledVehicle::GetCurrentGear() const
{
#if WITH_VEHICLE
- auto& drive = (const PxVehicleDrive*&)_drive;
- return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getCurrentGear() - 1 : 0;
+ return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleCurrentGear(_vehicle) : 0;
#else
return 0;
#endif
@@ -182,19 +142,15 @@ int32 WheeledVehicle::GetCurrentGear() const
void WheeledVehicle::SetCurrentGear(int32 value)
{
#if WITH_VEHICLE
- auto& drive = (PxVehicleDrive*&)_drive;
- if (drive && _driveType != DriveTypes::NoDrive)
- {
- drive->mDriveDynData.forceGearChange((PxU32)(value + 1));
- }
+ if (_vehicle && _driveType != DriveTypes::NoDrive)
+ PhysicsBackend::SetVehicleCurrentGear(_vehicle, value);
#endif
}
int32 WheeledVehicle::GetTargetGear() const
{
#if WITH_VEHICLE
- auto& drive = (const PxVehicleDrive*&)_drive;
- return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getTargetGear() - 1 : 0;
+ return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleTargetGear(_vehicle) : 0;
#else
return 0;
#endif
@@ -203,11 +159,8 @@ int32 WheeledVehicle::GetTargetGear() const
void WheeledVehicle::SetTargetGear(int32 value)
{
#if WITH_VEHICLE
- auto& drive = (PxVehicleDrive*&)_drive;
- if (drive && _driveType != DriveTypes::NoDrive)
- {
- drive->mDriveDynData.startGearChange((PxU32)(value + 1));
- }
+ if (_vehicle && _driveType != DriveTypes::NoDrive)
+ PhysicsBackend::SetVehicleTargetGear(_vehicle, value);
#endif
}
@@ -232,281 +185,25 @@ void WheeledVehicle::Setup()
#if WITH_VEHICLE
if (!_actor || !IsDuringPlay())
return;
- auto& drive = (PxVehicleWheels*&)_drive;
// Release previous
- if (drive)
+ if (_vehicle)
{
- GetPhysicsScene()->RemoveWheeledVehicle(this);
- FreeDrive(_driveTypeCurrent, drive);
- drive = nullptr;
+ PhysicsBackend::RemoveVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
+ PhysicsBackend::DestroyVehicle(_vehicle, (int32)_driveTypeCurrent);
+ _vehicle = nullptr;
}
- // Get wheels
- Array> wheels;
+ // Create a new one
_wheelsData.Clear();
- for (auto& wheel : _wheels)
- {
- if (!wheel.Collider)
- {
- LOG(Warning, "Missing wheel collider in vehicle {0}", ToString());
- continue;
- }
- if (wheel.Collider->GetParent() != this)
- {
- LOG(Warning, "Invalid wheel collider {1} in vehicle {0} attached to {2} (wheels needs to be added as children to vehicle)", ToString(), wheel.Collider->ToString(), wheel.Collider->GetParent() ? wheel.Collider->GetParent()->ToString() : String::Empty);
- continue;
- }
- if (wheel.Collider->GetIsTrigger())
- {
- LOG(Warning, "Invalid wheel collider {1} in vehicle {0} cannot be a trigger", ToString(), wheel.Collider->ToString());
- continue;
- }
- if (wheel.Collider->IsDuringPlay())
- {
- wheels.Add(&wheel);
- }
- }
- if (wheels.IsEmpty())
- {
- // No wheel, no car
- // No woman, no cry
+ _vehicle = PhysicsBackend::CreateVehicle(this);
+ if (!_vehicle)
return;
- }
- _wheelsData.Resize(wheels.Count());
-
- InitVehicleSDK();
-
- // Get linked shapes for the wheels mapping
- Array> shapes;
- shapes.Resize(_actor->getNbShapes());
- _actor->getShapes(shapes.Get(), shapes.Count(), 0);
- const PxTransform centerOfMassOffset = _actor->getCMassLocalPose();
-
- // Initialize wheels simulation data
- PxVec3 offsets[PX_MAX_NB_WHEELS];
- for (int32 i = 0; i < wheels.Count(); i++)
- {
- Wheel& wheel = *wheels[i];
- offsets[i] = C2P(wheel.Collider->GetLocalPosition());
- }
- PxF32 sprungMasses[PX_MAX_NB_WHEELS];
- const float mass = _actor->getMass();
- PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses);
- PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
- for (int32 i = 0; i < wheels.Count(); i++)
- {
- Wheel& wheel = *wheels[i];
-
- auto& data = _wheelsData[i];
- data.Collider = wheel.Collider;
- data.LocalOrientation = wheel.Collider->GetLocalOrientation();
-
- PxVehicleSuspensionData suspensionData;
- const float suspensionFrequency = 7.0f;
- suspensionData.mMaxCompression = wheel.SuspensionMaxRaise;
- suspensionData.mMaxDroop = wheel.SuspensionMaxDrop;
- suspensionData.mSprungMass = sprungMasses[i];
- suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass;
- suspensionData.mSpringDamperRate = wheel.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass);
-
- PxVehicleTireData tire;
- tire.mType = 0;
- tire.mLatStiffX = wheel.TireLateralMax;
- tire.mLatStiffY = wheel.TireLateralStiffness;
- tire.mLongitudinalStiffnessPerUnitGravity = wheel.TireLongitudinalStiffness;
-
- PxVehicleWheelData wheelData;
- wheelData.mMass = wheel.Mass;
- wheelData.mRadius = wheel.Radius;
- wheelData.mWidth = wheel.Width;
- wheelData.mMOI = 0.5f * wheelData.mMass * Math::Square(wheelData.mRadius);
- wheelData.mDampingRate = M2ToCm2(wheel.DampingRate);
- wheelData.mMaxSteer = wheel.MaxSteerAngle * DegreesToRadians;
- wheelData.mMaxBrakeTorque = M2ToCm2(wheel.MaxBrakeTorque);
- wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque);
-
- PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]);
- PxVec3 forceAppPointOffset(centreOffset.x, wheel.SuspensionForceOffset, centreOffset.z);
-
- wheelsSimData->setTireData(i, tire);
- wheelsSimData->setWheelData(i, wheelData);
- wheelsSimData->setSuspensionData(i, suspensionData);
- wheelsSimData->setSuspTravelDirection(i, centerOfMassOffset.rotate(PxVec3(0.0f, -1.0f, 0.0f)));
- wheelsSimData->setWheelCentreOffset(i, centreOffset);
- wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset);
- wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset);
- wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1);
- wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f);
-
- PxShape* wheelShape = wheel.Collider->GetPxShape();
- if (wheel.Collider->IsActiveInHierarchy())
- {
- wheelsSimData->setWheelShapeMapping(i, shapes.Find(wheelShape));
-
- // Setup Vehicle ID inside word3 for suspension raycasts to ignore self
- PxFilterData filter = wheelShape->getQueryFilterData();
- filter.word3 = _id.D + 1;
- wheelShape->setQueryFilterData(filter);
- wheelShape->setSimulationFilterData(filter);
- wheelsSimData->setSceneQueryFilterData(i, filter);
-
- // Remove wheels from the simulation (suspension force hold the vehicle)
- wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
- }
- else
- {
- wheelsSimData->setWheelShapeMapping(i, -1);
- wheelsSimData->disableWheel(i);
- }
- }
- for (auto child : Children)
- {
- auto collider = Cast(child);
- if (collider && collider->GetAttachedRigidBody() == this)
- {
- bool isWheel = false;
- for (auto& w : wheels)
- {
- if (w->Collider == collider)
- {
- isWheel = true;
- break;
- }
- }
- if (!isWheel)
- {
- // Setup Vehicle ID inside word3 for suspension raycasts to ignore self
- PxShape* shape = collider->GetPxShape();
- PxFilterData filter = shape->getQueryFilterData();
- filter.word3 = _id.D + 1;
- shape->setQueryFilterData(filter);
- shape->setSimulationFilterData(filter);
- }
- }
- }
-
- // Initialize vehicle drive
_driveTypeCurrent = _driveType;
- switch (_driveType)
- {
- case DriveTypes::Drive4W:
- {
- PxVehicleDriveSimData4W driveSimData;
-
- // Differential
- PxVehicleDifferential4WData diff;
- diff.mType = (PxVehicleDifferential4WData::Enum)_differential.Type;
- diff.mFrontRearSplit = _differential.FrontRearSplit;
- diff.mFrontLeftRightSplit = _differential.FrontLeftRightSplit;
- diff.mRearLeftRightSplit = _differential.RearLeftRightSplit;
- diff.mCentreBias = _differential.CentreBias;
- diff.mFrontBias = _differential.FrontBias;
- diff.mRearBias = _differential.RearBias;
- driveSimData.setDiffData(diff);
-
- // Engine
- PxVehicleEngineData engine;
- engine.mMOI = M2ToCm2(_engine.MOI);
- engine.mPeakTorque = M2ToCm2(_engine.MaxTorque);
- engine.mMaxOmega = RpmToRadPerS(_engine.MaxRotationSpeed);
- engine.mDampingRateFullThrottle = M2ToCm2(0.15f);
- engine.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f);
- engine.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f);
- driveSimData.setEngineData(engine);
-
- // Gears
- PxVehicleGearsData gears;
- gears.mSwitchTime = Math::Max(_gearbox.SwitchTime, 0.0f);
- driveSimData.setGearsData(gears);
-
- // Auto Box
- PxVehicleAutoBoxData autoBox;
- driveSimData.setAutoBoxData(autoBox);
-
- // Clutch
- PxVehicleClutchData clutch;
- clutch.mStrength = M2ToCm2(_gearbox.ClutchStrength);
- driveSimData.setClutchData(clutch);
-
- // Ackermann steer accuracy
- PxVehicleAckermannGeometryData ackermann;
- ackermann.mAxleSeparation = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).x - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).x);
- ackermann.mFrontWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z);
- ackermann.mRearWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z);
- driveSimData.setAckermannGeometryData(ackermann);
-
- // Create vehicle drive
- auto drive4W = PxVehicleDrive4W::allocate(wheels.Count());
- drive4W->setup(CPhysX, _actor, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0));
- drive4W->setToRestState();
- drive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
- drive4W->mDriveDynData.setUseAutoGears(_gearbox.AutoGear);
- drive = drive4W;
- break;
- }
- case DriveTypes::DriveNW:
- {
- PxVehicleDriveSimDataNW driveSimData;
-
- // Differential
- PxVehicleDifferentialNWData diff;
- for (int32 i = 0; i < wheels.Count(); i++)
- diff.setDrivenWheel(i, true);
- driveSimData.setDiffData(diff);
-
- // Engine
- PxVehicleEngineData engine;
- engine.mMOI = M2ToCm2(_engine.MOI);
- engine.mPeakTorque = M2ToCm2(_engine.MaxTorque);
- engine.mMaxOmega = RpmToRadPerS(_engine.MaxRotationSpeed);
- engine.mDampingRateFullThrottle = M2ToCm2(0.15f);
- engine.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f);
- engine.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f);
- driveSimData.setEngineData(engine);
-
- // Gears
- PxVehicleGearsData gears;
- gears.mSwitchTime = Math::Max(_gearbox.SwitchTime, 0.0f);
- driveSimData.setGearsData(gears);
-
- // Auto Box
- PxVehicleAutoBoxData autoBox;
- driveSimData.setAutoBoxData(autoBox);
-
- // Clutch
- PxVehicleClutchData clutch;
- clutch.mStrength = M2ToCm2(_gearbox.ClutchStrength);
- driveSimData.setClutchData(clutch);
-
- // Create vehicle drive
- auto driveNW = PxVehicleDriveNW::allocate(wheels.Count());
- driveNW->setup(CPhysX, _actor, *wheelsSimData, driveSimData, wheels.Count());
- driveNW->setToRestState();
- driveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
- driveNW->mDriveDynData.setUseAutoGears(_gearbox.AutoGear);
- drive = driveNW;
- break;
- }
- case DriveTypes::NoDrive:
- {
- // Create vehicle drive
- auto driveNo = PxVehicleNoDrive::allocate(wheels.Count());
- driveNo->setup(CPhysX, _actor, *wheelsSimData);
- driveNo->setToRestState();
- drive = driveNo;
- break;
- }
- default:
- CRASH;
- }
-
- GetPhysicsScene()->AddWheeledVehicle(this);
- wheelsSimData->free();
- _actor->setSolverIterationCounts(12, 4);
-
+ PhysicsBackend::AddVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
+ PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(_actor, 12, 4);
#else
- LOG(Fatal, "PhysX Vehicle SDK is not supported.");
+ LOG(Fatal, "Vehicles are not supported.");
#endif
}
@@ -560,9 +257,12 @@ void WheeledVehicle::OnDebugDrawSelected()
{
const Vector3 currentPos = wheel.Collider->GetPosition();
const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0);
+ Transform actorPose = Transform::Identity, shapePose = Transform::Identity;
+ PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation);
+ PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, false);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false);
- DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(P2C(_actor->getGlobalPose().transform(wheel.Collider->GetPxShape()->getLocalPose()).p), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false);
+ DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(actorPose.LocalToWorld(shapePose.Translation), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false);
DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false);
DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false);
if (!data.State.SuspensionTraceStart.IsZero())
@@ -625,8 +325,10 @@ void WheeledVehicle::OnPhysicsSceneChanged(PhysicsScene* previous)
{
RigidBody::OnPhysicsSceneChanged(previous);
- previous->RemoveWheeledVehicle(this);
- GetPhysicsScene()->AddWheeledVehicle(this);
+#if WITH_VEHICLE
+ PhysicsBackend::RemoveVehicle(previous->GetPhysicsScene(), this);
+ PhysicsBackend::AddVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
+#endif
}
void WheeledVehicle::BeginPlay(SceneBeginData* data)
@@ -649,13 +351,12 @@ void WheeledVehicle::EndPlay()
#endif
#if WITH_VEHICLE
- auto& drive = (PxVehicleWheels*&)_drive;
- if (drive)
+ if (_vehicle)
{
// Parkway Drive
- GetPhysicsScene()->RemoveWheeledVehicle(this);
- FreeDrive(_driveTypeCurrent, drive);
- drive = nullptr;
+ PhysicsBackend::RemoveVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
+ PhysicsBackend::DestroyVehicle(_vehicle, (int32)_driveTypeCurrent);
+ _vehicle = nullptr;
}
#endif
diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h
index cd3ef88f4..78e1ea9bb 100644
--- a/Source/Engine/Physics/Actors/WheeledVehicle.h
+++ b/Source/Engine/Physics/Actors/WheeledVehicle.h
@@ -6,17 +6,14 @@
#include "Engine/Physics/Colliders/Collider.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
-class PhysicsScene;
-
///
/// Representation of the car vehicle that uses wheels. Built on top of the RigidBody with collider representing its chassis shape and wheels.
///
///
API_CLASS() class FLAXENGINE_API WheeledVehicle : public RigidBody
{
- friend PhysicsScene;
+ friend class PhysicsBackend;
DECLARE_SCENE_OBJECT(WheeledVehicle);
-public:
///
/// Vehicle driving mode types.
@@ -319,7 +316,7 @@ private:
WheelState State;
};
- void* _drive = nullptr;
+ void* _vehicle = nullptr;
DriveTypes _driveType = DriveTypes::Drive4W, _driveTypeCurrent;
Array> _wheelsData;
float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f;
diff --git a/Source/Engine/Physics/Colliders/BoxCollider.cpp b/Source/Engine/Physics/Colliders/BoxCollider.cpp
index 3473b5961..e3d1cd2be 100644
--- a/Source/Engine/Physics/Colliders/BoxCollider.cpp
+++ b/Source/Engine/Physics/Colliders/BoxCollider.cpp
@@ -2,8 +2,7 @@
#include "BoxCollider.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
BoxCollider::BoxCollider(const SpawnParams& params)
: Collider(params)
@@ -134,11 +133,11 @@ void BoxCollider::UpdateBounds()
BoundingSphere::FromBox(_box, _sphere);
}
-void BoxCollider::GetGeometry(PxGeometryHolder& geometry)
+void BoxCollider::GetGeometry(CollisionShape& collision)
{
Vector3 size = _size * _cachedScale;
size.Absolute();
const float minSize = 0.001f;
- const PxBoxGeometry box(Math::Max(size.X * 0.5f, minSize), Math::Max(size.Y * 0.5f, minSize), Math::Max(size.Z * 0.5f, minSize));
- geometry.storeAny(box);
+ size = Vector3::Max(size * 0.5f, Vector3(minSize));
+ collision.SetBox(size.Raw);
}
diff --git a/Source/Engine/Physics/Colliders/BoxCollider.h b/Source/Engine/Physics/Colliders/BoxCollider.h
index 89850b101..26b190ee2 100644
--- a/Source/Engine/Physics/Colliders/BoxCollider.h
+++ b/Source/Engine/Physics/Colliders/BoxCollider.h
@@ -62,7 +62,7 @@ protected:
// [Collider]
void UpdateBounds() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
+ void GetGeometry(CollisionShape& collision) override;
#if USE_EDITOR
void DrawPhysicsDebug(RenderView& view) override;
#endif
diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
index 916c2b34b..065164f08 100644
--- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
+++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
@@ -2,8 +2,6 @@
#include "CapsuleCollider.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
CapsuleCollider::CapsuleCollider(const SpawnParams& params)
: Collider(params)
@@ -106,12 +104,11 @@ void CapsuleCollider::UpdateBounds()
BoundingSphere::FromBox(_box, _sphere);
}
-void CapsuleCollider::GetGeometry(PxGeometryHolder& geometry)
+void CapsuleCollider::GetGeometry(CollisionShape& collision)
{
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
- const PxCapsuleGeometry capsule(radius, height * 0.5f);
- geometry.storeAny(capsule);
+ collision.SetCapsule(radius, height * 0.5f);
}
diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.h b/Source/Engine/Physics/Colliders/CapsuleCollider.h
index 9e133dd7a..d55910f77 100644
--- a/Source/Engine/Physics/Colliders/CapsuleCollider.h
+++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h
@@ -77,7 +77,7 @@ protected:
// [Collider]
void UpdateBounds() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
+ void GetGeometry(CollisionShape& collision) override;
#if USE_EDITOR
void DrawPhysicsDebug(RenderView& view) override;
#endif
diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp
index 52324c98b..cc8e3e852 100644
--- a/Source/Engine/Physics/Colliders/CharacterController.cpp
+++ b/Source/Engine/Physics/Colliders/CharacterController.cpp
@@ -1,18 +1,12 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "CharacterController.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Colliders/Collider.h"
#include "Engine/Physics/Physics.h"
+#include "Engine/Physics/PhysicsBackend.h"
+#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Engine/Time.h"
-#include "Engine/Physics/PhysicalMaterial.h"
-#include "Engine/Physics/PhysicsScene.h"
-#include
-#include
-#include
-#include
-#include
CharacterController::CharacterController(const SpawnParams& params)
: Collider(params)
@@ -27,7 +21,6 @@ CharacterController::CharacterController(const SpawnParams& params)
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
, _lastFlags(CollisionFlags::None)
{
- static_assert(sizeof(_filterData) == sizeof(PxFilterData), "Invalid filter data size.");
}
float CharacterController::GetRadius() const
@@ -72,11 +65,9 @@ void CharacterController::SetSlopeLimit(float value)
value = Math::Clamp(value, 0.0f, 89.0f);
if (Math::NearEqual(value, _slopeLimit))
return;
-
_slopeLimit = value;
-
if (_controller)
- _controller->setSlopeLimit(Math::Cos(value * DegreesToRadians));
+ PhysicsBackend::SetControllerSlopeLimit(_controller, value);
}
CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode() const
@@ -86,10 +77,11 @@ CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode()
void CharacterController::SetNonWalkableMode(NonWalkableModes value)
{
+ if (_nonWalkableMode == value)
+ return;
_nonWalkableMode = value;
-
if (_controller)
- _controller->setNonWalkableMode(static_cast(value));
+ PhysicsBackend::SetControllerNonWalkableMode(_controller, (int32)value);
}
float CharacterController::GetStepOffset() const
@@ -111,15 +103,15 @@ void CharacterController::SetStepOffset(float value)
const float minSize = 0.001f;
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, minSize);
- _controller->setStepOffset(Math::Min(value, height + radius * 2.0f - minSize));
+ PhysicsBackend::SetControllerStepOffset(_controller, Math::Min(value, height + radius * 2.0f - minSize));
}
}
void CharacterController::SetUpDirection(const Vector3& up)
{
- if (_controller)
- _controller->setUpDirection(C2P(up));
_upDirection = up;
+ if (_controller)
+ PhysicsBackend::SetControllerUpDirection(_controller, up);
}
float CharacterController::GetMinMoveDistance() const
@@ -129,7 +121,7 @@ float CharacterController::GetMinMoveDistance() const
Vector3 CharacterController::GetUpDirection() const
{
- return _controller ? P2C(_controller->getUpDirection()) : _upDirection;
+ return _controller ? PhysicsBackend::GetControllerUpDirection(_controller) : _upDirection;
}
void CharacterController::SetMinMoveDistance(float value)
@@ -139,7 +131,7 @@ void CharacterController::SetMinMoveDistance(float value)
Vector3 CharacterController::GetVelocity() const
{
- return _controller ? P2C(_controller->getActor()->getLinearVelocity()) : Vector3::Zero;
+ return _controller ? PhysicsBackend::GetRigidDynamicActorLinearVelocity(PhysicsBackend::GetControllerRigidDynamicActor(_controller)) : Vector3::Zero;
}
bool CharacterController::IsGrounded() const
@@ -165,30 +157,16 @@ CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector
CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement)
{
CollisionFlags result = CollisionFlags::None;
-
if (_controller)
{
const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds();
- PxControllerFilters filters;
- filters.mFilterData = (PxFilterData*)&_filterData;
- filters.mFilterCallback = GetPhysicsScene()->GetCharacterQueryFilterCallback();
- filters.mFilterFlags = PxQueryFlag::eDYNAMIC | PxQueryFlag::eSTATIC | PxQueryFlag::ePREFILTER;
- filters.mCCTFilterCallback = GetPhysicsScene()->GetCharacterControllerFilterCallback();
-
- result = (CollisionFlags)(byte)_controller->move(C2P(displacement), _minMoveDistance, deltaTime, filters);
+ result = (CollisionFlags)PhysicsBackend::MoveController(_controller, _shape, displacement, _minMoveDistance, deltaTime);
_lastFlags = result;
-
- SetPosition(P2C(_controller->getPosition()));
+ SetPosition(PhysicsBackend::GetControllerPosition(_controller));
}
-
return result;
}
-PxRigidDynamic* CharacterController::GetPhysXRigidActor() const
-{
- return _controller ? _controller->getActor() : nullptr;
-}
-
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
@@ -222,41 +200,16 @@ void CharacterController::OnDebugDrawSelected()
void CharacterController::CreateController()
{
+ // Create controller
ASSERT(_controller == nullptr && _shape == nullptr);
-
- PxCapsuleControllerDesc desc;
- desc.userData = this;
- desc.contactOffset = Math::Max(_contactOffset, ZeroTolerance);
- desc.position = PxExtendedVec3(_transform.Translation.X, _transform.Translation.Y, _transform.Translation.Z);
- desc.slopeLimit = Math::Cos(_slopeLimit * DegreesToRadians);
- desc.nonWalkableMode = static_cast(_nonWalkableMode);
- desc.climbingMode = PxCapsuleClimbingMode::eEASY;
- if (Material && !Material->WaitForLoaded())
- desc.material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial();
- else
- desc.material = Physics::GetDefaultMaterial();
_cachedScale = GetScale();
const float scaling = _cachedScale.GetAbsolute().MaxValue();
- const float minSize = 0.001f;
- desc.height = Math::Max(Math::Abs(_height) * scaling, minSize);
- desc.radius = Math::Max(Math::Abs(_radius) * scaling - desc.contactOffset, minSize);
- desc.stepOffset = Math::Min(_stepOffset, desc.height + desc.radius * 2.0f - minSize);
+ _controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, _transform.Translation, _slopeLimit, (int32)_nonWalkableMode, Material.Get(), Math::Abs(_radius) * scaling, Math::Abs(_height) * scaling, _stepOffset, _shape);
- // Create controller
- _controller = (PxCapsuleController*)GetPhysicsScene()->GetControllerManager()->createController(desc);
- ASSERT(_controller);
- _controller->setUpDirection(C2P(_upDirection));
- const auto actor = _controller->getActor();
- ASSERT(actor && actor->getNbShapes() == 1);
- actor->getShapes(&_shape, 1);
- actor->userData = this;
- _shape->userData = this;
-
- // Apply additional shape properties
- _shape->setLocalPose(PxTransform(C2P(_center)));
+ // Setup
+ PhysicsBackend::SetControllerUpDirection(_shape, _upDirection);
+ PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity);
UpdateLayerBits();
-
- // Update cached data
UpdateBounds();
}
@@ -264,12 +217,10 @@ void CharacterController::DeleteController()
{
if (_controller)
{
- _shape->userData = nullptr;
- _controller->getActor()->userData = nullptr;
- _controller->release();
+ PhysicsBackend::DestroyController(_controller);
_controller = nullptr;
+ _shape = nullptr;
}
- _shape = nullptr;
}
void CharacterController::UpdateSize() const
@@ -280,9 +231,7 @@ void CharacterController::UpdateSize() const
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
-
- _controller->setRadius(radius);
- _controller->resize(height);
+ PhysicsBackend::SetControllerSize(_controller, radius, height);
}
}
@@ -293,10 +242,9 @@ void CharacterController::CreateShape()
void CharacterController::UpdateBounds()
{
- const auto actor = GetPhysXRigidActor();
- const float boundsScale = 1.03f;
+ void* actor = PhysicsBackend::GetShapeActor(_shape);
if (actor)
- _box = P2C(actor->getWorldBounds(boundsScale));
+ PhysicsBackend::GetActorBounds(actor, _box);
else
_box = BoundingBox(_transform.Translation);
BoundingSphere::FromBox(_box, _sphere);
@@ -322,22 +270,24 @@ RigidBody* CharacterController::GetAttachedRigidBody() const
return nullptr;
}
-void CharacterController::OnActiveTransformChanged(const PxTransform& transform)
+void CharacterController::OnActiveTransformChanged()
{
// Change actor transform (but with locking)
ASSERT(!_isUpdatingTransform);
_isUpdatingTransform = true;
- Transform t = _transform;
- t.Translation = P2C(transform.p);
- SetTransform(t);
+ Transform transform;
+ PhysicsBackend::GetRigidActorPose(PhysicsBackend::GetShapeActor(_shape), transform.Translation, transform.Orientation);
+ transform.Orientation = _transform.Orientation;
+ transform.Scale = _transform.Scale;
+ SetTransform(transform);
_isUpdatingTransform = false;
UpdateBounds();
}
-PxRigidActor* CharacterController::GetRigidActor()
+void* CharacterController::GetPhysicsActor() const
{
- return _shape ? _shape->getActor() : nullptr;
+ return _shape ? PhysicsBackend::GetShapeActor(_shape) : nullptr;
}
void CharacterController::UpdateGeometry()
@@ -351,20 +301,11 @@ void CharacterController::UpdateGeometry()
UpdateSize();
}
-void CharacterController::GetGeometry(PxGeometryHolder& geometry)
+void CharacterController::GetGeometry(CollisionShape& collision)
{
// Unused
}
-void CharacterController::UpdateLayerBits()
-{
- // Base
- Collider::UpdateLayerBits();
-
- // Cache filter data
- *(PxFilterData*)&_filterData = _shape->getSimulationFilterData();
-}
-
void CharacterController::BeginPlay(SceneBeginData* data)
{
if (IsActiveInHierarchy())
@@ -418,9 +359,7 @@ void CharacterController::OnTransformChanged()
// Update physics
if (!_isUpdatingTransform && _controller)
{
- const PxExtendedVec3 pos(_transform.Translation.X, _transform.Translation.Y, _transform.Translation.Z);
- _controller->setPosition(pos);
-
+ PhysicsBackend::SetControllerPosition(_controller, _transform.Translation);
const Vector3 scale = GetScale();
if (!Vector3::NearEqual(_cachedScale, scale))
UpdateGeometry();
diff --git a/Source/Engine/Physics/Colliders/CharacterController.h b/Source/Engine/Physics/Colliders/CharacterController.h
index 8a0a79223..129a432e6 100644
--- a/Source/Engine/Physics/Colliders/CharacterController.h
+++ b/Source/Engine/Physics/Colliders/CharacterController.h
@@ -58,7 +58,7 @@ public:
private:
- PxCapsuleController* _controller;
+ void* _controller;
float _stepOffset;
float _slopeLimit;
float _radius;
@@ -68,7 +68,6 @@ private:
Vector3 _upDirection;
NonWalkableModes _nonWalkableMode;
CollisionFlags _lastFlags;
- uint32 _filterData[4];
public:
///
@@ -181,11 +180,6 @@ public:
/// The collision flags. It can be used to trigger various character animations.
API_FUNCTION() CollisionFlags Move(const Vector3& displacement);
- ///
- /// Gets the native PhysX rigid actor object.
- ///
- PxRigidDynamic* GetPhysXRigidActor() const;
-
protected:
///
@@ -218,15 +212,14 @@ public:
RigidBody* GetAttachedRigidBody() const override;
// [IPhysicsActor]
- void OnActiveTransformChanged(const PxTransform& transform) override;
- PxRigidActor* GetRigidActor() override;
+ void OnActiveTransformChanged() override;
+ void* GetPhysicsActor() const override;
protected:
// [PhysicsActor]
void UpdateGeometry() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
- void UpdateLayerBits() override;
+ void GetGeometry(CollisionShape& collision) override;
void BeginPlay(SceneBeginData* data) override;
void EndPlay() override;
#if USE_EDITOR
diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp
index 73440c5b3..6d971dc52 100644
--- a/Source/Engine/Physics/Colliders/Collider.cpp
+++ b/Source/Engine/Physics/Colliders/Collider.cpp
@@ -6,18 +6,11 @@
#include "Engine/Level/Scene/SceneRendering.h"
#endif
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/PhysicsSettings.h"
#include "Engine/Physics/Physics.h"
-#include "Engine/Physics/PhysicalMaterial.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Physics/Actors/RigidBody.h"
-#include
-#include
-#include
-#include
-#include
-#include
Collider::Collider(const SpawnParams& params)
: PhysicsColliderActor(params)
@@ -31,7 +24,7 @@ Collider::Collider(const SpawnParams& params)
Material.Changed.Bind(this);
}
-PxShape* Collider::GetPxShape() const
+void* Collider::GetPhysicsShape() const
{
return _shape;
}
@@ -40,33 +33,24 @@ void Collider::SetIsTrigger(bool value)
{
if (value == _isTrigger || !CanBeTrigger())
return;
-
_isTrigger = value;
-
if (_shape)
- {
- const bool isTrigger = _isTrigger && CanBeTrigger();
- const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy());
- _shape->setFlags(shapeFlags);
- }
+ PhysicsBackend::SetShapeState(_shape, IsActiveInHierarchy(), _isTrigger && CanBeTrigger());
}
void Collider::SetCenter(const Vector3& value)
{
if (Vector3::NearEqual(value, _center))
return;
-
_center = value;
-
if (_staticActor)
{
- _shape->setLocalPose(PxTransform(C2P(_center)));
+ PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity);
}
else if (const RigidBody* rigidBody = GetAttachedRigidBody())
{
- _shape->setLocalPose(PxTransform(C2P((_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale()), C2P(_localTransform.Orientation)));
+ PhysicsBackend::SetShapeLocalPose(_shape, (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(), _localTransform.Orientation);
}
-
UpdateBounds();
}
@@ -75,13 +59,9 @@ void Collider::SetContactOffset(float value)
value = Math::Clamp(value, 0.0f, 100.0f);
if (Math::NearEqual(value, _contactOffset))
return;
-
_contactOffset = value;
-
if (_shape)
- {
- _shape->setContactOffset(Math::Max(_shape->getRestOffset() + ZeroTolerance, _contactOffset));
- }
+ PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset);
}
bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const
@@ -89,73 +69,36 @@ bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& r
resultHitDistance = MAX_float;
if (_shape == nullptr)
return false;
-
- // Prepare data
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV;
-
- // Perform raycast test
- PxRaycastHit hit;
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _shape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0)
- {
- resultHitDistance = hit.distance;
- return true;
- }
-
- return false;
+ return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, resultHitDistance, maxDistance);
}
bool Collider::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const
{
if (_shape == nullptr)
return false;
-
- // Prepare data
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV;
- PxRaycastHit hit;
-
- // Perform raycast test
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _shape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0)
- return false;
-
- // Gather results
- hitInfo.Gather(hit);
- return true;
+ return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, hitInfo, maxDistance);
}
-void Collider::ClosestPoint(const Vector3& position, Vector3& result) const
+void Collider::ClosestPoint(const Vector3& point, Vector3& result) const
{
if (_shape == nullptr)
{
result = Vector3::Maximum;
return;
}
-
- // Prepare data
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- PxVec3 closestPoint;
-
- // Compute distance between a point and a geometry object
- const float distanceSqr = PxGeometryQuery::pointDistance(C2P(position), _shape->getGeometry().any(), trans, &closestPoint);
+ Vector3 closestPoint;
+ const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_shape, _transform.Translation, _transform.Orientation, point, &closestPoint);
if (distanceSqr > 0.0f)
- {
- // Use calculated point
- result = P2C(closestPoint);
- }
+ result = closestPoint;
else
- {
- // Fallback to the input location
- result = position;
- }
+ result = point;
}
bool Collider::ContainsPoint(const Vector3& point) const
{
if (_shape)
{
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- const float distanceSqr = PxGeometryQuery::pointDistance(C2P(point), _shape->getGeometry().any(), trans);
+ const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_shape, _transform.Translation, _transform.Orientation, point);
return distanceSqr <= 0.0f;
}
return false;
@@ -165,17 +108,12 @@ bool Collider::ComputePenetration(const Collider* colliderA, const Collider* col
{
direction = Vector3::Zero;
distance = 0.0f;
-
CHECK_RETURN(colliderA && colliderB, false);
- const PxShape* shapeA = colliderA->GetPxShape();
- const PxShape* shapeB = colliderB->GetPxShape();
+ void* shapeA = colliderA->GetPhysicsShape();
+ void* shapeB = colliderB->GetPhysicsShape();
if (!shapeA || !shapeB)
return false;
-
- const PxTransform poseA(C2P(colliderA->GetPosition()), C2P(colliderA->GetOrientation()));
- const PxTransform poseB(C2P(colliderB->GetPosition()), C2P(colliderB->GetOrientation()));
-
- return PxGeometryQuery::computePenetration(C2P(direction), distance, shapeA->getGeometry().any(), poseA, shapeB->getGeometry().any(), poseB);
+ return PhysicsBackend::ComputeShapesPenetration(shapeA, shapeB, colliderA->GetPosition(), colliderA->GetOrientation(), colliderB->GetPosition(), colliderB->GetOrientation(), direction, distance);
}
bool Collider::CanAttach(RigidBody* rigidBody) const
@@ -192,9 +130,7 @@ RigidBody* Collider::GetAttachedRigidBody() const
{
if (_shape && _staticActor == nullptr)
{
- auto actor = _shape->getActor();
- if (actor && actor->is())
- return static_cast(actor->userData);
+ return dynamic_cast(GetParent());
}
return nullptr;
}
@@ -232,10 +168,10 @@ void Collider::Attach(RigidBody* rigidBody)
CreateShape();
// Attach
- rigidBody->GetPhysXRigidActor()->attachShape(*_shape);
+ PhysicsBackend::AttachShape(_shape, rigidBody->GetPhysicsActor());
_cachedLocalPosePos = (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale();
_cachedLocalPoseRot = _localTransform.Orientation;
- _shape->setLocalPose(PxTransform(C2P(_cachedLocalPosePos), C2P(_cachedLocalPoseRot)));
+ PhysicsBackend::SetShapeLocalPose(_shape, _cachedLocalPosePos, _cachedLocalPoseRot);
if (rigidBody->IsDuringPlay())
{
rigidBody->UpdateBounds();
@@ -245,40 +181,29 @@ void Collider::Attach(RigidBody* rigidBody)
void Collider::UpdateLayerBits()
{
- ASSERT(_shape);
-
- PxFilterData filterData;
-
// Own layer ID
- filterData.word0 = GetLayerMask();
+ const uint32 mask0 = GetLayerMask();
// Own layer mask
- filterData.word1 = Physics::LayerMasks[GetLayer()];
+ const uint32 mask1 = Physics::LayerMasks[GetLayer()];
- _shape->setSimulationFilterData(filterData);
- _shape->setQueryFilterData(filterData);
+ ASSERT(_shape);
+ PhysicsBackend::SetShapeFilterMask(_shape, mask0, mask1);
}
void Collider::CreateShape()
{
+ ASSERT(_shape == nullptr);
+
// Setup shape geometry
_cachedScale = GetScale();
- PxGeometryHolder geometry;
- GetGeometry(geometry);
+ CollisionShape shape;
+ GetGeometry(shape);
// Create shape
const bool isTrigger = _isTrigger && CanBeTrigger();
- const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy());
- PxMaterial* material = Physics::GetDefaultMaterial();
- if (Material && !Material->WaitForLoaded() && Material->Instance)
- {
- material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial();
- }
- ASSERT(_shape == nullptr);
- _shape = CPhysX->createShape(geometry.any(), *material, true, shapeFlags);
- ASSERT(_shape);
- _shape->userData = this;
- _shape->setContactOffset(Math::Max(_shape->getRestOffset() + ZeroTolerance, _contactOffset));
+ _shape = PhysicsBackend::CreateShape(this, shape, Material.Get(), IsActiveInHierarchy(), isTrigger);
+ PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset);
UpdateLayerBits();
}
@@ -289,20 +214,20 @@ void Collider::UpdateGeometry()
// Setup shape geometry
_cachedScale = GetScale();
- PxGeometryHolder geometry;
- GetGeometry(geometry);
+ CollisionShape shape;
+ GetGeometry(shape);
// Recreate shape if geometry has different type
- if (_shape->getGeometryType() != geometry.getType())
+ if (PhysicsBackend::GetShapeType(_shape) != shape.Type)
{
// Detach from the actor
- auto actor = _shape->getActor();
+ void* actor = PhysicsBackend::GetShapeActor(_shape);
if (actor)
- actor->detachShape(*_shape);
+ PhysicsBackend::DetachShape(_shape, actor);
// Release shape
- GetPhysicsScene()->RemoveCollider(this);
- _shape->release();
+ PhysicsBackend::RemoveCollider(this);
+ PhysicsBackend::DestroyShape(_shape);
_shape = nullptr;
// Recreate shape
@@ -314,7 +239,7 @@ void Collider::UpdateGeometry()
const auto rigidBody = dynamic_cast(GetParent());
if (_staticActor != nullptr || (rigidBody && CanAttach(rigidBody)))
{
- actor->attachShape(*_shape);
+ PhysicsBackend::AttachShape(_shape, actor);
}
else
{
@@ -327,33 +252,28 @@ void Collider::UpdateGeometry()
}
// Update shape
- _shape->setGeometry(geometry.any());
+ PhysicsBackend::SetShapeGeometry(_shape, shape);
}
void Collider::CreateStaticActor()
{
ASSERT(_staticActor == nullptr);
-
- const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation));
- _staticActor = CPhysX->createRigidStatic(trans);
- ASSERT(_staticActor);
- _staticActor->userData = this;
-#if WITH_PVD
- _staticActor->setActorFlag(PxActorFlag::eVISUALIZATION, true);
-#endif
+ _staticActor = PhysicsBackend::CreateRigidStaticActor(nullptr, _transform.Translation, _transform.Orientation);
// Reset local pos of the shape and link it to the actor
- _shape->setLocalPose(PxTransform(C2P(_center)));
- _staticActor->attachShape(*_shape);
+ PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity);
+ PhysicsBackend::AttachShape(_shape, _staticActor);
- GetPhysicsScene()->AddActor(_staticActor);
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _staticActor);
}
void Collider::RemoveStaticActor()
{
ASSERT(_staticActor != nullptr);
-
- GetPhysicsScene()->RemoveActor(_staticActor);
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::RemoveSceneActor(scene, _staticActor);
+ PhysicsBackend::DestroyActor(_staticActor);
_staticActor = nullptr;
}
@@ -369,14 +289,7 @@ void Collider::OnMaterialChanged()
{
// Update the shape material
if (_shape)
- {
- PxMaterial* material = Physics::GetDefaultMaterial();
- if (Material && !Material->WaitForLoaded() && Material->Instance)
- {
- material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial();
- }
- _shape->setMaterials(&material, 1);
- }
+ PhysicsBackend::SetShapeMaterial(_shape, Material.Get());
}
void Collider::Serialize(SerializeStream& stream, const void* otherObj)
@@ -436,19 +349,22 @@ void Collider::EndPlay()
if (_shape)
{
// Detach from the actor
- auto actor = _shape->getActor();
+ void* actor = PhysicsBackend::GetShapeActor(_shape);
+ RigidBody* rigidBody = GetAttachedRigidBody();
if (actor)
- actor->detachShape(*_shape);
- if (actor && actor->is())
- static_cast(actor->userData)->OnColliderChanged(this);
+ PhysicsBackend::DetachShape(_shape, actor);
+ if (rigidBody)
+ {
+ rigidBody->OnColliderChanged(this);
+ }
else if (_staticActor)
{
RemoveStaticActor();
}
// Release shape
- GetPhysicsScene()->RemoveCollider(this);
- _shape->release();
+ PhysicsBackend::RemoveCollider(this);
+ PhysicsBackend::DestroyShape(_shape);
_shape = nullptr;
}
}
@@ -460,9 +376,7 @@ void Collider::OnActiveInTreeChanged()
if (_shape)
{
- const bool isTrigger = _isTrigger && CanBeTrigger();
- const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy());
- _shape->setFlags(shapeFlags);
+ PhysicsBackend::SetShapeState(_shape, IsActiveInHierarchy(), _isTrigger && CanBeTrigger());
auto rigidBody = GetAttachedRigidBody();
if (rigidBody)
@@ -481,17 +395,20 @@ void Collider::OnParentChanged()
if (_shape)
{
// Detach from the actor
- auto actor = _shape->getActor();
+ void* actor = PhysicsBackend::GetShapeActor(_shape);
+ RigidBody* rigidBody = GetAttachedRigidBody();
if (actor)
- actor->detachShape(*_shape);
- if (actor && actor->is())
- static_cast(actor->userData)->OnColliderChanged(this);
+ PhysicsBackend::DetachShape(_shape, actor);
+ if (rigidBody)
+ {
+ rigidBody->OnColliderChanged(this);
+ }
// Check if the new parent is a rigidbody
- const auto rigidBody = dynamic_cast(GetParent());
+ rigidBody = dynamic_cast(GetParent());
if (rigidBody && CanAttach(rigidBody))
{
- // Attach to the rigidbody (will remove static actor if it's n use)
+ // Attach to the rigidbody
Attach(rigidBody);
}
else
@@ -499,6 +416,8 @@ void Collider::OnParentChanged()
// Use static actor (if not created yet)
if (_staticActor == nullptr)
CreateStaticActor();
+ else
+ PhysicsBackend::AttachShape(_shape, _staticActor);
}
}
}
@@ -510,7 +429,7 @@ void Collider::OnTransformChanged()
if (_staticActor)
{
- _staticActor->setGlobalPose(PxTransform(C2P(_transform.Translation), C2P(_transform.Orientation)));
+ PhysicsBackend::SetRigidActorPose(_staticActor, _transform.Translation, _transform.Orientation);
}
else if (const RigidBody* rigidBody = GetAttachedRigidBody())
{
@@ -519,7 +438,7 @@ void Collider::OnTransformChanged()
{
_cachedLocalPosePos = localPosePos;
_cachedLocalPoseRot = _localTransform.Orientation;
- _shape->setLocalPose(PxTransform(C2P(localPosePos), C2P(_cachedLocalPoseRot)));
+ PhysicsBackend::SetShapeLocalPose(_shape, localPosePos, _cachedLocalPoseRot);
}
}
@@ -544,7 +463,8 @@ void Collider::OnPhysicsSceneChanged(PhysicsScene* previous)
if (_staticActor != nullptr)
{
- previous->UnlinkActor(_staticActor);
- GetPhysicsScene()->AddActor(_staticActor);
+ PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _staticActor);
+ void* scene = GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _staticActor);
}
}
diff --git a/Source/Engine/Physics/Colliders/Collider.h b/Source/Engine/Physics/Colliders/Collider.h
index 479b7c288..07a06c3bc 100644
--- a/Source/Engine/Physics/Colliders/Collider.h
+++ b/Source/Engine/Physics/Colliders/Collider.h
@@ -22,8 +22,8 @@ protected:
Vector3 _center;
bool _isTrigger;
- PxShape* _shape;
- PxRigidStatic* _staticActor;
+ void* _shape;
+ void* _staticActor;
Vector3 _cachedScale;
float _contactOffset;
Vector3 _cachedLocalPosePos;
@@ -32,9 +32,9 @@ protected:
public:
///
- /// Gets the collider shape PhysX object.
+ /// Gets the native physics backend object.
///
- PxShape* GetPxShape() const;
+ void* GetPhysicsShape() const;
///
/// Gets the 'IsTrigger' flag.
@@ -121,9 +121,9 @@ public:
///
/// Gets a point on the collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
///
- /// The position to find the closest point to it.
+ /// The position to find the closest point to it.
/// The result point on the collider that is closest to the specified location.
- API_FUNCTION() void ClosestPoint(const Vector3& position, API_PARAM(Out) Vector3& result) const;
+ API_FUNCTION() void ClosestPoint(const Vector3& point, API_PARAM(Out) Vector3& result) const;
///
/// Checks if a point is inside the collider.
@@ -171,7 +171,7 @@ protected:
///
/// Updates the shape actor collisions/queries layer mask bits.
///
- virtual void UpdateLayerBits();
+ void UpdateLayerBits();
///
/// Updates the bounding box of the shape.
@@ -181,8 +181,8 @@ protected:
///
/// Gets the collider shape geometry.
///
- /// The output geometry.
- virtual void GetGeometry(PxGeometryHolder& geometry) = 0;
+ /// The output collision shape.
+ virtual void GetGeometry(CollisionShape& collision) = 0;
///
/// Creates the collider shape.
diff --git a/Source/Engine/Physics/Colliders/MeshCollider.cpp b/Source/Engine/Physics/Colliders/MeshCollider.cpp
index 5b720860c..32e47429a 100644
--- a/Source/Engine/Physics/Colliders/MeshCollider.cpp
+++ b/Source/Engine/Physics/Colliders/MeshCollider.cpp
@@ -4,7 +4,6 @@
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Ray.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Physics.h"
#include "Engine/Physics/PhysicsScene.h"
#if USE_EDITOR || !BUILD_RELEASE
@@ -147,7 +146,7 @@ void MeshCollider::UpdateBounds()
BoundingSphere::FromBox(_box, _sphere);
}
-void MeshCollider::GetGeometry(PxGeometryHolder& geometry)
+void MeshCollider::GetGeometry(CollisionShape& collision)
{
// Prepare scale
Vector3 scale = _cachedScale;
@@ -160,25 +159,9 @@ void MeshCollider::GetGeometry(PxGeometryHolder& geometry)
if (CollisionData && CollisionData->IsLoaded())
type = CollisionData->GetOptions().Type;
if (type == CollisionDataType::ConvexMesh)
- {
- // Convex mesh
- PxConvexMeshGeometry convexMesh;
- convexMesh.scale.scale = C2P(scale);
- convexMesh.convexMesh = CollisionData->GetConvex();
- geometry.storeAny(convexMesh);
- }
+ collision.SetConvexMesh(CollisionData->GetConvex(), scale.Raw);
else if (type == CollisionDataType::TriangleMesh)
- {
- // Triangle mesh
- PxTriangleMeshGeometry triangleMesh;
- triangleMesh.scale.scale = C2P(scale);
- triangleMesh.triangleMesh = CollisionData->GetTriangle();
- geometry.storeAny(triangleMesh);
- }
+ collision.SetTriangleMesh(CollisionData->GetTriangle(), scale.Raw);
else
- {
- // Dummy geometry
- const PxSphereGeometry sphere(minSize);
- geometry.storeAny(sphere);
- }
+ collision.SetSphere(minSize);
}
diff --git a/Source/Engine/Physics/Colliders/MeshCollider.h b/Source/Engine/Physics/Colliders/MeshCollider.h
index efcf60cee..9db547477 100644
--- a/Source/Engine/Physics/Colliders/MeshCollider.h
+++ b/Source/Engine/Physics/Colliders/MeshCollider.h
@@ -45,5 +45,5 @@ protected:
void DrawPhysicsDebug(RenderView& view) override;
#endif
void UpdateBounds() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
+ void GetGeometry(CollisionShape& collision) override;
};
diff --git a/Source/Engine/Physics/Colliders/SphereCollider.cpp b/Source/Engine/Physics/Colliders/SphereCollider.cpp
index 1ff955c3d..6d1a009aa 100644
--- a/Source/Engine/Physics/Colliders/SphereCollider.cpp
+++ b/Source/Engine/Physics/Colliders/SphereCollider.cpp
@@ -2,8 +2,6 @@
#include "SphereCollider.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
SphereCollider::SphereCollider(const SpawnParams& params)
: Collider(params)
@@ -78,11 +76,10 @@ void SphereCollider::UpdateBounds()
_sphere.GetBoundingBox(_box);
}
-void SphereCollider::GetGeometry(PxGeometryHolder& geometry)
+void SphereCollider::GetGeometry(CollisionShape& collision)
{
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float radius = Math::Abs(_radius) * scaling;
const float minSize = 0.001f;
- const PxSphereGeometry sphere(Math::Max(radius, minSize));
- geometry.storeAny(sphere);
+ collision.SetSphere(Math::Max(radius, minSize));
}
diff --git a/Source/Engine/Physics/Colliders/SphereCollider.h b/Source/Engine/Physics/Colliders/SphereCollider.h
index ed2d4cd09..172e6438c 100644
--- a/Source/Engine/Physics/Colliders/SphereCollider.h
+++ b/Source/Engine/Physics/Colliders/SphereCollider.h
@@ -54,5 +54,5 @@ protected:
void DrawPhysicsDebug(RenderView& view) override;
#endif
void UpdateBounds() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
+ void GetGeometry(CollisionShape& collision) override;
};
diff --git a/Source/Engine/Physics/Colliders/SplineCollider.cpp b/Source/Engine/Physics/Colliders/SplineCollider.cpp
index 62516a954..117ec757e 100644
--- a/Source/Engine/Physics/Colliders/SplineCollider.cpp
+++ b/Source/Engine/Physics/Colliders/SplineCollider.cpp
@@ -6,16 +6,13 @@
#include "Engine/Core/Math/Ray.h"
#include "Engine/Level/Actors/Spline.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Physics.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Profiler/ProfilerCPU.h"
#if COMPILE_WITH_PHYSICS_COOKING
#include "Engine/Physics/CollisionCooking.h"
-#include
-#include
#endif
-#include
SplineCollider::SplineCollider(const SpawnParams& params)
: Collider(params)
@@ -173,7 +170,7 @@ void SplineCollider::EndPlay()
// Cleanup
if (_triangleMesh)
{
- GetPhysicsScene()->RemoveObject(_triangleMesh);
+ PhysicsBackend::DestroyObject(_triangleMesh);
_triangleMesh = nullptr;
}
}
@@ -183,18 +180,17 @@ void SplineCollider::UpdateBounds()
// Unused as bounds are updated during collision building
}
-void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
+void SplineCollider::GetGeometry(CollisionShape& collision)
{
// Reset bounds
_box = BoundingBox(_transform.Translation);
BoundingSphere::FromBox(_box, _sphere);
+ const float minSize = 0.001f;
+ collision.SetSphere(minSize);
// Skip if sth is missing
if (!_spline || !IsActiveInHierarchy() || _spline->GetSplinePointsCount() < 2 || !CollisionData || !CollisionData->IsLoaded())
- {
- geometry.storeAny(PxSphereGeometry(0.001f));
return;
- }
PROFILE_CPU();
// Extract collision geometry
@@ -203,10 +199,7 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
Array collisionIndices;
CollisionData->ExtractGeometry(collisionVertices, collisionIndices);
if (collisionIndices.IsEmpty())
- {
- geometry.storeAny(PxSphereGeometry(0.001f));
return;
- }
// Apply local mesh transformation
if (!_preTransform.IsIdentity())
@@ -288,7 +281,6 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
// Prepare scale
Vector3 scale = _cachedScale;
scale.Absolute();
- const float minSize = 0.001f;
scale = Vector3::Max(scale, minSize);
// TODO: add support for cooking collision for static splines in editor and reusing it in game
@@ -307,16 +299,15 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
// Create triangle mesh
if (_triangleMesh)
{
- GetPhysicsScene()->RemoveObject(_triangleMesh);
+ PhysicsBackend::DestroyObject(_triangleMesh);
_triangleMesh = nullptr;
}
- PxDefaultMemoryInputData input(collisionData.Get(), collisionData.Length());
// TODO: try using getVerticesForModification for dynamic triangle mesh vertices updating when changing curve in the editor
- _triangleMesh = Physics::GetPhysics()->createTriangleMesh(input);
+ BoundingBox localBounds;
+ _triangleMesh = PhysicsBackend::CreateTriangleMesh(collisionData.Get(), collisionData.Length(), localBounds);
if (!_triangleMesh)
{
LOG(Error, "Failed to create triangle mesh from collision data of {0}.", ToString());
- geometry.storeAny(PxSphereGeometry(0.001f));
return;
}
@@ -325,17 +316,13 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
_vertexBuffer[i] = colliderTransform.LocalToWorld(_vertexBuffer[i]);
// Update bounds
- _box = P2C(_triangleMesh->getLocalBounds());
Matrix splineWorld;
colliderTransform.GetWorld(splineWorld);
- BoundingBox::Transform(_box, splineWorld, _box);
+ BoundingBox::Transform(localBounds, splineWorld, _box);
BoundingSphere::FromBox(_box, _sphere);
// Setup geometry
- PxTriangleMeshGeometry triangleMesh;
- triangleMesh.scale.scale = C2P(scale);
- triangleMesh.triangleMesh = _triangleMesh;
- geometry.storeAny(triangleMesh);
+ collision.SetTriangleMesh(_triangleMesh, scale.Raw);
// TODO: find a way of releasing _vertexBuffer and _indexBuffer for static colliders (note: ExtractGeometry usage for navmesh generation at runtime)
@@ -344,5 +331,4 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry)
#endif
LOG(Error, "Cannot build collision data for {0} due to runtime collision cooking diabled.", ToString());
- geometry.storeAny(PxSphereGeometry(0.001f));
}
diff --git a/Source/Engine/Physics/Colliders/SplineCollider.h b/Source/Engine/Physics/Colliders/SplineCollider.h
index c1cdab7b7..910bdd9fc 100644
--- a/Source/Engine/Physics/Colliders/SplineCollider.h
+++ b/Source/Engine/Physics/Colliders/SplineCollider.h
@@ -18,7 +18,7 @@ API_CLASS() class FLAXENGINE_API SplineCollider : public Collider
DECLARE_SCENE_OBJECT(SplineCollider);
private:
Spline* _spline = nullptr;
- PxTriangleMesh* _triangleMesh = nullptr;
+ void* _triangleMesh = nullptr;
Array _vertexBuffer;
Array _indexBuffer;
Transform _preTransform = Transform::Identity;
@@ -76,5 +76,5 @@ protected:
void DrawPhysicsDebug(RenderView& view) override;
#endif
void UpdateBounds() override;
- void GetGeometry(PxGeometryHolder& geometry) override;
+ void GetGeometry(CollisionShape& collision) override;
};
diff --git a/Source/Engine/Physics/CollisionCooking.cpp b/Source/Engine/Physics/CollisionCooking.cpp
index 18d11b718..d6915f24c 100644
--- a/Source/Engine/Physics/CollisionCooking.cpp
+++ b/Source/Engine/Physics/CollisionCooking.cpp
@@ -8,96 +8,6 @@
#include "Engine/Graphics/Models/MeshBase.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Core/Log.h"
-#include "Physics.h"
-#include
-#include
-
-#define CONVEX_VERTEX_MIN 8
-#define CONVEX_VERTEX_MAX 255
-#define ENSURE_CAN_COOK \
- auto cooking = Physics::GetCooking(); \
- if (cooking == nullptr) \
- { \
- LOG(Warning, "Physics collisions cooking is disabled at runtime. Enable Physics Settings option SupportCookingAtRuntime to use collision generation at runtime."); \
- return true; \
- }
-
-bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output)
-{
- ENSURE_CAN_COOK;
- if (input.VertexCount == 0)
- LOG(Warning, "Empty mesh data for collision cooking.");
-
- // Init options
- PxConvexMeshDesc desc;
- desc.points.count = input.VertexCount;
- desc.points.stride = sizeof(Vector3);
- desc.points.data = input.VertexData;
- desc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
- if (input.ConvexVertexLimit == 0)
- desc.vertexLimit = CONVEX_VERTEX_MAX;
- else
- desc.vertexLimit = (PxU16)Math::Clamp(input.ConvexVertexLimit, CONVEX_VERTEX_MIN, CONVEX_VERTEX_MAX);
- if (input.ConvexFlags & ConvexMeshGenerationFlags::SkipValidation)
- desc.flags |= PxConvexFlag::Enum::eDISABLE_MESH_VALIDATION;
- if (input.ConvexFlags & ConvexMeshGenerationFlags::UsePlaneShifting)
- desc.flags |= PxConvexFlag::Enum::ePLANE_SHIFTING;
- if (input.ConvexFlags & ConvexMeshGenerationFlags::UseFastInteriaComputation)
- desc.flags |= PxConvexFlag::Enum::eFAST_INERTIA_COMPUTATION;
- if (input.ConvexFlags & ConvexMeshGenerationFlags::ShiftVertices)
- desc.flags |= PxConvexFlag::Enum::eSHIFT_VERTICES;
- PxCookingParams cookingParams = cooking->getParams();
- cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable;
- cooking->setParams(cookingParams);
-
- // Perform cooking
- PxDefaultMemoryOutputStream outputStream;
- PxConvexMeshCookingResult::Enum result;
- if (!cooking->cookConvexMesh(desc, outputStream, &result))
- {
- LOG(Warning, "Convex Mesh cooking failed. Error code: {0}, Input vertices count: {1}", result, input.VertexCount);
- return true;
- }
-
- // Copy result
- output.Copy(outputStream.getData(), outputStream.getSize());
-
- return false;
-}
-
-bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output)
-{
- ENSURE_CAN_COOK;
- if (input.VertexCount == 0 || input.IndexCount == 0)
- LOG(Warning, "Empty mesh data for collision cooking.");
-
- // Init options
- PxTriangleMeshDesc desc;
- desc.points.count = input.VertexCount;
- desc.points.stride = sizeof(Vector3);
- desc.points.data = input.VertexData;
- desc.triangles.count = input.IndexCount / 3;
- desc.triangles.stride = 3 * (input.Is16bitIndexData ? sizeof(uint16) : sizeof(uint32));
- desc.triangles.data = input.IndexData;
- desc.flags = input.Is16bitIndexData ? PxMeshFlag::e16_BIT_INDICES : (PxMeshFlag::Enum)0;
- PxCookingParams cookingParams = cooking->getParams();
- cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable;
- cooking->setParams(cookingParams);
-
- // Perform cooking
- PxDefaultMemoryOutputStream outputStream;
- PxTriangleMeshCookingResult::Enum result;
- if (!cooking->cookTriangleMesh(desc, outputStream, &result))
- {
- LOG(Warning, "Triangle Mesh cooking failed. Error code: {0}, Input vertices count: {1}, indices count: {2}", result, input.VertexCount, input.IndexCount);
- return true;
- }
-
- // Copy result
- output.Copy(outputStream.getData(), outputStream.getSize());
-
- return false;
-}
bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::SerializedOptions& outputOptions, BytesContainer& outputData)
{
@@ -371,17 +281,4 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
return false;
}
-bool CollisionCooking::CookHeightField(const physx::PxHeightFieldDesc& desc, physx::PxOutputStream& stream)
-{
- ENSURE_CAN_COOK;
-
- if (!Physics::GetCooking()->cookHeightField(desc, stream))
- {
- LOG(Warning, "Height Field collision cooking failed.");
- return true;
- }
-
- return false;
-}
-
#endif
diff --git a/Source/Engine/Physics/CollisionCooking.h b/Source/Engine/Physics/CollisionCooking.h
index 992038224..afd3098a9 100644
--- a/Source/Engine/Physics/CollisionCooking.h
+++ b/Source/Engine/Physics/CollisionCooking.h
@@ -8,12 +8,10 @@
#include "Engine/Physics/CollisionData.h"
#include "Engine/Graphics/Models/ModelData.h"
#include "Engine/Content/Assets/ModelBase.h"
+#include "Engine/Physics/PhysicsBackend.h"
-namespace physx
-{
- class PxHeightFieldDesc;
- class PxOutputStream;
-}
+#define CONVEX_VERTEX_MIN 8
+#define CONVEX_VERTEX_MAX 255
///
/// Physical collision data cooking tools. Allows to bake heightfield, convex and triangle mesh colliders data.
@@ -21,7 +19,6 @@ namespace physx
class CollisionCooking
{
public:
-
struct CookingInput
{
int32 VertexCount = 0;
@@ -65,6 +62,16 @@ public:
/// True if failed, otherwise false.
static bool CookTriangleMesh(CookingInput& input, BytesContainer& output);
+ ///
+ /// Cooks a heightfield. The results are written to the stream. To create a heightfield object there is an option to precompute some of calculations done while loading the heightfield data.
+ ///
+ /// The heightfield columns count.
+ /// The heightfield rows count.
+ /// The heightfield data.
+ /// The user stream to output the cooked data.
+ /// True if failed, otherwise false.
+ static bool CookHeightField(int32 cols, int32 rows, const PhysicsBackend::HeightFieldSample* data, WriteStream& stream);
+
///
/// Cooks the collision from the model and prepares the data for the format.
///
@@ -73,14 +80,6 @@ public:
/// The output data container.
/// True if failed, otherwise false.
static bool CookCollision(const Argument& arg, CollisionData::SerializedOptions& outputOptions, BytesContainer& outputData);
-
- ///
- /// Cooks a heightfield. The results are written to the stream. To create a heightfield object there is an option to precompute some of calculations done while loading the heightfield data.
- ///
- /// The heightfield descriptor to read the HF from.
- /// The user stream to output the cooked data.
- /// True if failed, otherwise false.
- static bool CookHeightField(const physx::PxHeightFieldDesc& desc, physx::PxOutputStream& stream);
};
#endif
diff --git a/Source/Engine/Physics/CollisionData.cpp b/Source/Engine/Physics/CollisionData.cpp
index 95e5a67ca..deb343384 100644
--- a/Source/Engine/Physics/CollisionData.cpp
+++ b/Source/Engine/Physics/CollisionData.cpp
@@ -1,19 +1,14 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+#include "CollisionData.h"
#include "Engine/Core/Log.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
-#include "Engine/Physics/Physics.h"
#include "Engine/Physics/PhysicsScene.h"
-#include "Engine/Physics/Utilities.h"
-#include "Engine/Physics/CollisionData.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Physics/CollisionCooking.h"
#include "Engine/Threading/Threading.h"
-#include
-#include
-#include
-#include
REGISTER_BINARY_ASSET(CollisionData, "FlaxEngine.CollisionData", true);
@@ -141,9 +136,11 @@ bool CollisionData::GetModelTriangle(uint32 faceIndex, MeshBase*& mesh, uint32&
if (!IsLoaded())
return false;
ScopeLock lock(Locker);
- if (_triangleMesh && faceIndex < _triangleMesh->getNbTriangles())
+ if (_triangleMesh)
{
- if (const PxU32* remap = _triangleMesh->getTrianglesRemap())
+ uint32 trianglesCount;
+ const uint32* remap = PhysicsBackend::GetTriangleMeshRemap(_triangleMesh, trianglesCount);
+ if (remap && faceIndex < trianglesCount)
{
// Get source triangle index from the triangle mesh
meshTriangleIndex = remap[faceIndex];
@@ -187,98 +184,10 @@ void CollisionData::ExtractGeometry(Array& vertexBuffer, Array&
indexBuffer.Clear();
ScopeLock lock(Locker);
-
- uint32 numVertices = 0;
- uint32 numIndices = 0;
-
- // Convex Mesh
if (_convexMesh)
- {
- numVertices = _convexMesh->getNbVertices();
-
- const uint32 numPolygons = _convexMesh->getNbPolygons();
- for (uint32 i = 0; i < numPolygons; i++)
- {
- PxHullPolygon face;
- const bool status = _convexMesh->getPolygonData(i, face);
- ASSERT(status);
-
- numIndices += (face.mNbVerts - 2) * 3;
- }
- }
- // Triangle Mesh
+ PhysicsBackend::GetConvexMeshTriangles(_convexMesh, vertexBuffer, indexBuffer);
else if (_triangleMesh)
- {
- numVertices = _triangleMesh->getNbVertices();
- numIndices = _triangleMesh->getNbTriangles() * 3;
- }
- // No collision data
- else
- {
- return;
- }
-
- // Prepare vertex and index buffers
- vertexBuffer.Resize(numVertices);
- indexBuffer.Resize(numIndices);
- auto outVertices = vertexBuffer.Get();
- auto outIndices = indexBuffer.Get();
-
- if (_convexMesh)
- {
- const PxVec3* convexVertices = _convexMesh->getVertices();
- const byte* convexIndices = _convexMesh->getIndexBuffer();
-
- for (uint32 i = 0; i < numVertices; i++)
- *outVertices++ = P2C(convexVertices[i]);
-
- uint32 numPolygons = _convexMesh->getNbPolygons();
- for (uint32 i = 0; i < numPolygons; i++)
- {
- PxHullPolygon face;
- bool status = _convexMesh->getPolygonData(i, face);
- ASSERT(status);
-
- const PxU8* faceIndices = convexIndices + face.mIndexBase;
- for (uint32 j = 2; j < face.mNbVerts; j++)
- {
- *outIndices++ = faceIndices[0];
- *outIndices++ = faceIndices[j];
- *outIndices++ = faceIndices[j - 1];
- }
- }
- }
- else
- {
- const PxVec3* vertices = _triangleMesh->getVertices();
- for (uint32 i = 0; i < numVertices; i++)
- *outVertices++ = P2C(vertices[i]);
-
- if (_triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
- {
- const uint16* indices = (const uint16*)_triangleMesh->getTriangles();
-
- uint32 numTriangles = numIndices / 3;
- for (uint32 i = 0; i < numTriangles; i++)
- {
- outIndices[i * 3 + 0] = (uint32)indices[i * 3 + 0];
- outIndices[i * 3 + 1] = (uint32)indices[i * 3 + 1];
- outIndices[i * 3 + 2] = (uint32)indices[i * 3 + 2];
- }
- }
- else
- {
- const uint32* indices = (const uint32*)_triangleMesh->getTriangles();
-
- uint32 numTriangles = numIndices / 3;
- for (uint32 i = 0; i < numTriangles; i++)
- {
- outIndices[i * 3 + 0] = indices[i * 3 + 0];
- outIndices[i * 3 + 1] = indices[i * 3 + 1];
- outIndices[i * 3 + 2] = indices[i * 3 + 2];
- }
- }
- }
+ PhysicsBackend::GetTriangleMeshTriangles(_triangleMesh, vertexBuffer, indexBuffer);
}
#if USE_EDITOR
@@ -360,16 +269,13 @@ CollisionData::LoadResult CollisionData::load(const SerializedOptions* options,
return LoadResult::InvalidData;
// Create PhysX object
- PxDefaultMemoryInputData input(dataPtr, dataSize);
if (_options.Type == CollisionDataType::ConvexMesh)
{
- _convexMesh = Physics::GetPhysics()->createConvexMesh(input);
- _options.Box = P2C(_convexMesh->getLocalBounds());
+ _convexMesh = PhysicsBackend::CreateConvexMesh(dataPtr, dataSize, _options.Box);
}
else if (_options.Type == CollisionDataType::TriangleMesh)
{
- _triangleMesh = Physics::GetPhysics()->createTriangleMesh(input);
- _options.Box = P2C(_triangleMesh->getLocalBounds());
+ _triangleMesh = PhysicsBackend::CreateTriangleMesh(dataPtr, dataSize, _options.Box);
}
else
{
@@ -385,16 +291,12 @@ void CollisionData::unload(bool isReloading)
{
if (_convexMesh)
{
- for (auto scene : Physics::Scenes)
- scene->RemoveObject(_convexMesh);
-
+ PhysicsBackend::DestroyObject(_convexMesh);
_convexMesh = nullptr;
}
if (_triangleMesh)
{
- for (auto scene : Physics::Scenes)
- scene->RemoveObject(_triangleMesh);
-
+ PhysicsBackend::DestroyObject(_triangleMesh);
_triangleMesh = nullptr;
}
_options = CollisionDataOptions();
diff --git a/Source/Engine/Physics/CollisionData.h b/Source/Engine/Physics/CollisionData.h
index e95f73c77..8804ebf6b 100644
--- a/Source/Engine/Physics/CollisionData.h
+++ b/Source/Engine/Physics/CollisionData.h
@@ -10,12 +10,6 @@ class ModelBase;
class ModelData;
class MeshBase;
-namespace physx
-{
- class PxConvexMesh;
- class PxTriangleMesh;
-}
-
///
/// A storage data type.
///
@@ -165,8 +159,8 @@ public:
private:
CollisionDataOptions _options;
- physx::PxConvexMesh* _convexMesh;
- physx::PxTriangleMesh* _triangleMesh;
+ void* _convexMesh;
+ void* _triangleMesh;
public:
@@ -181,7 +175,7 @@ public:
///
/// Gets the convex mesh object (valid only if asset is loaded and has cooked convex data).
///
- FORCE_INLINE physx::PxConvexMesh* GetConvex() const
+ FORCE_INLINE void* GetConvex() const
{
return _convexMesh;
}
@@ -189,7 +183,7 @@ public:
///
/// Gets the triangle mesh object (valid only if asset is loaded and has cooked triangle data).
///
- FORCE_INLINE physx::PxTriangleMesh* GetTriangle() const
+ FORCE_INLINE void* GetTriangle() const
{
return _triangleMesh;
}
diff --git a/Source/Engine/Physics/Collisions.h b/Source/Engine/Physics/Collisions.h
index 658e9a211..205ec3b43 100644
--- a/Source/Engine/Physics/Collisions.h
+++ b/Source/Engine/Physics/Collisions.h
@@ -2,13 +2,9 @@
#pragma once
-#include "Engine/Core/Delegate.h"
#include "Engine/Core/Math/Vector3.h"
class PhysicsColliderActor;
-class Joint;
-class Rigidbody;
-class Collider;
///
/// Contains a contact point data for the collision location.
diff --git a/Source/Engine/Physics/Joints/D6Joint.cpp b/Source/Engine/Physics/Joints/D6Joint.cpp
index 079c9a1cc..7b890c5a0 100644
--- a/Source/Engine/Physics/Joints/D6Joint.cpp
+++ b/Source/Engine/Physics/Joints/D6Joint.cpp
@@ -3,9 +3,7 @@
#include "D6Joint.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include "Engine/Physics/Physics.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
D6Joint::D6Joint(const SpawnParams& params)
: Joint(params)
@@ -19,185 +17,118 @@ void D6Joint::SetMotion(const D6JointAxis axis, const D6JointMotion value)
{
if (value == GetMotion(axis))
return;
-
_motion[static_cast(axis)] = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- joint->setMotion(static_cast(axis), static_cast(value));
- }
+ PhysicsBackend::SetD6JointMotion(_joint, axis, value);
}
void D6Joint::SetDrive(const D6JointDriveType index, const D6JointDrive& value)
{
if (value == GetDrive(index))
return;
-
_drive[static_cast(index)] = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxD6JointDrive drive;
- if (value.Acceleration)
- drive.flags = PxD6JointDriveFlag::eACCELERATION;
- drive.stiffness = value.Stiffness;
- drive.damping = value.Damping;
- drive.forceLimit = value.ForceLimit;
- ASSERT_LOW_LAYER(drive.isValid());
- joint->setDrive(static_cast(index), drive);
- }
+ PhysicsBackend::SetD6JointDrive(_joint, index, value);
}
void D6Joint::SetLimitLinear(const LimitLinear& value)
{
if (value == _limitLinear)
return;
-
_limitLinear = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointLinearLimit limit(*Physics::GetTolerancesScale(), Math::Max(value.Extent, ZeroTolerance), value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setLinearLimit(limit);
- }
+ PhysicsBackend::SetD6JointLimitLinear(_joint, value);
}
void D6Joint::SetLimitTwist(const LimitAngularRange& value)
{
if (value == _limitTwist)
return;
-
_limitTwist = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setTwistLimit(limit);
- }
+ PhysicsBackend::SetD6JointLimitTwist(_joint, value);
}
void D6Joint::SetLimitSwing(const LimitConeRange& value)
{
if (value == _limitSwing)
return;
-
_limitSwing = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setSwingLimit(limit);
- }
+ PhysicsBackend::SetD6JointLimitSwing(_joint, value);
}
Vector3 D6Joint::GetDrivePosition() const
{
- return _joint ? P2C(static_cast(_joint)->getDrivePosition().p) : Vector3::Zero;
+ return _joint ? PhysicsBackend::GetD6JointDrivePosition(_joint) : Vector3::Zero;
}
void D6Joint::SetDrivePosition(const Vector3& value)
{
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxTransform t = joint->getDrivePosition();
- t.p = C2P(value);
- joint->setDrivePosition(t);
- }
+ PhysicsBackend::SetD6JointDrivePosition(_joint, value);
}
Quaternion D6Joint::GetDriveRotation() const
{
- return _joint ? P2C(static_cast(_joint)->getDrivePosition().q) : Quaternion::Identity;
+ return _joint ? PhysicsBackend::GetD6JointDriveRotation(_joint) : Quaternion::Identity;
}
void D6Joint::SetDriveRotation(const Quaternion& value)
{
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxTransform t = joint->getDrivePosition();
- t.q = C2P(value);
- joint->setDrivePosition(t);
- }
+ PhysicsBackend::SetD6JointDriveRotation(_joint, value);
}
Vector3 D6Joint::GetDriveLinearVelocity() const
{
+ Vector3 linear = Vector3::Zero, angular;
if (_joint)
- {
- PxVec3 linear, angular;
- static_cast(_joint)->getDriveVelocity(linear, angular);
- return P2C(linear);
- }
- return Vector3::Zero;
+ PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular);
+ return linear;
}
void D6Joint::SetDriveLinearVelocity(const Vector3& value)
{
if (_joint)
{
- PxVec3 linear, angular;
- auto joint = static_cast(_joint);
- joint->getDriveVelocity(linear, angular);
- linear = C2P(value);
- joint->setDriveVelocity(linear, angular);
+ Vector3 linear, angular;
+ PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular);
+ PhysicsBackend::SetD6JointDriveVelocity(_joint, value, angular);
}
}
Vector3 D6Joint::GetDriveAngularVelocity() const
{
+ Vector3 linear, angular = Vector3::Zero;
if (_joint)
- {
- PxVec3 linear, angular;
- static_cast(_joint)->getDriveVelocity(linear, angular);
- return P2C(angular);
- }
- return Vector3::Zero;
+ PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular);
+ return angular;
}
void D6Joint::SetDriveAngularVelocity(const Vector3& value)
{
if (_joint)
{
- PxVec3 linear, angular;
- auto joint = static_cast(_joint);
- joint->getDriveVelocity(linear, angular);
- angular = C2P(value);
- joint->setDriveVelocity(linear, angular);
+ Vector3 linear, angular;
+ PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular);
+ PhysicsBackend::SetD6JointDriveVelocity(_joint, linear, value);
}
}
float D6Joint::GetCurrentTwist() const
{
- return _joint ? static_cast(_joint)->getTwistAngle() : 0.0f;
+ return _joint ? PhysicsBackend::GetD6JointTwist(_joint) : 0.0f;
}
-float D6Joint::GetCurrentSwingYAngle() const
+float D6Joint::GetCurrentSwingY() const
{
- return _joint ? static_cast(_joint)->getSwingYAngle() : 0.0f;
+ return _joint ? PhysicsBackend::GetD6JointSwingY(_joint) : 0.0f;
}
-float D6Joint::GetCurrentSwingZAngle() const
+float D6Joint::GetCurrentSwingZ() const
{
- return _joint ? static_cast(_joint)->getSwingZAngle() : 0.0f;
+ return _joint ? PhysicsBackend::GetD6JointSwingZ(_joint) : 0.0f;
}
#if USE_EDITOR
@@ -412,59 +343,15 @@ void D6Joint::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie
JsonTools::GetFloat(_limitSwing.Spring.Damping, stream, "LimitSwing.Damping");
}
-PxJoint* D6Joint::CreateJoint(JointData& data)
+void* D6Joint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- auto joint = PxD6JointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
-
+ void* joint = PhysicsBackend::CreateD6Joint(desc);
for (int32 i = 0; i < static_cast(D6JointAxis::MAX); i++)
- {
- joint->setMotion(static_cast(i), static_cast(_motion[i]));
- }
-
+ PhysicsBackend::SetD6JointMotion(joint, (D6JointAxis)i, _motion[i]);
for (int32 i = 0; i < static_cast(D6JointAxis::MAX); i++)
- {
- const auto& value = _drive[i];
- PxD6JointDrive drive;
- if (value.Acceleration)
- drive.flags = PxD6JointDriveFlag::eACCELERATION;
- drive.stiffness = value.Stiffness;
- drive.damping = value.Damping;
- drive.forceLimit = value.ForceLimit;
- ASSERT_LOW_LAYER(drive.isValid());
- joint->setDrive(static_cast(i), drive);
- }
-
- {
- const auto& value = _limitLinear;
- PxJointLinearLimit limit(*Physics::GetTolerancesScale(), Math::Max(value.Extent, ZeroTolerance), value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setDistanceLimit(limit);
- }
-
- {
- const auto& value = _limitTwist;
- PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setTwistLimit(limit);
- }
-
- {
- const auto& value = _limitSwing;
- PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setSwingLimit(limit);
- }
-
+ PhysicsBackend::SetD6JointDrive(joint, (D6JointDriveType)i, _drive[i]);
+ PhysicsBackend::SetD6JointLimitLinear(joint, _limitLinear);
+ PhysicsBackend::SetD6JointLimitTwist(joint, _limitTwist);
+ PhysicsBackend::SetD6JointLimitSwing(joint, _limitSwing);
return joint;
}
diff --git a/Source/Engine/Physics/Joints/D6Joint.h b/Source/Engine/Physics/Joints/D6Joint.h
index f17571bbb..c57742cea 100644
--- a/Source/Engine/Physics/Joints/D6Joint.h
+++ b/Source/Engine/Physics/Joints/D6Joint.h
@@ -303,19 +303,19 @@ public:
public:
///
- /// Gets the twist angle of the joint.
+ /// Gets the twist angle of the joint (in the range (-2*Pi, 2*Pi]).
///
API_PROPERTY() float GetCurrentTwist() const;
///
/// Gets the current swing angle of the joint from the Y axis.
///
- API_PROPERTY() float GetCurrentSwingYAngle() const;
+ API_PROPERTY() float GetCurrentSwingY() const;
///
/// Gets the current swing angle of the joint from the Z axis.
///
- API_PROPERTY() float GetCurrentSwingZAngle() const;
+ API_PROPERTY() float GetCurrentSwingZ() const;
public:
@@ -329,5 +329,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/Joints/DistanceJoint.cpp b/Source/Engine/Physics/Joints/DistanceJoint.cpp
index 5df279801..f38fc2498 100644
--- a/Source/Engine/Physics/Joints/DistanceJoint.cpp
+++ b/Source/Engine/Physics/Joints/DistanceJoint.cpp
@@ -1,9 +1,8 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "DistanceJoint.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
DistanceJoint::DistanceJoint(const SpawnParams& params)
: Joint(params)
@@ -18,13 +17,9 @@ void DistanceJoint::SetFlags(DistanceJointFlag value)
{
if (_flags == value)
return;
-
_flags = value;
-
if (_joint)
- {
- static_cast(_joint)->setDistanceJointFlags(static_cast(value));
- }
+ PhysicsBackend::SetDistanceJointFlags(_joint, value);
}
void DistanceJoint::SetMinDistance(float value)
@@ -32,13 +27,9 @@ void DistanceJoint::SetMinDistance(float value)
value = Math::Clamp(value, 0.0f, _maxDistance);
if (Math::NearEqual(value, _minDistance))
return;
-
_minDistance = value;
-
if (_joint)
- {
- static_cast(_joint)->setMinDistance(value);
- }
+ PhysicsBackend::SetDistanceJointMinDistance(_joint, value);
}
void DistanceJoint::SetMaxDistance(float value)
@@ -46,13 +37,9 @@ void DistanceJoint::SetMaxDistance(float value)
value = Math::Max(_minDistance, value);
if (Math::NearEqual(value, _maxDistance))
return;
-
_maxDistance = value;
-
if (_joint)
- {
- static_cast(_joint)->setMaxDistance(value);
- }
+ PhysicsBackend::SetDistanceJointMaxDistance(_joint, value);
}
void DistanceJoint::SetTolerance(float value)
@@ -60,32 +47,23 @@ void DistanceJoint::SetTolerance(float value)
value = Math::Max(0.1f, value);
if (Math::NearEqual(value, _tolerance))
return;
-
_tolerance = value;
-
if (_joint)
- {
- static_cast(_joint)->setTolerance(value);
- }
+ PhysicsBackend::SetDistanceJointTolerance(_joint, value);
}
void DistanceJoint::SetSpringParameters(const SpringParameters& value)
{
if (value == _spring)
return;
-
_spring = value;
-
if (_joint)
- {
- static_cast(_joint)->setStiffness(value.Stiffness);
- static_cast(_joint)->setDamping(value.Damping);
- }
+ PhysicsBackend::SetDistanceJointSpring(_joint, value);
}
float DistanceJoint::GetCurrentDistance() const
{
- return _joint ? static_cast(_joint)->getDistance() : 0.0f;
+ return _joint ? PhysicsBackend::GetDistanceJointDistance(_joint) : 0.0f;
}
#if USE_EDITOR
@@ -149,18 +127,13 @@ void DistanceJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* m
DESERIALIZE_MEMBER(Damping, _spring.Damping);
}
-PxJoint* DistanceJoint::CreateJoint(JointData& data)
+void* DistanceJoint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- auto joint = PxDistanceJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
-
- joint->setMinDistance(_minDistance);
- joint->setMaxDistance(_maxDistance);
- joint->setTolerance(_tolerance);
- joint->setDistanceJointFlags(static_cast(_flags));
- joint->setStiffness(_spring.Stiffness);
- joint->setDamping(_spring.Damping);
-
+ void* joint = PhysicsBackend::CreateDistanceJoint(desc);
+ PhysicsBackend::SetDistanceJointFlags(joint, _flags);
+ PhysicsBackend::SetDistanceJointMinDistance(joint, _minDistance);
+ PhysicsBackend::SetDistanceJointMaxDistance(joint, _maxDistance);
+ PhysicsBackend::SetDistanceJointTolerance(joint, _tolerance);
+ PhysicsBackend::SetDistanceJointSpring(joint, _spring);
return joint;
}
diff --git a/Source/Engine/Physics/Joints/DistanceJoint.h b/Source/Engine/Physics/Joints/DistanceJoint.h
index 05dad5d0c..fc1c615f3 100644
--- a/Source/Engine/Physics/Joints/DistanceJoint.h
+++ b/Source/Engine/Physics/Joints/DistanceJoint.h
@@ -157,5 +157,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/Joints/FixedJoint.cpp b/Source/Engine/Physics/Joints/FixedJoint.cpp
index 7c01e3e3c..8f1c2a888 100644
--- a/Source/Engine/Physics/Joints/FixedJoint.cpp
+++ b/Source/Engine/Physics/Joints/FixedJoint.cpp
@@ -1,8 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "FixedJoint.h"
-#include "Engine/Physics/Utilities.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
FixedJoint::FixedJoint(const SpawnParams& params)
: Joint(params)
@@ -23,9 +22,7 @@ void FixedJoint::OnDebugDrawSelected()
#endif
-PxJoint* FixedJoint::CreateJoint(JointData& data)
+void* FixedJoint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- return PxFixedJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
+ return PhysicsBackend::CreateFixedJoint(desc);
}
diff --git a/Source/Engine/Physics/Joints/FixedJoint.h b/Source/Engine/Physics/Joints/FixedJoint.h
index d2ee0f583..c62789c4e 100644
--- a/Source/Engine/Physics/Joints/FixedJoint.h
+++ b/Source/Engine/Physics/Joints/FixedJoint.h
@@ -21,5 +21,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/Joints/HingeJoint.cpp b/Source/Engine/Physics/Joints/HingeJoint.cpp
index a651dab63..4d078880d 100644
--- a/Source/Engine/Physics/Joints/HingeJoint.cpp
+++ b/Source/Engine/Physics/Joints/HingeJoint.cpp
@@ -2,8 +2,7 @@
#include "HingeJoint.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
HingeJoint::HingeJoint(const SpawnParams& params)
: Joint(params)
@@ -17,61 +16,37 @@ void HingeJoint::SetFlags(const HingeJointFlag value)
{
if (_flags == value)
return;
-
_flags = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- joint->setRevoluteJointFlag(PxRevoluteJointFlag::eLIMIT_ENABLED, (_flags & HingeJointFlag::Limit) != 0);
- joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, (_flags & HingeJointFlag::Drive) != 0);
- }
+ PhysicsBackend::SetHingeJointFlags(_joint, value, _drive.FreeSpin);
}
void HingeJoint::SetLimit(const LimitAngularRange& value)
{
if (_limit == value)
return;
-
_limit = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setLimit(limit);
- }
+ PhysicsBackend::SetHingeJointLimit(_joint, value);
}
void HingeJoint::SetDrive(const HingeJointDrive& value)
{
if (_drive == value)
return;
-
_drive = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- joint->setDriveVelocity(Math::Max(value.Velocity, 0.0f));
- joint->setDriveForceLimit(Math::Max(value.ForceLimit, 0.0f));
- joint->setDriveGearRatio(Math::Max(value.GearRatio, 0.0f));
- joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, value.FreeSpin);
- }
+ PhysicsBackend::SetHingeJointDrive(_joint, value);
}
float HingeJoint::GetCurrentAngle() const
{
- return _joint ? static_cast(_joint)->getAngle() : 0.0f;
+ return _joint ? PhysicsBackend::GetHingeJointAngle(_joint) : 0.0f;
}
float HingeJoint::GetCurrentVelocity() const
{
- return _joint ? static_cast(_joint)->getVelocity() : 0.0f;
+ return _joint ? PhysicsBackend::GetHingeJointVelocity(_joint) : 0.0f;
}
#if USE_EDITOR
@@ -146,29 +121,11 @@ void HingeJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* modi
DESERIALIZE_MEMBER(FreeSpin, _drive.FreeSpin);
}
-PxJoint* HingeJoint::CreateJoint(JointData& data)
+void* HingeJoint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- auto joint = PxRevoluteJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
-
- int32 flags = 0;
- if (_flags & HingeJointFlag::Limit)
- flags |= PxRevoluteJointFlag::eLIMIT_ENABLED;
- if (_flags & HingeJointFlag::Drive)
- flags |= PxRevoluteJointFlag::eDRIVE_ENABLED;
- if (_drive.FreeSpin)
- flags |= PxRevoluteJointFlag::eDRIVE_FREESPIN;
- joint->setRevoluteJointFlags(static_cast(flags));
- joint->setDriveVelocity(_drive.Velocity);
- joint->setDriveForceLimit(_drive.ForceLimit);
- joint->setDriveGearRatio(_drive.GearRatio);
- PxJointAngularLimitPair limit(_limit.Lower * DegreesToRadians, Math::Max(_limit.Upper, _limit.Lower) * DegreesToRadians, _limit.ContactDist);
- limit.stiffness = _limit.Spring.Stiffness;
- limit.damping = _limit.Spring.Damping;
- limit.restitution = _limit.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setLimit(limit);
-
+ void* joint = PhysicsBackend::CreateHingeJoint(desc);
+ PhysicsBackend::SetHingeJointFlags(joint, _flags, _drive.FreeSpin);
+ PhysicsBackend::SetHingeJointLimit(joint, _limit);
+ PhysicsBackend::SetHingeJointDrive(joint, _drive);
return joint;
}
diff --git a/Source/Engine/Physics/Joints/HingeJoint.h b/Source/Engine/Physics/Joints/HingeJoint.h
index cea8a30ff..7b0957101 100644
--- a/Source/Engine/Physics/Joints/HingeJoint.h
+++ b/Source/Engine/Physics/Joints/HingeJoint.h
@@ -165,5 +165,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/Joints/Joint.cpp b/Source/Engine/Physics/Joints/Joint.cpp
index 84a8ad249..3e65f3e60 100644
--- a/Source/Engine/Physics/Joints/Joint.cpp
+++ b/Source/Engine/Physics/Joints/Joint.cpp
@@ -3,14 +3,13 @@
#include "Joint.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Core/Log.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Physics.h"
+#include "Engine/Physics/PhysicsBackend.h"
+#include "Engine/Physics/PhysicsScene.h"
#include "Engine/Physics/Actors/IPhysicsActor.h"
#if USE_EDITOR
#include "Engine/Level/Scene/SceneRendering.h"
#endif
-#include "Engine/Scripting/Script.h"
-#include
Joint::Joint(const SpawnParams& params)
: Actor(params)
@@ -27,36 +26,27 @@ void Joint::SetBreakForce(float value)
{
if (Math::NearEqual(value, _breakForce))
return;
-
_breakForce = value;
if (_joint)
- {
- _joint->setBreakForce(_breakForce, _breakTorque);
- }
+ PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque);
}
void Joint::SetBreakTorque(float value)
{
if (Math::NearEqual(value, _breakTorque))
return;
-
_breakTorque = value;
if (_joint)
- {
- _joint->setBreakForce(_breakForce, _breakTorque);
- }
+ PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque);
}
void Joint::SetEnableCollision(bool value)
{
if (value == GetEnableCollision())
return;
-
_enableCollision = value;
if (_joint)
- {
- _joint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value);
- }
+ PhysicsBackend::SetJointFlags(_joint, _enableCollision ? PhysicsBackend::JointFlags::Collision : PhysicsBackend::JointFlags::None);
}
bool Joint::GetEnableAutoAnchor() const
@@ -73,24 +63,23 @@ void Joint::SetTargetAnchor(const Vector3& value)
{
if (Vector3::NearEqual(value, _targetAnchor))
return;
-
_targetAnchor = value;
if (_joint && !_enableAutoAnchor)
- {
- _joint->setLocalPose(PxJointActorIndex::eACTOR1, PxTransform(C2P(_targetAnchor), C2P(_targetAnchorRotation)));
- }
+ PhysicsBackend::SetJointActorPose(_joint, _targetAnchor, _targetAnchorRotation, 1);
}
void Joint::SetTargetAnchorRotation(const Quaternion& value)
{
if (Quaternion::NearEqual(value, _targetAnchorRotation))
return;
-
_targetAnchorRotation = value;
if (_joint && !_enableAutoAnchor)
- {
- _joint->setLocalPose(PxJointActorIndex::eACTOR1, PxTransform(C2P(_targetAnchor), C2P(_targetAnchorRotation)));
- }
+ PhysicsBackend::SetJointActorPose(_joint, _targetAnchor, _targetAnchorRotation, 1);
+}
+
+void* Joint::GetPhysicsImpl() const
+{
+ return _joint;
}
void Joint::SetJointLocation(const Vector3& location)
@@ -128,14 +117,9 @@ void Joint::SetJointOrientation(const Quaternion& orientation)
void Joint::GetCurrentForce(Vector3& linear, Vector3& angular) const
{
- if (_joint && _joint->getConstraint())
- {
- _joint->getConstraint()->getForce(*(PxVec3*)&linear, *(PxVec3*)&angular);
- }
- else
- {
- linear = angular = Vector3::Zero;
- }
+ linear = angular = Vector3::Zero;
+ if (_joint)
+ PhysicsBackend::GetJointForce(_joint, linear, angular);
}
void Joint::Create()
@@ -151,26 +135,25 @@ void Joint::Create()
}
// Create joint object
- JointData data;
- data.Physics = Physics::GetPhysics();
- data.Actor0 = parent->GetRigidActor();
- data.Actor1 = target ? target->GetRigidActor() : nullptr;
- data.Pos0 = _localTransform.Translation;
- data.Rot0 = _localTransform.Orientation;
- data.Pos1 = _targetAnchor;
- data.Rot1 = _targetAnchorRotation;
+ PhysicsJointDesc desc;
+ desc.Joint = this;
+ desc.Actor0 = parent->GetPhysicsActor();
+ desc.Actor1 = target ? target->GetPhysicsActor() : nullptr;
+ desc.Pos0 = _localTransform.Translation;
+ desc.Rot0 = _localTransform.Orientation;
+ desc.Pos1 = _targetAnchor;
+ desc.Rot1 = _targetAnchorRotation;
if (_enableAutoAnchor && target)
{
// Place target anchor at the joint location
- data.Pos1 = Target->GetTransform().WorldToLocal(GetPosition());
- data.Rot1 = WorldToLocal(Target->GetOrientation(), GetOrientation());
+ desc.Pos1 = Target->GetTransform().WorldToLocal(GetPosition());
+ desc.Rot1 = WorldToLocal(Target->GetOrientation(), GetOrientation());
}
- _joint = CreateJoint(data);
- _joint->userData = this;
+ _joint = CreateJoint(desc);
// Setup joint properties
- _joint->setBreakForce(_breakForce, _breakTorque);
- _joint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, _enableCollision);
+ PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque);
+ PhysicsBackend::SetJointFlags(_joint, _enableCollision ? PhysicsBackend::JointFlags::Collision : PhysicsBackend::JointFlags::None);
}
void Joint::OnJointBreak()
@@ -180,10 +163,8 @@ void Joint::OnJointBreak()
void Joint::Delete()
{
- // Remove the joint
- Physics::RemoveJoint(this);
- _joint->userData = nullptr;
- _joint->release();
+ PhysicsBackend::RemoveJoint(this);
+ PhysicsBackend::DestroyJoint(_joint);
_joint = nullptr;
}
@@ -192,8 +173,7 @@ void Joint::SetActors()
auto parent = dynamic_cast(GetParent());
auto target = dynamic_cast(Target.Get());
ASSERT(parent != nullptr);
-
- _joint->setActors(parent ? parent->GetRigidActor() : nullptr, target ? target->GetRigidActor() : nullptr);
+ PhysicsBackend::SetJointActors(_joint, parent->GetPhysicsActor(), target ? target->GetPhysicsActor() : nullptr);
}
void Joint::OnTargetChanged()
@@ -347,7 +327,7 @@ void Joint::OnActiveInTreeChanged()
else
Delete();
}
- // Joint object may not be created if actor is disabled on play mode begin (late init feature)
+ // Joint object may not be created if actor is disabled on play mode begin (late init feature)
else if (IsDuringPlay())
{
Create();
@@ -393,9 +373,6 @@ void Joint::OnTransformChanged()
_box = BoundingBox(_transform.Translation);
_sphere = BoundingSphere(_transform.Translation, 0.0f);
-
if (_joint)
- {
- _joint->setLocalPose(PxJointActorIndex::eACTOR0, PxTransform(C2P(_localTransform.Translation), C2P(_localTransform.Orientation)));
- }
+ PhysicsBackend::SetJointActorPose(_joint, _localTransform.Translation, _localTransform.Orientation, 0);
}
diff --git a/Source/Engine/Physics/Joints/Joint.h b/Source/Engine/Physics/Joints/Joint.h
index a9f1a02ab..f8e341eb5 100644
--- a/Source/Engine/Physics/Joints/Joint.h
+++ b/Source/Engine/Physics/Joints/Joint.h
@@ -21,7 +21,7 @@ API_CLASS(Abstract) class FLAXENGINE_API Joint : public Actor
DECLARE_SCENE_OBJECT_ABSTRACT(Joint);
protected:
- PxJoint* _joint;
+ void* _joint;
float _breakForce;
float _breakTorque;
Vector3 _targetAnchor;
@@ -133,12 +133,9 @@ public:
public:
///
- /// Gets the native PhysX joint object.
+ /// Gets the native physics backend object.
///
- FORCE_INLINE PxJoint* GetPhysXJoint() const
- {
- return _joint;
- }
+ void* GetPhysicsImpl() const;
///
/// Sets the location of the joint by automatically computing local position and target anchor to place a joint at the given location (world-space).
@@ -178,20 +175,9 @@ public:
protected:
- struct JointData
- {
- PxPhysics* Physics;
- PxRigidActor* Actor0;
- PxRigidActor* Actor1;
- Quaternion Rot0;
- Quaternion Rot1;
- Vector3 Pos0;
- Vector3 Pos1;
- };
-
Vector3 GetTargetPosition() const;
Quaternion GetTargetOrientation() const;
- virtual PxJoint* CreateJoint(JointData& data) = 0;
+ virtual void* CreateJoint(const struct PhysicsJointDesc& desc) = 0;
#if USE_EDITOR
virtual void DrawPhysicsDebug(RenderView& view);
#endif
diff --git a/Source/Engine/Physics/Joints/SliderJoint.cpp b/Source/Engine/Physics/Joints/SliderJoint.cpp
index f6bda1b1f..62f1b646b 100644
--- a/Source/Engine/Physics/Joints/SliderJoint.cpp
+++ b/Source/Engine/Physics/Joints/SliderJoint.cpp
@@ -2,9 +2,7 @@
#include "SliderJoint.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include "Engine/Physics/Physics.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
SliderJoint::SliderJoint(const SpawnParams& params)
: Joint(params)
@@ -18,43 +16,28 @@ void SliderJoint::SetFlags(const SliderJointFlag value)
{
if (_flags == value)
return;
-
_flags = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- joint->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, (_flags & SliderJointFlag::Limit) != 0);
- }
+ PhysicsBackend::SetSliderJointFlags(_joint, value);
}
void SliderJoint::SetLimit(const LimitLinearRange& value)
{
if (_limit == value)
return;
-
_limit = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointLinearLimitPair limit(*Physics::GetTolerancesScale(), value.Lower, value.Upper, value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setLimit(limit);
- }
+ PhysicsBackend::SetSliderJointLimit(_joint, value);
}
float SliderJoint::GetCurrentPosition() const
{
- return _joint ? static_cast(_joint)->getPosition() : 0.0f;
+ return _joint ? PhysicsBackend::GetSliderJointPosition(_joint) : 0.0f;
}
float SliderJoint::GetCurrentVelocity() const
{
- return _joint ? static_cast(_joint)->getVelocity() : 0.0f;
+ return _joint ? PhysicsBackend::GetSliderJointVelocity(_joint) : 0.0f;
}
#if USE_EDITOR
@@ -111,21 +94,10 @@ void SliderJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
DESERIALIZE_MEMBER(UpperLimit, _limit.Upper);
}
-PxJoint* SliderJoint::CreateJoint(JointData& data)
+void* SliderJoint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- auto joint = PxPrismaticJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
-
- int32 flags = 0;
- if (_flags & SliderJointFlag::Limit)
- flags |= PxPrismaticJointFlag::eLIMIT_ENABLED;
- joint->setPrismaticJointFlags(static_cast(flags));
- PxJointLinearLimitPair limit(*Physics::GetTolerancesScale(), _limit.Lower, _limit.Upper, _limit.ContactDist);
- limit.stiffness = _limit.Spring.Stiffness;
- limit.damping = _limit.Spring.Damping;
- limit.restitution = _limit.Restitution;
- joint->setLimit(limit);
-
+ void* joint = PhysicsBackend::CreateSliderJoint(desc);
+ PhysicsBackend::SetSliderJointFlags(joint, _flags);
+ PhysicsBackend::SetSliderJointLimit(joint, _limit);
return joint;
}
diff --git a/Source/Engine/Physics/Joints/SliderJoint.h b/Source/Engine/Physics/Joints/SliderJoint.h
index b9a11c0a0..12dbed970 100644
--- a/Source/Engine/Physics/Joints/SliderJoint.h
+++ b/Source/Engine/Physics/Joints/SliderJoint.h
@@ -95,5 +95,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/Joints/SphericalJoint.cpp b/Source/Engine/Physics/Joints/SphericalJoint.cpp
index bb83ee7cb..0833086cf 100644
--- a/Source/Engine/Physics/Joints/SphericalJoint.cpp
+++ b/Source/Engine/Physics/Joints/SphericalJoint.cpp
@@ -2,8 +2,7 @@
#include "SphericalJoint.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Physics/Utilities.h"
-#include
+#include "Engine/Physics/PhysicsBackend.h"
SphericalJoint::SphericalJoint(const SpawnParams& params)
: Joint(params)
@@ -15,33 +14,18 @@ void SphericalJoint::SetFlags(const SphericalJointFlag value)
{
if (_flags == value)
return;
-
_flags = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- joint->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, (_flags & SphericalJointFlag::Limit) != 0);
- }
+ PhysicsBackend::SetSphericalJointFlags(_joint, value);
}
void SphericalJoint::SetLimit(const LimitConeRange& value)
{
if (_limit == value)
return;
-
_limit = value;
-
if (_joint)
- {
- auto joint = static_cast(_joint);
- PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist);
- limit.stiffness = value.Spring.Stiffness;
- limit.damping = value.Spring.Damping;
- limit.restitution = value.Restitution;
- ASSERT_LOW_LAYER(limit.isValid());
- joint->setLimitCone(limit);
- }
+ PhysicsBackend::SetSphericalJointLimit(_joint, value);
}
#if USE_EDITOR
@@ -101,21 +85,10 @@ void SphericalJoint::Deserialize(DeserializeStream& stream, ISerializeModifier*
DESERIALIZE_MEMBER(ZLimitAngle, _limit.ZLimitAngle);
}
-PxJoint* SphericalJoint::CreateJoint(JointData& data)
+void* SphericalJoint::CreateJoint(const PhysicsJointDesc& desc)
{
- const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
- const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
- auto joint = PxSphericalJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);
-
- int32 flags = 0;
- if (_flags & SphericalJointFlag::Limit)
- flags |= PxSphericalJointFlag::eLIMIT_ENABLED;
- joint->setSphericalJointFlags(static_cast(flags));
- PxJointLimitCone limit(Math::Clamp(_limit.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(_limit.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), _limit.ContactDist);
- limit.stiffness = _limit.Spring.Stiffness;
- limit.damping = _limit.Spring.Damping;
- limit.restitution = _limit.Restitution;
- joint->setLimitCone(limit);
-
+ void* joint = PhysicsBackend::CreateSphericalJoint(desc);
+ PhysicsBackend::SetSphericalJointFlags(joint, _flags);
+ PhysicsBackend::SetSphericalJointLimit(joint, _limit);
return joint;
}
diff --git a/Source/Engine/Physics/Joints/SphericalJoint.h b/Source/Engine/Physics/Joints/SphericalJoint.h
index 67d7e8e07..6fc370dee 100644
--- a/Source/Engine/Physics/Joints/SphericalJoint.h
+++ b/Source/Engine/Physics/Joints/SphericalJoint.h
@@ -85,5 +85,5 @@ public:
protected:
// [Joint]
- PxJoint* CreateJoint(JointData& data) override;
+ void* CreateJoint(const PhysicsJointDesc& desc) override;
};
diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
new file mode 100644
index 000000000..940f4e260
--- /dev/null
+++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
@@ -0,0 +1,3061 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+#if COMPILE_WITH_PHYSX
+
+#include "PhysicsBackendPhysX.h"
+#include "PhysicsStepperPhysX.h"
+#include "SimulationEventCallbackPhysX.h"
+#include "Engine/Core/Log.h"
+#include "Engine/Core/Utilities.h"
+#include "Engine/Physics/CollisionData.h"
+#include "Engine/Physics/PhysicalMaterial.h"
+#include "Engine/Physics/PhysicsScene.h"
+#include "Engine/Physics/CollisionCooking.h"
+#include "Engine/Physics/Actors/IPhysicsActor.h"
+#include "Engine/Physics/Joints/Limits.h"
+#include "Engine/Physics/Joints/DistanceJoint.h"
+#include "Engine/Physics/Joints/HingeJoint.h"
+#include "Engine/Physics/Joints/SliderJoint.h"
+#include "Engine/Physics/Joints/SphericalJoint.h"
+#include "Engine/Physics/Joints/D6Joint.h"
+#include "Engine/Physics/Colliders/Collider.h"
+#include "Engine/Platform/CPUInfo.h"
+#include "Engine/Platform/CriticalSection.h"
+#include "Engine/Profiler/ProfilerCPU.h"
+#include "Engine/Serialization/WriteStream.h"
+#include
+#include
+#include
+#include
+#if WITH_VEHICLE
+#include "Engine/Physics/Actors/WheeledVehicle.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+#if WITH_PVD
+#include
+#endif
+
+// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned.
+#define PHYSX_SCRATCH_BLOCK_SIZE (1024 * 128)
+
+// Enables vehicles simulation debugging
+#define PHYSX_VEHICLE_DEBUG_TELEMETRY 0
+
+// Enables using debug naming for PhysX objects (eg. for debugging)
+#define PHYSX_DEBUG_NAMING 0
+
+// Temporary result buffer size
+#define PHYSX_HIT_BUFFER_SIZE 128
+
+struct ActionDataPhysX
+{
+ PhysicsBackend::ActionType Type;
+ PxActor* Actor;
+};
+
+struct ScenePhysX
+{
+ PxScene* Scene = nullptr;
+ PxCpuDispatcher* CpuDispatcher = nullptr;
+ PxControllerManager* ControllerManager = nullptr;
+ void* ScratchMemory = nullptr;
+ float LastDeltaTime = 0.0f;
+ FixedStepper Stepper;
+ SimulationEventCallback EventsCallback;
+ Array AddActors;
+ Array RemoveActors;
+ Array RemoveColliders;
+ Array RemoveJoints;
+ Array Actions;
+#if WITH_VEHICLE
+ Array WheelVehicles;
+ PxBatchQuery* WheelRaycastBatchQuery = nullptr;
+#endif
+};
+
+class AllocatorPhysX : public PxAllocatorCallback
+{
+ void* allocate(size_t size, const char* typeName, const char* filename, int line) override
+ {
+ return Allocator::Allocate(size, 16);
+ }
+
+ void deallocate(void* ptr) override
+ {
+ Allocator::Free(ptr);
+ }
+};
+
+class ErrorPhysX : public PxErrorCallback
+{
+ void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) override
+ {
+ LOG(Error, "PhysX Error! Code: {0}.\n{1}\nSource: {2} : {3}.", static_cast(code), String(message), String(file), line);
+ }
+};
+
+class QueryFilterPhysX : public PxQueryFilterCallback
+{
+ PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override
+ {
+ // Early out to avoid crashing
+ if (!shape)
+ return PxQueryHitType::eNONE;
+
+ // Check mask
+ const PxFilterData shapeFilter = shape->getQueryFilterData();
+ if ((filterData.word0 & shapeFilter.word0) == 0)
+ {
+ return PxQueryHitType::eNONE;
+ }
+
+ // Check if skip triggers
+ const bool hitTriggers = filterData.word2 != 0;
+ if (!hitTriggers && shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE)
+ return PxQueryHitType::eNONE;
+
+ const bool blockSingle = filterData.word1 != 0;
+ return blockSingle ? PxQueryHitType::eBLOCK : PxQueryHitType::eTOUCH;
+ }
+
+ PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override
+ {
+ // Not used
+ return PxQueryHitType::eNONE;
+ }
+};
+
+class CharacterQueryFilterPhysX : public PxQueryFilterCallback
+{
+ PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override
+ {
+ // Early out to avoid crashing
+ if (!shape)
+ return PxQueryHitType::eNONE;
+
+ // Let triggers through
+ if (PxFilterObjectIsTrigger(shape->getFlags()))
+ return PxQueryHitType::eNONE;
+
+ // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
+ const PxFilterData shapeFilter = shape->getQueryFilterData();
+ if (filterData.word0 & shapeFilter.word1)
+ return PxQueryHitType::eBLOCK;
+
+ return PxQueryHitType::eNONE;
+ }
+
+ PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override
+ {
+ // Not used
+ return PxQueryHitType::eNONE;
+ }
+};
+
+class CharacterControllerFilterPhysX : public PxControllerFilterCallback
+{
+ static PxShape* getShape(const PxController& controller)
+ {
+ PxRigidDynamic* actor = controller.getActor();
+
+ // Early out if no actor or no shapes
+ if (!actor || actor->getNbShapes() < 1)
+ return nullptr;
+
+ // Get first shape only
+ PxShape* shape = nullptr;
+ actor->getShapes(&shape, 1);
+
+ return shape;
+ }
+
+ bool filter(const PxController& a, const PxController& b) override
+ {
+ // Early out to avoid crashing
+ PxShape* shapeA = getShape(a);
+ if (!shapeA)
+ return false;
+
+ PxShape* shapeB = getShape(b);
+ if (!shapeB)
+ return false;
+
+ // Let triggers through
+ if (PxFilterObjectIsTrigger(shapeB->getFlags()))
+ return false;
+
+ // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
+ const PxFilterData shapeFilterA = shapeA->getQueryFilterData();
+ const PxFilterData shapeFilterB = shapeB->getQueryFilterData();
+ if (shapeFilterA.word0 & shapeFilterB.word1)
+ return true;
+
+ return false;
+ }
+};
+
+class WriteStreamPhysX : public PxOutputStream
+{
+public:
+ WriteStream* Stream;
+
+ uint32_t write(const void* src, uint32_t count) override
+ {
+ Stream->WriteBytes(src, (int32)count);
+ return count;
+ }
+};
+
+template
+class DynamicHitBuffer : public PxHitCallback
+{
+private:
+ uint32 _count;
+ HitType _buffer[PHYSX_HIT_BUFFER_SIZE];
+
+public:
+ DynamicHitBuffer()
+ : PxHitCallback(_buffer, PHYSX_HIT_BUFFER_SIZE)
+ , _count(0)
+ {
+ }
+
+public:
+ // Computes the number of any hits in this result, blocking or touching.
+ PX_INLINE PxU32 getNbAnyHits() const
+ {
+ return getNbTouches();
+ }
+
+ // Convenience iterator used to access any hits in this result, blocking or touching.
+ PX_INLINE const HitType& getAnyHit(const PxU32 index) const
+ {
+ PX_ASSERT(index < getNbTouches() + PxU32(this->hasBlock));
+ return index < getNbTouches() ? getTouches()[index] : this->block;
+ }
+
+ PX_INLINE PxU32 getNbTouches() const
+ {
+ return _count;
+ }
+
+ PX_INLINE const HitType* getTouches() const
+ {
+ return _buffer;
+ }
+
+ PX_INLINE const HitType& getTouch(const PxU32 index) const
+ {
+ PX_ASSERT(index < getNbTouches());
+ return _buffer[index];
+ }
+
+ PX_INLINE PxU32 getMaxNbTouches() const
+ {
+ return PHYSX_HIT_BUFFER_SIZE;
+ }
+
+protected:
+ PxAgain processTouches(const HitType* buffer, PxU32 nbHits) override
+ {
+ nbHits = Math::Min(nbHits, PHYSX_HIT_BUFFER_SIZE - _count);
+ for (PxU32 i = 0; i < nbHits; i++)
+ {
+ _buffer[_count + i] = buffer[i];
+ }
+ _count += nbHits;
+ return true;
+ }
+
+ void finalizeQuery() override
+ {
+ if (this->hasBlock)
+ {
+ // Blocking hits go to hits
+ processTouches(&this->block, 1);
+ }
+ }
+};
+
+#define SCENE_QUERY_SETUP(blockSingle) auto scenePhysX = (ScenePhysX*)scene; if (scene == nullptr) return false; \
+ const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; \
+ PxQueryFilterData filterData; \
+ filterData.flags |= PxQueryFlag::ePREFILTER; \
+ filterData.data.word0 = layerMask; \
+ filterData.data.word1 = blockSingle ? 1 : 0; \
+ filterData.data.word2 = hitTriggers ? 1 : 0
+
+#define SCENE_QUERY_SETUP_SWEEP_1() SCENE_QUERY_SETUP(true); \
+ PxSweepBufferN<1> buffer
+
+#define SCENE_QUERY_SETUP_SWEEP() SCENE_QUERY_SETUP(false); \
+ DynamicHitBuffer buffer
+
+#define SCENE_QUERY_SETUP_OVERLAP_1() SCENE_QUERY_SETUP(false); \
+ PxOverlapBufferN<1> buffer
+
+#define SCENE_QUERY_SETUP_OVERLAP() SCENE_QUERY_SETUP(false); \
+ DynamicHitBuffer buffer
+
+#define SCENE_QUERY_COLLECT_SINGLE() const auto& hit = buffer.getAnyHit(0); \
+ P2C(hit, hitInfo)
+
+#define SCENE_QUERY_COLLECT_ALL() results.Clear(); \
+ results.Resize(buffer.getNbAnyHits(), false); \
+ for (int32 i = 0; i < results.Count(); i++) \
+ { \
+ const auto& hit = buffer.getAnyHit(i); \
+ P2C(hit, results[i]); \
+ }
+
+#define SCENE_QUERY_COLLECT_OVERLAP() results.Clear(); \
+ results.Resize(buffer.getNbTouches(), false); \
+ for (int32 i = 0; i < results.Count(); i++) \
+ { \
+ auto& hitInfo = results[i]; \
+ const auto& hit = buffer.getTouch(i); \
+ hitInfo = hit.shape ? static_cast(hit.shape->userData) : nullptr; \
+ }
+
+#define SCENE_QUERY_COLLECT_OVERLAP_COLLIDER() results.Clear(); \
+ results.Resize(buffer.getNbTouches(), false); \
+ for (int32 i = 0; i < results.Count(); i++) \
+ { \
+ auto& hitInfo = results[i]; \
+ const auto& hit = buffer.getTouch(i); \
+ hitInfo = hit.shape ? static_cast(hit.shape->userData) : nullptr; \
+ }
+
+namespace
+{
+ PxFoundation* Foundation = nullptr;
+ PxPhysics* PhysX = nullptr;
+#if WITH_PVD
+ PxPvd* PVD = nullptr;
+#endif
+#if COMPILE_WITH_PHYSICS_COOKING
+ PxCooking* Cooking = nullptr;
+#endif
+ PxMaterial* DefaultMaterial = nullptr;
+ AllocatorPhysX AllocatorCallback;
+ ErrorPhysX ErrorCallback;
+ PxTolerancesScale ToleranceScale;
+ QueryFilterPhysX QueryFilter;
+ CharacterQueryFilterPhysX CharacterQueryFilter;
+ CharacterControllerFilterPhysX CharacterControllerFilter;
+
+ CriticalSection FlushLocker;
+ Array DeleteObjects;
+
+ bool _queriesHitTriggers = true;
+ PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average;
+ PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average;
+
+#if WITH_VEHICLE
+ bool VehicleSDKInitialized = false;
+ Array WheelVehiclesCache;
+ Array WheelQueryResults;
+ Array WheelHitResults;
+ Array WheelVehiclesResultsPerWheel;
+ Array WheelVehiclesResultsPerVehicle;
+ PxVehicleDrivableSurfaceToTireFrictionPairs* WheelTireFrictions = nullptr;
+#endif
+}
+
+PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled)
+{
+#if WITH_PVD
+ PxShapeFlags flags = PxShapeFlag::eVISUALIZATION;
+#else
+ PxShapeFlags flags = static_cast(0);
+#endif
+
+ if (isEnabled)
+ {
+ if (isTrigger)
+ {
+ flags |= PxShapeFlag::eTRIGGER_SHAPE;
+ if (_queriesHitTriggers)
+ flags |= PxShapeFlag::eSCENE_QUERY_SHAPE;
+ }
+ else
+ {
+ flags = PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eSCENE_QUERY_SHAPE;
+ }
+ }
+
+ return flags;
+}
+
+void GetShapeGeometry(const CollisionShape& shape, PxGeometryHolder& geometry)
+{
+ switch (shape.Type)
+ {
+ case CollisionShape::Types::Sphere:
+ geometry.storeAny(PxSphereGeometry(shape.Sphere.Radius));
+ break;
+ case CollisionShape::Types::Box:
+ geometry.storeAny(PxBoxGeometry(shape.Box.HalfExtents[0], shape.Box.HalfExtents[1], shape.Box.HalfExtents[2]));
+ break;
+ case CollisionShape::Types::Capsule:
+ geometry.storeAny(PxCapsuleGeometry(shape.Capsule.Radius, shape.Capsule.HalfHeight));
+ break;
+ case CollisionShape::Types::ConvexMesh:
+ geometry.storeAny(PxConvexMeshGeometry((PxConvexMesh*)shape.ConvexMesh.ConvexMesh, PxMeshScale(PxVec3(shape.ConvexMesh.Scale[0], shape.ConvexMesh.Scale[1], shape.ConvexMesh.Scale[2]))));
+ break;
+ case CollisionShape::Types::TriangleMesh:
+ geometry.storeAny(PxTriangleMeshGeometry((PxTriangleMesh*)shape.TriangleMesh.TriangleMesh, PxMeshScale(PxVec3(shape.TriangleMesh.Scale[0], shape.TriangleMesh.Scale[1], shape.TriangleMesh.Scale[2]))));
+ break;
+ case CollisionShape::Types::HeightField:
+ geometry.storeAny(PxHeightFieldGeometry((PxHeightField*)shape.HeightField.HeightField, PxMeshGeometryFlags(0), Math::Max(shape.HeightField.HeightScale, PX_MIN_HEIGHTFIELD_Y_SCALE), Math::Max(shape.HeightField.RowScale, PX_MIN_HEIGHTFIELD_XZ_SCALE), Math::Max(shape.HeightField.ColumnScale, PX_MIN_HEIGHTFIELD_XZ_SCALE)));
+ break;
+ }
+}
+
+PxFilterFlags FilterShader(
+ PxFilterObjectAttributes attributes0, PxFilterData filterData0,
+ PxFilterObjectAttributes attributes1, PxFilterData filterData1,
+ PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
+{
+ // Let triggers through
+ if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
+ {
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST;
+ pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
+ return PxFilterFlag::eDEFAULT;
+ }
+
+ // Send events for the kinematic actors but don't solve the contact
+ if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1))
+ {
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST;
+ pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
+ return PxFilterFlag::eSUPPRESS;
+ }
+
+ // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
+ if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
+ {
+ pairFlags |= PxPairFlag::eSOLVE_CONTACT;
+ pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
+ pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
+ pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY;
+ pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS;
+ return PxFilterFlag::eDEFAULT;
+ }
+
+ // Ignore pair (no collisions nor events)
+ return PxFilterFlag::eKILL;
+}
+
+#if WITH_VEHICLE
+
+void InitVehicleSDK()
+{
+ if (!VehicleSDKInitialized)
+ {
+ VehicleSDKInitialized = true;
+ PxInitVehicleSDK(*PhysX);
+ PxVehicleSetBasisVectors(PxVec3(0, 1, 0), PxVec3(1, 0, 0));
+ PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE);
+ }
+}
+
+PxQueryHitType::Enum WheelRaycastPreFilter(PxFilterData filterData0, PxFilterData filterData1, const void* constantBlock, PxU32 constantBlockSize, PxHitFlags& queryFlags)
+{
+ // Hardcoded id for vehicle shapes masking
+ if (filterData0.word3 == filterData1.word3)
+ {
+ return PxQueryHitType::eNONE;
+ }
+
+ // Collide for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
+ if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
+ {
+ return PxQueryHitType::eBLOCK;
+ }
+
+ return PxQueryHitType::eNONE;
+}
+
+#endif
+
+void* PhysicalMaterial::GetPhysicsMaterial()
+{
+ if (_material == nullptr && PhysX)
+ {
+ auto material = PhysX->createMaterial(Friction, Friction, Restitution);
+ material->userData = this;
+ _material = material;
+
+ const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode;
+ material->setFrictionCombineMode(static_cast(useFrictionCombineMode));
+
+ const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
+ material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode));
+ }
+ return _material;
+}
+
+void PhysicalMaterial::UpdatePhysicsMaterial()
+{
+ auto material = (PxMaterial*)_material;
+ if (material != nullptr)
+ {
+ material->setStaticFriction(Friction);
+ material->setDynamicFriction(Friction);
+
+ const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode;
+ material->setFrictionCombineMode(static_cast(useFrictionCombineMode));
+
+ material->setRestitution(Restitution);
+ const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
+ material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode));
+ }
+}
+
+#if COMPILE_WITH_PHYSICS_COOKING
+
+#define ENSURE_CAN_COOK \
+ auto cooking = Cooking; \
+ if (cooking == nullptr) \
+ { \
+ LOG(Warning, "Physics collisions cooking is disabled at runtime. Enable Physics Settings option SupportCookingAtRuntime to use collision generation at runtime."); \
+ return true; \
+ }
+
+bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output)
+{
+ ENSURE_CAN_COOK;
+ if (input.VertexCount == 0)
+ LOG(Warning, "Empty mesh data for collision cooking.");
+
+ // Init options
+ PxConvexMeshDesc desc;
+ desc.points.count = input.VertexCount;
+ desc.points.stride = sizeof(Vector3);
+ desc.points.data = input.VertexData;
+ desc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
+ if (input.ConvexVertexLimit == 0)
+ desc.vertexLimit = CONVEX_VERTEX_MAX;
+ else
+ desc.vertexLimit = (PxU16)Math::Clamp(input.ConvexVertexLimit, CONVEX_VERTEX_MIN, CONVEX_VERTEX_MAX);
+ if (input.ConvexFlags & ConvexMeshGenerationFlags::SkipValidation)
+ desc.flags |= PxConvexFlag::Enum::eDISABLE_MESH_VALIDATION;
+ if (input.ConvexFlags & ConvexMeshGenerationFlags::UsePlaneShifting)
+ desc.flags |= PxConvexFlag::Enum::ePLANE_SHIFTING;
+ if (input.ConvexFlags & ConvexMeshGenerationFlags::UseFastInteriaComputation)
+ desc.flags |= PxConvexFlag::Enum::eFAST_INERTIA_COMPUTATION;
+ if (input.ConvexFlags & ConvexMeshGenerationFlags::ShiftVertices)
+ desc.flags |= PxConvexFlag::Enum::eSHIFT_VERTICES;
+ PxCookingParams cookingParams = cooking->getParams();
+ cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable;
+ cooking->setParams(cookingParams);
+
+ // Perform cooking
+ PxDefaultMemoryOutputStream outputStream;
+ PxConvexMeshCookingResult::Enum result;
+ if (!cooking->cookConvexMesh(desc, outputStream, &result))
+ {
+ LOG(Warning, "Convex Mesh cooking failed. Error code: {0}, Input vertices count: {1}", result, input.VertexCount);
+ return true;
+ }
+
+ // Copy result
+ output.Copy(outputStream.getData(), outputStream.getSize());
+
+ return false;
+}
+
+bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output)
+{
+ ENSURE_CAN_COOK;
+ if (input.VertexCount == 0 || input.IndexCount == 0)
+ LOG(Warning, "Empty mesh data for collision cooking.");
+
+ // Init options
+ PxTriangleMeshDesc desc;
+ desc.points.count = input.VertexCount;
+ desc.points.stride = sizeof(Vector3);
+ desc.points.data = input.VertexData;
+ desc.triangles.count = input.IndexCount / 3;
+ desc.triangles.stride = 3 * (input.Is16bitIndexData ? sizeof(uint16) : sizeof(uint32));
+ desc.triangles.data = input.IndexData;
+ desc.flags = input.Is16bitIndexData ? PxMeshFlag::e16_BIT_INDICES : (PxMeshFlag::Enum)0;
+ PxCookingParams cookingParams = cooking->getParams();
+ cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable;
+ cooking->setParams(cookingParams);
+
+ // Perform cooking
+ PxDefaultMemoryOutputStream outputStream;
+ PxTriangleMeshCookingResult::Enum result;
+ if (!cooking->cookTriangleMesh(desc, outputStream, &result))
+ {
+ LOG(Warning, "Triangle Mesh cooking failed. Error code: {0}, Input vertices count: {1}, indices count: {2}", result, input.VertexCount, input.IndexCount);
+ return true;
+ }
+
+ // Copy result
+ output.Copy(outputStream.getData(), outputStream.getSize());
+
+ return false;
+}
+
+bool CollisionCooking::CookHeightField(int32 cols, int32 rows, const PhysicsBackend::HeightFieldSample* data, WriteStream& stream)
+{
+ ENSURE_CAN_COOK;
+
+ PxHeightFieldDesc heightFieldDesc;
+ heightFieldDesc.format = PxHeightFieldFormat::eS16_TM;
+ heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES;
+ heightFieldDesc.nbColumns = cols;
+ heightFieldDesc.nbRows = rows;
+ heightFieldDesc.samples.data = data;
+ heightFieldDesc.samples.stride = sizeof(PhysicsBackend::HeightFieldSample);
+
+ WriteStreamPhysX outputStream;
+ outputStream.Stream = &stream;
+ if (!Cooking->cookHeightField(heightFieldDesc, outputStream))
+ {
+ LOG(Warning, "Height Field collision cooking failed.");
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+PxPhysics* PhysicsBackendPhysX::GetPhysics()
+{
+ return PhysX;
+}
+
+#if COMPILE_WITH_PHYSICS_COOKING
+
+PxCooking* PhysicsBackendPhysX::GetCooking()
+{
+ return Cooking;
+}
+
+#endif
+
+PxMaterial* PhysicsBackendPhysX::GetDefaultMaterial()
+{
+ return DefaultMaterial;
+}
+
+bool PhysicsBackend::Init()
+{
+#define CHECK_INIT(value, msg) if (!value) { LOG(Error, msg); return true; }
+ auto& settings = *PhysicsSettings::Get();
+
+ // Init PhysX foundation object
+ LOG(Info, "Setup NVIDIA PhysX {0}.{1}.{2}", PX_PHYSICS_VERSION_MAJOR, PX_PHYSICS_VERSION_MINOR, PX_PHYSICS_VERSION_BUGFIX);
+ Foundation = PxCreateFoundation(PX_PHYSICS_VERSION, AllocatorCallback, ErrorCallback);
+ CHECK_INIT(Foundation, "PxCreateFoundation failed!");
+
+ // Init debugger
+ PxPvd* pvd = nullptr;
+#if WITH_PVD
+ {
+ // Init PVD
+ pvd = PxCreatePvd(*Foundation);
+ PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("127.0.0.1", 5425, 100);
+ //PxPvdTransport* transport = PxDefaultPvdFileTransportCreate("D:\\physx_sample.pxd2");
+ if (transport)
+ {
+ const bool isConnected = pvd->connect(*transport, PxPvdInstrumentationFlag::eALL);
+ if (isConnected)
+ {
+ LOG(Info, "Connected to PhysX Visual Debugger (PVD)");
+ }
+ }
+ PVD = pvd;
+ }
+
+#endif
+
+ // Init PhysX
+ ToleranceScale.length = 100;
+ ToleranceScale.speed = 981;
+ PhysX = PxCreatePhysics(PX_PHYSICS_VERSION, *Foundation, ToleranceScale, false, pvd);
+ CHECK_INIT(PhysX, "PxCreatePhysics failed!");
+
+ // Init extensions
+ const bool extensionsInit = PxInitExtensions(*PhysX, pvd);
+ CHECK_INIT(extensionsInit, "PxInitExtensions failed!");
+
+ // Init collision cooking
+#if COMPILE_WITH_PHYSICS_COOKING
+#if !USE_EDITOR
+ if (settings.SupportCookingAtRuntime)
+#endif
+ {
+ PxCookingParams cookingParams(ToleranceScale);
+ cookingParams.meshWeldTolerance = 0.1f; // 1mm precision
+ cookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES);
+ Cooking = PxCreateCooking(PX_PHYSICS_VERSION, *Foundation, cookingParams);
+ CHECK_INIT(Cooking, "PxCreateCooking failed!");
+ }
+#endif
+
+ // Create default material
+ DefaultMaterial = PhysX->createMaterial(0.7f, 0.7f, 0.3f);
+
+ return false;
+}
+
+void PhysicsBackend::Shutdown()
+{
+ // Remove all scenes still registered
+ const int32 numScenes = PhysX ? PhysX->getNbScenes() : 0;
+ if (numScenes)
+ {
+ Array scenes;
+ scenes.Resize(numScenes);
+ scenes.SetAll(nullptr);
+ PhysX->getScenes(scenes.Get(), sizeof(PxScene*) * numScenes);
+ for (PxScene* scene : scenes)
+ {
+ if (scene)
+ scene->release();
+ }
+ }
+
+ // Cleanup any resources
+#if WITH_VEHICLE
+ RELEASE_PHYSX(WheelTireFrictions);
+ WheelQueryResults.Resize(0);
+ WheelHitResults.Resize(0);
+ WheelVehiclesResultsPerWheel.Resize(0);
+ WheelVehiclesResultsPerVehicle.Resize(0);
+#endif
+ RELEASE_PHYSX(DefaultMaterial);
+
+ // Shutdown PhysX
+#if WITH_VEHICLE
+ if (VehicleSDKInitialized)
+ {
+ VehicleSDKInitialized = false;
+ PxCloseVehicleSDK();
+ }
+#endif
+#if COMPILE_WITH_PHYSICS_COOKING
+ RELEASE_PHYSX(Cooking);
+#endif
+ if (PhysX)
+ {
+ PxCloseExtensions();
+ PhysX->release();
+ PhysX = nullptr;
+ }
+#if WITH_PVD
+ RELEASE_PHYSX(PVD);
+#endif
+ RELEASE_PHYSX(Foundation);
+}
+
+void PhysicsBackend::ApplySettings(const PhysicsSettings& settings)
+{
+ _queriesHitTriggers = settings.QueriesHitTriggers;
+ _frictionCombineMode = settings.FrictionCombineMode;
+ _restitutionCombineMode = settings.RestitutionCombineMode;
+
+ // TODO: setting eADAPTIVE_FORCE requires PxScene setup (physx docs: This flag is not mutable, and must be set in PxSceneDesc at scene creation.)
+ // TODO: update all shapes filter data
+ // TODO: update all shapes flags
+
+ /*
+ {
+ get all actors and then:
+
+ const PxU32 numShapes = actor->getNbShapes();
+ PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes);
+ actor->getShapes(shapes, numShapes);
+ for (PxU32 i = 0; i < numShapes; i++)
+ {
+ ..
+ }
+ SAMPLE_FREE(shapes);
+ }*/
+}
+
+void* PhysicsBackend::CreateScene(const PhysicsSettings& settings)
+{
+#define CHECK_INIT(value, msg) if (!value) { LOG(Error, msg); return nullptr; }
+ auto scenePhysX = New();
+
+ // Create scene description
+ PxSceneDesc sceneDesc(ToleranceScale);
+ sceneDesc.gravity = C2P(settings.DefaultGravity);
+ sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVE_ACTORS;
+ if (!settings.DisableCCD)
+ sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
+ if (settings.EnableAdaptiveForce)
+ sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE;
+ sceneDesc.simulationEventCallback = &scenePhysX->EventsCallback;
+ sceneDesc.filterShader = FilterShader;
+ sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity;
+ if (sceneDesc.cpuDispatcher == nullptr)
+ {
+ scenePhysX->CpuDispatcher = PxDefaultCpuDispatcherCreate(Math::Clamp(Platform::GetCPUInfo().ProcessorCoreCount - 1, 1, 4));
+ CHECK_INIT(scenePhysX->CpuDispatcher, "PxDefaultCpuDispatcherCreate failed!");
+ sceneDesc.cpuDispatcher = scenePhysX->CpuDispatcher;
+ }
+
+ // Create scene
+ scenePhysX->Scene = PhysX->createScene(sceneDesc);
+ CHECK_INIT(scenePhysX->Scene, "createScene failed!");
+#if WITH_PVD
+ auto pvdClient = scenePhysX->Scene->getScenePvdClient();
+ if (pvdClient)
+ {
+ pvdClient->setScenePvdFlags(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS | PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES | PxPvdSceneFlag::eTRANSMIT_CONTACTS);
+ }
+ else
+ {
+ LOG(Info, "Missing PVD client scene.");
+ }
+#endif
+
+ // Init characters controller
+ scenePhysX->ControllerManager = PxCreateControllerManager(*scenePhysX->Scene);
+
+#undef CHECK_INIT
+ return scenePhysX;
+}
+
+void PhysicsBackend::DestroyScene(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+
+ // Flush any latent actions related to this scene
+ FlushRequests(scene);
+
+ // Release resources
+#if WITH_VEHICLE
+ RELEASE_PHYSX(scenePhysX->WheelRaycastBatchQuery);
+#endif
+ RELEASE_PHYSX(scenePhysX->ControllerManager);
+ SAFE_DELETE(scenePhysX->CpuDispatcher);
+ Allocator::Free(scenePhysX->ScratchMemory);
+ scenePhysX->Scene->release();
+
+ Delete(scene);
+}
+
+void PhysicsBackend::StartSimulateScene(void* scene, float dt)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ const auto& settings = *PhysicsSettings::Get();
+
+ // Clamp delta
+ dt = Math::Clamp(dt, 0.0f, settings.MaxDeltaTime);
+
+ // Prepare util objects
+ if (scenePhysX->ScratchMemory == nullptr)
+ {
+ scenePhysX->ScratchMemory = Allocator::Allocate(PHYSX_SCRATCH_BLOCK_SIZE, 16);
+ }
+ if (settings.EnableSubstepping)
+ {
+ // Use substeps
+ scenePhysX->Stepper.Setup(settings.SubstepDeltaTime, settings.MaxSubsteps);
+ }
+ else
+ {
+ // Use single step
+ scenePhysX->Stepper.Setup(dt);
+ }
+
+ // Start simulation (may not be fired due to too small delta time)
+ if (scenePhysX->Stepper.advance(scenePhysX->Scene, dt, scenePhysX->ScratchMemory, PHYSX_SCRATCH_BLOCK_SIZE) == false)
+ return;
+ scenePhysX->EventsCallback.Clear();
+ scenePhysX->LastDeltaTime = dt;
+
+ // TODO: move this call after rendering done
+ scenePhysX->Stepper.renderDone();
+}
+
+void PhysicsBackend::EndSimulateScene(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+
+ {
+ PROFILE_CPU_NAMED("Physics.Fetch");
+
+ // Gather results (with waiting for the end)
+ scenePhysX->Stepper.wait(scenePhysX->Scene);
+ }
+
+#if WITH_VEHICLE
+ if (scenePhysX->WheelVehicles.HasItems())
+ {
+ PROFILE_CPU_NAMED("Physics.Vehicles");
+
+ // Update vehicles steering
+ WheelVehiclesCache.Clear();
+ WheelVehiclesCache.EnsureCapacity(scenePhysX->WheelVehicles.Count());
+ int32 wheelsCount = 0;
+ for (auto wheelVehicle : scenePhysX->WheelVehicles)
+ {
+ if (!wheelVehicle->IsActiveInHierarchy())
+ continue;
+ auto drive = (PxVehicleWheels*)wheelVehicle->_vehicle;
+ ASSERT(drive);
+ WheelVehiclesCache.Add(drive);
+ wheelsCount += drive->mWheelsSimData.getNbWheels();
+
+ float throttle = wheelVehicle->_throttle;
+ float brake = wheelVehicle->_brake;
+ if (wheelVehicle->UseReverseAsBrake)
+ {
+ const float invalidDirectionThreshold = 80.0f;
+ const float breakThreshold = 8.0f;
+ const float forwardSpeed = wheelVehicle->GetForwardSpeed();
+
+ // Automatic gear change when changing driving direction
+ if (Math::Abs(forwardSpeed) < invalidDirectionThreshold)
+ {
+ if (throttle < -ZeroTolerance && wheelVehicle->GetCurrentGear() >= 0 && wheelVehicle->GetTargetGear() >= 0)
+ {
+ wheelVehicle->SetCurrentGear(-1);
+ }
+ else if (throttle > ZeroTolerance && wheelVehicle->GetCurrentGear() <= 0 && wheelVehicle->GetTargetGear() <= 0)
+ {
+ wheelVehicle->SetCurrentGear(1);
+ }
+ }
+
+ // Automatic break when changing driving direction
+ if (throttle > 0.0f)
+ {
+ if (forwardSpeed < -invalidDirectionThreshold)
+ {
+ brake = 1.0f;
+ }
+ }
+ else if (throttle < 0.0f)
+ {
+ if (forwardSpeed > invalidDirectionThreshold)
+ {
+ brake = 1.0f;
+ }
+ }
+ else
+ {
+ if (forwardSpeed < breakThreshold && forwardSpeed > -breakThreshold)
+ {
+ brake = 1.0f;
+ }
+ }
+
+ // Block throttle if user is changing driving direction
+ if ((throttle > 0.0f && wheelVehicle->GetTargetGear() < 0) || (throttle < 0.0f && wheelVehicle->GetTargetGear() > 0))
+ {
+ throttle = 0.0f;
+ }
+
+ throttle = Math::Abs(throttle);
+ }
+ else
+ {
+ throttle = Math::Max(throttle, 0.0f);
+ }
+ // @formatter:off
+ // Reference: PhysX SDK docs
+ // TODO: expose input control smoothing data
+ static constexpr PxVehiclePadSmoothingData padSmoothing =
+ {
+ {
+ 6.0f, // rise rate eANALOG_INPUT_ACCEL
+ 6.0f, // rise rate eANALOG_INPUT_BRAKE
+ 12.0f, // rise rate eANALOG_INPUT_HANDBRAKE
+ 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT
+ 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT
+ },
+ {
+ 10.0f, // fall rate eANALOG_INPUT_ACCEL
+ 10.0f, // fall rate eANALOG_INPUT_BRAKE
+ 12.0f, // fall rate eANALOG_INPUT_HANDBRAKE
+ 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT
+ 5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT
+ }
+ };
+ PxVehicleKeySmoothingData keySmoothing =
+ {
+ {
+ 3.0f, // rise rate eANALOG_INPUT_ACCEL
+ 3.0f, // rise rate eANALOG_INPUT_BRAKE
+ 10.0f, // rise rate eANALOG_INPUT_HANDBRAKE
+ 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT
+ 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT
+ },
+ {
+ 5.0f, // fall rate eANALOG_INPUT__ACCEL
+ 5.0f, // fall rate eANALOG_INPUT__BRAKE
+ 10.0f, // fall rate eANALOG_INPUT__HANDBRAKE
+ 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT
+ 5.0f // fall rate eANALOG_INPUT_STEER_RIGHT
+ }
+ };
+ // Reference: PhysX SDK docs
+ // TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range)
+ static constexpr PxF32 steerVsForwardSpeedData[] =
+ {
+ 0.0f, 1.0f,
+ 20.0f, 0.9f,
+ 65.0f, 0.8f,
+ 120.0f, 0.7f,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32,
+ };
+ const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
+ // @formatter:on
+ if (wheelVehicle->UseAnalogSteering)
+ {
+ switch (wheelVehicle->_driveTypeCurrent)
+ {
+ case WheeledVehicle::DriveTypes::Drive4W:
+ {
+ PxVehicleDrive4WRawInputData rawInputData;
+ rawInputData.setAnalogAccel(throttle);
+ rawInputData.setAnalogBrake(brake);
+ rawInputData.setAnalogSteer(wheelVehicle->_steering);
+ rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
+ PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDrive4W*)drive);
+ break;
+ }
+ case WheeledVehicle::DriveTypes::DriveNW:
+ {
+ PxVehicleDriveNWRawInputData rawInputData;
+ rawInputData.setAnalogAccel(throttle);
+ rawInputData.setAnalogBrake(brake);
+ rawInputData.setAnalogSteer(wheelVehicle->_steering);
+ rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
+ PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDriveNW*)drive);
+ break;
+ }
+ }
+ }
+ else
+ {
+ const float deadZone = 0.1f;
+ switch (wheelVehicle->_driveTypeCurrent)
+ {
+ case WheeledVehicle::DriveTypes::Drive4W:
+ {
+ PxVehicleDrive4WRawInputData rawInputData;
+ rawInputData.setDigitalAccel(throttle > deadZone);
+ rawInputData.setDigitalBrake(brake > deadZone);
+ rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
+ rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
+ rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
+ PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDrive4W*)drive);
+ break;
+ }
+ case WheeledVehicle::DriveTypes::DriveNW:
+ {
+ PxVehicleDriveNWRawInputData rawInputData;
+ rawInputData.setDigitalAccel(throttle > deadZone);
+ rawInputData.setDigitalBrake(brake > deadZone);
+ rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
+ rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
+ rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
+ PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDriveNW*)drive);
+ break;
+ }
+ }
+ }
+ }
+
+ // Update batches queries cache
+ if (wheelsCount > WheelQueryResults.Count())
+ {
+ if (scenePhysX->WheelRaycastBatchQuery)
+ scenePhysX->WheelRaycastBatchQuery->release();
+ WheelQueryResults.Resize(wheelsCount, false);
+ WheelHitResults.Resize(wheelsCount, false);
+ PxBatchQueryDesc desc(wheelsCount, 0, 0);
+ desc.queryMemory.userRaycastResultBuffer = WheelQueryResults.Get();
+ desc.queryMemory.userRaycastTouchBuffer = WheelHitResults.Get();
+ desc.queryMemory.raycastTouchBufferSize = wheelsCount;
+ desc.preFilterShader = WheelRaycastPreFilter;
+ scenePhysX->WheelRaycastBatchQuery = scenePhysX->Scene->createBatchQuery(desc);
+ }
+
+ // TODO: expose vehicle tires configuration
+ if (!WheelTireFrictions)
+ {
+ PxVehicleDrivableSurfaceType surfaceTypes[1];
+ surfaceTypes[0].mType = 0;
+ const PxMaterial* surfaceMaterials[1];
+ surfaceMaterials[0] = DefaultMaterial;
+ WheelTireFrictions = PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(1, 1);
+ WheelTireFrictions->setup(1, 1, surfaceMaterials, surfaceTypes);
+ WheelTireFrictions->setTypePairFriction(0, 0, 5.0f);
+ }
+
+ // Setup cache for wheel states
+ WheelVehiclesResultsPerVehicle.Resize(WheelVehiclesCache.Count(), false);
+ WheelVehiclesResultsPerWheel.Resize(wheelsCount, false);
+ wheelsCount = 0;
+ for (int32 i = 0, ii = 0; i < scenePhysX->WheelVehicles.Count(); i++)
+ {
+ auto wheelVehicle = scenePhysX->WheelVehicles[i];
+ if (!wheelVehicle->IsActiveInHierarchy())
+ continue;
+ auto drive = (PxVehicleWheels*)scenePhysX->WheelVehicles[ii]->_vehicle;
+ auto& perVehicle = WheelVehiclesResultsPerVehicle[ii];
+ ii++;
+ perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels();
+ perVehicle.wheelQueryResults = WheelVehiclesResultsPerWheel.Get() + wheelsCount;
+ wheelsCount += perVehicle.nbWheelQueryResults;
+ }
+
+ // Update vehicles
+ if (WheelVehiclesCache.Count() != 0)
+ {
+ PxVehicleSuspensionRaycasts(scenePhysX->WheelRaycastBatchQuery, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelQueryResults.Count(), WheelQueryResults.Get());
+ PxVehicleUpdates(scenePhysX->LastDeltaTime, scenePhysX->Scene->getGravity(), *WheelTireFrictions, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelVehiclesResultsPerVehicle.Get());
+ }
+
+ // Synchronize state
+ for (int32 i = 0, ii = 0; i < scenePhysX->WheelVehicles.Count(); i++)
+ {
+ auto wheelVehicle = scenePhysX->WheelVehicles[i];
+ if (!wheelVehicle->IsActiveInHierarchy())
+ continue;
+ auto drive = WheelVehiclesCache[ii];
+ auto& perVehicle = WheelVehiclesResultsPerVehicle[ii];
+ ii++;
+#if PHYSX_VEHICLE_DEBUG_TELEMETRY
+ LOG(Info, "Vehicle[{}] Gear={}, RPM={}", ii, wheelVehicle->GetCurrentGear(), (int32)wheelVehicle->GetEngineRotationSpeed());
+#endif
+
+ // Update wheels
+ for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++)
+ {
+ auto& wheelData = wheelVehicle->_wheelsData[j];
+ auto& perWheel = perVehicle.wheelQueryResults[j];
+#if PHYSX_VEHICLE_DEBUG_TELEMETRY
+ LOG(Info, "Vehicle[{}] Wheel[{}] longitudinalSlip={}, lateralSlip={}, suspSpringForce={}", ii, j, Utilities::RoundTo2DecimalPlaces(perWheel.longitudinalSlip), Utilities::RoundTo2DecimalPlaces(perWheel.lateralSlip), (int32)perWheel.suspSpringForce);
+#endif
+
+ auto& state = wheelData.State;
+ state.IsInAir = perWheel.isInAir;
+ state.TireContactCollider = perWheel.tireContactShape ? static_cast(perWheel.tireContactShape->userData) : nullptr;
+ state.TireContactPoint = P2C(perWheel.tireContactPoint);
+ state.TireContactNormal = P2C(perWheel.tireContactNormal);
+ state.TireFriction = perWheel.tireFriction;
+ state.SteerAngle = RadiansToDegrees * perWheel.steerAngle;
+ state.RotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j);
+ state.SuspensionOffset = perWheel.suspJounce;
+#if USE_EDITOR
+ state.SuspensionTraceStart = P2C(perWheel.suspLineStart);
+ state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength);
+#endif
+
+ if (!wheelData.Collider)
+ continue;
+ auto shape = (PxShape*)wheelData.Collider->GetPhysicsShape();
+
+ // Update wheel collider transformation
+ auto localPose = shape->getLocalPose();
+ Transform t = wheelData.Collider->GetLocalTransform();
+ t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation;
+ t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter();
+ wheelData.Collider->SetLocalTransform(t);
+ }
+ }
+ }
+#endif
+
+ {
+ PROFILE_CPU_NAMED("Physics.FlushActiveTransforms");
+
+ // Gather change info
+ PxU32 activeActorsCount;
+ PxActor** activeActors = scenePhysX->Scene->getActiveActors(activeActorsCount);
+ if (activeActorsCount > 0)
+ {
+ // Update changed transformations
+ // TODO: use jobs system if amount if huge
+ for (uint32 i = 0; i < activeActorsCount; i++)
+ {
+ const auto pxActor = (PxRigidActor*)*activeActors++;
+ auto actor = static_cast(pxActor->userData);
+ if (actor)
+ actor->OnActiveTransformChanged();
+ }
+ }
+ }
+
+ {
+ PROFILE_CPU_NAMED("Physics.SendEvents");
+
+ scenePhysX->EventsCallback.CollectResults();
+ scenePhysX->EventsCallback.SendTriggerEvents();
+ scenePhysX->EventsCallback.SendCollisionEvents();
+ scenePhysX->EventsCallback.SendJointEvents();
+ }
+}
+
+Vector3 PhysicsBackend::GetSceneGravity(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ return P2C(scenePhysX->Scene->getGravity());
+}
+
+void PhysicsBackend::SetSceneGravity(void* scene, const Vector3& value)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ scenePhysX->Scene->setGravity(C2P(value));
+}
+
+bool PhysicsBackend::GetSceneEnableCCD(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ return (scenePhysX->Scene->getFlags() & PxSceneFlag::eENABLE_CCD) == PxSceneFlag::eENABLE_CCD;
+}
+
+void PhysicsBackend::SetSceneEnableCCD(void* scene, bool value)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ scenePhysX->Scene->setFlag(PxSceneFlag::eENABLE_CCD, value);
+}
+
+float PhysicsBackend::GetSceneBounceThresholdVelocity(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ return scenePhysX->Scene->getBounceThresholdVelocity();
+}
+
+void PhysicsBackend::SetSceneBounceThresholdVelocity(void* scene, float value)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ scenePhysX->Scene->setBounceThresholdVelocity(value);
+}
+
+void PhysicsBackend::AddSceneActor(void* scene, void* actor)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ FlushLocker.Lock();
+ scenePhysX->AddActors.Add((PxActor*)actor);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::RemoveSceneActor(void* scene, void* actor)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ FlushLocker.Lock();
+ scenePhysX->RemoveActors.Add((PxActor*)actor);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::AddSceneActorAction(void* scene, void* actor, ActionType action)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ FlushLocker.Lock();
+ auto& a = scenePhysX->Actions.AddOne();
+ a.Actor = (PxActor*)actor;
+ a.Type = action;
+ FlushLocker.Unlock();
+}
+
+bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP(true);
+ PxRaycastBuffer buffer;
+ return scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP(true);
+ PxRaycastBuffer buffer;
+ if (!scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_SINGLE();
+ return true;
+}
+
+bool PhysicsBackend::RayCastAll(void* scene, const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP(false);
+ DynamicHitBuffer buffer;
+ if (!scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_ALL();
+ return true;
+}
+
+bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_SINGLE();
+ return true;
+}
+
+bool PhysicsBackend::BoxCastAll(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_ALL();
+ return true;
+}
+
+bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_SINGLE();
+ return true;
+}
+
+bool PhysicsBackend::SphereCastAll(void* scene, const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_ALL();
+ return true;
+}
+
+bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_SINGLE();
+ return true;
+}
+
+bool PhysicsBackend::CapsuleCastAll(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_SWEEP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_ALL();
+ return true;
+}
+
+bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_SWEEP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_SINGLE();
+ return true;
+}
+
+bool PhysicsBackend::ConvexCastAll(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_SWEEP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_ALL();
+ return true;
+}
+
+bool PhysicsBackend::CheckBox(void* scene, const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::CheckSphere(void* scene, const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP_1();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::CheckCapsule(void* scene, const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::CheckConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_OVERLAP_1();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter);
+}
+
+bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
+ return true;
+}
+
+bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
+ return true;
+}
+
+bool PhysicsBackend::OverlapCapsule(void* scene, const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
+ return true;
+}
+
+bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
+ return true;
+}
+
+bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxBoxGeometry geometry(C2P(halfExtents));
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP();
+ return true;
+}
+
+bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center));
+ const PxSphereGeometry geometry(radius);
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP();
+ return true;
+}
+
+bool PhysicsBackend::OverlapCapsule(void* scene, const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxCapsuleGeometry geometry(radius, height * 0.5f);
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP();
+ return true;
+}
+
+bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
+ SCENE_QUERY_SETUP_OVERLAP();
+ const PxTransform pose(C2P(center), C2P(rotation));
+ const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
+ if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter))
+ return false;
+ SCENE_QUERY_COLLECT_OVERLAP();
+ return true;
+}
+
+PhysicsBackend::ActorFlags PhysicsBackend::GetActorFlags(void* actor)
+{
+ auto actorPhysX = (PxActor*)actor;
+ auto flags = actorPhysX->getActorFlags();
+ auto result = ActorFlags::None;
+ if (flags & PxActorFlag::eDISABLE_GRAVITY)
+ result |= ActorFlags::NoGravity;
+ if (flags & PxActorFlag::eDISABLE_SIMULATION)
+ result |= ActorFlags::NoSimulation;
+ return result;
+}
+
+void PhysicsBackend::SetActorFlags(void* actor, ActorFlags value)
+{
+ auto actorPhysX = (PxActor*)actor;
+ auto flags = (PxActorFlags)0;
+#if WITH_PVD
+ flags |= PxActorFlag::eVISUALIZATION;
+#endif
+ if (value & ActorFlags::NoGravity)
+ flags |= PxActorFlag::eDISABLE_GRAVITY;
+ if (value & ActorFlags::NoSimulation)
+ flags |= PxActorFlag::eDISABLE_SIMULATION;
+ actorPhysX->setActorFlags(flags);
+}
+
+void PhysicsBackend::GetActorBounds(void* actor, BoundingBox& bounds)
+{
+ auto actorPhysX = (PxActor*)actor;
+ const float boundsScale = 1.02f;
+ bounds = P2C(actorPhysX->getWorldBounds(boundsScale));
+}
+
+void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation)
+{
+ const PxTransform trans(C2P(position), C2P(orientation));
+ PxRigidDynamic* actorPhysX = PhysX->createRigidDynamic(trans);
+ actorPhysX->userData = actor;
+#if PHYSX_DEBUG_NAMING
+ actorPhysX->setName("RigidDynamicActor");
+#endif
+#if WITH_PVD
+ actorPhysX->setActorFlag(PxActorFlag::eVISUALIZATION, true);
+#endif
+ return actorPhysX;
+}
+
+void* PhysicsBackend::CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation)
+{
+ const PxTransform trans(C2P(position), C2P(orientation));
+ PxRigidStatic* actorPhysX = PhysX->createRigidStatic(trans);
+ actorPhysX->userData = actor;
+#if PHYSX_DEBUG_NAMING
+ actorPhysX->setName("RigidStaticActor");
+#endif
+#if WITH_PVD
+ actorPhysX->setActorFlag(PxActorFlag::eVISUALIZATION, true);
+#endif
+ return actorPhysX;
+}
+
+PhysicsBackend::RigidDynamicFlags PhysicsBackend::GetRigidDynamicActorFlags(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ auto flags = actorPhysX->getRigidBodyFlags();
+ auto result = RigidDynamicFlags::None;
+ if (flags & PxRigidBodyFlag::eKINEMATIC)
+ result |= RigidDynamicFlags::Kinematic;
+ if (flags & PxRigidBodyFlag::eENABLE_CCD)
+ result |= RigidDynamicFlags::CCD;
+ return result;
+}
+
+void PhysicsBackend::SetRigidDynamicActorFlags(void* actor, RigidDynamicFlags value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ auto flags = (PxRigidBodyFlags)0;
+ if (value & RigidDynamicFlags::Kinematic)
+ flags |= PxRigidBodyFlag::eKINEMATIC;
+ if (value & RigidDynamicFlags::CCD)
+ flags |= PxRigidBodyFlag::eENABLE_CCD;
+ actorPhysX->setRigidBodyFlags(flags);
+}
+
+void PhysicsBackend::GetRigidActorPose(void* actor, Vector3& position, Quaternion& orientation)
+{
+ auto actorPhysX = (PxRigidActor*)actor;
+ auto pose = actorPhysX->getGlobalPose();
+ position = P2C(pose.p);
+ orientation = P2C(pose.q);
+}
+
+void PhysicsBackend::SetRigidActorPose(void* actor, const Vector3& position, const Quaternion& orientation, bool kinematic, bool wakeUp)
+{
+ const PxTransform trans(C2P(position), C2P(orientation));
+ if (kinematic)
+ {
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setKinematicTarget(trans);
+ }
+ else
+ {
+ auto actorPhysX = (PxRigidActor*)actor;
+ actorPhysX->setGlobalPose(trans, wakeUp);
+ }
+}
+
+void PhysicsBackend::SetRigidDynamicActorLinearDamping(void* actor, float value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setLinearDamping(value);
+}
+
+void PhysicsBackend::SetRigidDynamicActorAngularDamping(void* actor, float value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setAngularDamping(value);
+}
+
+void PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(void* actor, float value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setMaxAngularVelocity(value);
+}
+
+void PhysicsBackend::SetRigidDynamicActorConstraints(void* actor, RigidbodyConstraints value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setRigidDynamicLockFlags(static_cast(value));
+}
+
+Vector3 PhysicsBackend::GetRigidDynamicActorLinearVelocity(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return P2C(actorPhysX->getLinearVelocity());
+}
+
+void PhysicsBackend::SetRigidDynamicActorLinearVelocity(void* actor, const Vector3& value, bool wakeUp)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setLinearVelocity(C2P(value), wakeUp);
+}
+
+Vector3 PhysicsBackend::GetRigidDynamicActorAngularVelocity(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return P2C(actorPhysX->getAngularVelocity());
+}
+
+void PhysicsBackend::SetRigidDynamicActorAngularVelocity(void* actor, const Vector3& value, bool wakeUp)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setAngularVelocity(C2P(value), wakeUp);
+}
+
+Vector3 PhysicsBackend::GetRigidDynamicActorCenterOfMass(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return P2C(actorPhysX->getCMassLocalPose().p);
+}
+
+void PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(void* actor, const Vector3& value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ auto pose = actorPhysX->getCMassLocalPose();
+ pose.p += C2P(value);
+ actorPhysX->setCMassLocalPose(pose);
+}
+
+bool PhysicsBackend::GetRigidDynamicActorIsSleeping(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return actorPhysX->isSleeping();
+}
+
+void PhysicsBackend::GetRigidActorSleep(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->putToSleep();
+}
+
+void PhysicsBackend::GetRigidDynamicActorWakeUp(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->wakeUp();
+}
+
+float PhysicsBackend::GetRigidDynamicActorSleepThreshold(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return actorPhysX->getSleepThreshold();
+}
+
+void PhysicsBackend::SetRigidDynamicActorSleepThreshold(void* actor, float value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setSleepThreshold(value);
+}
+
+float PhysicsBackend::GetRigidDynamicActorMaxDepenetrationVelocity(void* actor)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ return actorPhysX->getMaxDepenetrationVelocity();
+}
+
+void PhysicsBackend::SetRigidDynamicActorMaxDepenetrationVelocity(void* actor, float value)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setMaxDepenetrationVelocity(value);
+}
+
+void PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(void* actor, int32 minPositionIters, int32 minVelocityIters)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->setSolverIterationCounts(Math::Clamp(minPositionIters, 1, 255), Math::Clamp(minVelocityIters, 1, 255));
+}
+
+void PhysicsBackend::UpdateRigidDynamicActorMass(void* actor, float& mass, float massScale, bool autoCalculate)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ if (autoCalculate)
+ {
+ // Calculate per-shape densities (convert kg/m^3 into engine units)
+ const float minDensity = 0.08375f; // Hydrogen density
+ const float defaultDensity = 1000.0f; // Water density
+ Array> densities;
+ for (uint32 i = 0; i < actorPhysX->getNbShapes(); i++)
+ {
+ PxShape* shape;
+ actorPhysX->getShapes(&shape, 1, i);
+ if (shape->getFlags() & PxShapeFlag::eSIMULATION_SHAPE)
+ {
+ float density = defaultDensity;
+ PxMaterial* material;
+ if (shape->getMaterials(&material, 1, 0) == 1)
+ {
+ if (const auto mat = (PhysicalMaterial*)material->userData)
+ {
+ density = Math::Max(mat->Density, minDensity);
+ }
+ }
+ densities.Add(KgPerM3ToKgPerCm3(density));
+ }
+ }
+ if (densities.IsEmpty())
+ densities.Add(KgPerM3ToKgPerCm3(defaultDensity));
+
+ // Auto calculated mass
+ PxRigidBodyExt::updateMassAndInertia(*actorPhysX, densities.Get(), densities.Count());
+ mass = actorPhysX->getMass();
+ massScale = Math::Max(massScale, 0.001f);
+ if (!Math::IsOne(massScale))
+ {
+ mass *= massScale;
+ actorPhysX->setMass(mass);
+ }
+ }
+ else
+ {
+ // Use fixed mass
+ PxRigidBodyExt::setMassAndUpdateInertia(*actorPhysX, Math::Max(mass * massScale, 0.001f));
+ }
+}
+
+void PhysicsBackend::AddRigidDynamicActorForce(void* actor, const Vector3& force, ForceMode mode)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->addForce(C2P(force), static_cast(mode));
+}
+
+void PhysicsBackend::AddRigidDynamicActorForceAtPosition(void* actor, const Vector3& force, const Vector3& position, ForceMode mode)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ PxRigidBodyExt::addForceAtPos(*actorPhysX, C2P(force), C2P(position), static_cast(mode));
+}
+
+void PhysicsBackend::AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode)
+{
+ auto actorPhysX = (PxRigidDynamic*)actor;
+ actorPhysX->addTorque(C2P(torque), static_cast(mode));
+}
+
+void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger)
+{
+ const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled);
+ PxMaterial* materialPhysX = DefaultMaterial;
+ if (material && !material->WaitForLoaded() && material->Instance)
+ {
+ materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
+ }
+ PxGeometryHolder geometryPhysX;
+ GetShapeGeometry(geometry, geometryPhysX);
+ PxShape* shapePhysX = PhysX->createShape(geometryPhysX.any(), *materialPhysX, true, shapeFlags);
+ shapePhysX->userData = collider;
+#if PHYSX_DEBUG_NAMING
+ shapePhysX->setName("Shape");
+#endif
+ return shapePhysX;
+}
+
+void PhysicsBackend::SetShapeState(void* shape, bool enabled, bool trigger)
+{
+ auto shapePhysX = (PxShape*)shape;
+ const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled);
+ shapePhysX->setFlags(shapeFlags);
+}
+
+void PhysicsBackend::SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1)
+{
+ auto shapePhysX = (PxShape*)shape;
+ PxFilterData filterData;
+ filterData.word0 = mask0;
+ filterData.word1 = mask1;
+ shapePhysX->setSimulationFilterData(filterData);
+ shapePhysX->setQueryFilterData(filterData);
+}
+
+void* PhysicsBackend::GetShapeActor(void* shape)
+{
+ auto shapePhysX = (PxShape*)shape;
+ return shapePhysX->getActor();
+}
+
+void PhysicsBackend::GetShapePose(void* shape, Vector3& position, Quaternion& orientation)
+{
+ auto shapePhysX = (PxShape*)shape;
+ PxRigidActor* actorPhysX = shapePhysX->getActor();
+ PxTransform pose = actorPhysX->getGlobalPose().transform(shapePhysX->getLocalPose());
+ position = P2C(pose.p);
+ orientation = P2C(pose.q);
+}
+
+CollisionShape::Types PhysicsBackend::GetShapeType(void* shape)
+{
+ auto shapePhysX = (PxShape*)shape;
+ CollisionShape::Types type;
+ switch (shapePhysX->getGeometryType())
+ {
+ case PxGeometryType::eSPHERE:
+ type = CollisionShape::Types::Sphere;
+ break;
+ case PxGeometryType::eCAPSULE:
+ type = CollisionShape::Types::Capsule;
+ break;
+ case PxGeometryType::eBOX:
+ type = CollisionShape::Types::Box;
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ type = CollisionShape::Types::ConvexMesh;
+ break;
+ case PxGeometryType::eTRIANGLEMESH:
+ type = CollisionShape::Types::TriangleMesh;
+ break;
+ case PxGeometryType::eHEIGHTFIELD:
+ type = CollisionShape::Types::HeightField;
+ break;
+ default: ;
+ }
+ return type;
+}
+
+void PhysicsBackend::GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation)
+{
+ auto shapePhysX = (PxShape*)shape;
+ auto pose = shapePhysX->getLocalPose();
+ position = P2C(pose.p);
+ orientation = P2C(pose.q);
+}
+
+void PhysicsBackend::SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation)
+{
+ auto shapePhysX = (PxShape*)shape;
+ shapePhysX->setLocalPose(PxTransform(C2P(position), C2P(orientation)));
+}
+
+void PhysicsBackend::SetShapeContactOffset(void* shape, float value)
+{
+ auto shapePhysX = (PxShape*)shape;
+ shapePhysX->setContactOffset(Math::Max(shapePhysX->getRestOffset() + ZeroTolerance, value));
+}
+
+void PhysicsBackend::SetShapeMaterial(void* shape, JsonAsset* material)
+{
+ auto shapePhysX = (PxShape*)shape;
+ PxMaterial* materialPhysX = DefaultMaterial;
+ if (material && !material->WaitForLoaded() && material->Instance)
+ {
+ materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
+ }
+ shapePhysX->setMaterials(&materialPhysX, 1);
+}
+
+void PhysicsBackend::SetShapeGeometry(void* shape, const CollisionShape& geometry)
+{
+ auto shapePhysX = (PxShape*)shape;
+ PxGeometryHolder geometryPhysX;
+ GetShapeGeometry(geometry, geometryPhysX);
+ shapePhysX->setGeometry(geometryPhysX.any());
+}
+
+void PhysicsBackend::AttachShape(void* shape, void* actor)
+{
+ auto shapePhysX = (PxShape*)shape;
+ auto actorPhysX = (PxRigidActor*)actor;
+ actorPhysX->attachShape(*shapePhysX);
+}
+
+void PhysicsBackend::DetachShape(void* shape, void* actor)
+{
+ auto shapePhysX = (PxShape*)shape;
+ auto actorPhysX = (PxRigidActor*)actor;
+ actorPhysX->detachShape(*shapePhysX);
+}
+
+bool PhysicsBackend::ComputeShapesPenetration(void* shapeA, void* shapeB, const Vector3& positionA, const Quaternion& orientationA, const Vector3& positionB, const Quaternion& orientationB, Vector3& direction, float& distance)
+{
+ auto shapeAPhysX = (PxShape*)shapeA;
+ auto shapeBPhysX = (PxShape*)shapeB;
+ const PxTransform poseA(C2P(positionA), C2P(orientationA));
+ const PxTransform poseB(C2P(positionB), C2P(orientationB));
+ return PxGeometryQuery::computePenetration(C2P(direction), distance, shapeAPhysX->getGeometry().any(), poseA, shapeBPhysX->getGeometry().any(), poseB);
+}
+
+float PhysicsBackend::ComputeShapeSqrDistanceToPoint(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& point, Vector3* closestPoint)
+{
+ auto shapePhysX = (PxShape*)shape;
+ const PxTransform trans(C2P(position), C2P(orientation));
+ return PxGeometryQuery::pointDistance(C2P(point), shapePhysX->getGeometry().any(), trans, (PxVec3*)closestPoint);
+}
+
+bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance)
+{
+ auto shapePhysX = (PxShape*)shape;
+ const PxTransform trans(C2P(position), C2P(orientation));
+ const PxHitFlags hitFlags = (PxHitFlags)0;
+ PxRaycastHit hit;
+ if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0)
+ {
+ resultHitDistance = hit.distance;
+ return true;
+ }
+ return false;
+}
+
+bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance)
+{
+ auto shapePhysX = (PxShape*)shape;
+ const PxTransform trans(C2P(position), C2P(orientation));
+ const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV;
+ PxRaycastHit hit;
+ if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0)
+ return false;
+ P2C(hit, hitInfo);
+ return true;
+}
+
+void PhysicsBackend::SetJointFlags(void* joint, JointFlags value)
+{
+ auto jointPhysX = (PxJoint*)joint;
+ jointPhysX->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value & JointFlags::Collision);
+}
+
+void PhysicsBackend::SetJointActors(void* joint, void* actors0, void* actor1)
+{
+ auto jointPhysX = (PxJoint*)joint;
+ jointPhysX->setActors((PxRigidActor*)actors0, (PxRigidActor*)actor1);
+}
+
+void PhysicsBackend::SetJointActorPose(void* joint, const Vector3& position, const Quaternion& orientation, uint8 index)
+{
+ auto jointPhysX = (PxJoint*)joint;
+ jointPhysX->setLocalPose((PxJointActorIndex::Enum)index, PxTransform(C2P(position), C2P(orientation)));
+}
+
+void PhysicsBackend::SetJointBreakForce(void* joint, float force, float torque)
+{
+ auto jointPhysX = (PxJoint*)joint;
+ jointPhysX->setBreakForce(force, torque);
+}
+
+void PhysicsBackend::GetJointForce(void* joint, Vector3& linear, Vector3& angular)
+{
+ auto jointPhysX = (PxJoint*)joint;
+ if (jointPhysX->getConstraint())
+ jointPhysX->getConstraint()->getForce(*(PxVec3*)&linear, *(PxVec3*)&angular);
+}
+
+void* PhysicsBackend::CreateFixedJoint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxFixedJoint* joint = PxFixedJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("FixedJoint");
+#endif
+ return joint;
+}
+
+void* PhysicsBackend::CreateDistanceJoint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxDistanceJoint* joint = PxDistanceJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("DistanceJoint");
+#endif
+ return joint;
+}
+
+void* PhysicsBackend::CreateHingeJoint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxRevoluteJoint* joint = PxRevoluteJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("HingeJoint");
+#endif
+ return joint;
+}
+
+void* PhysicsBackend::CreateSliderJoint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxPrismaticJoint* joint = PxPrismaticJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("SliderJoint");
+#endif
+ return joint;
+}
+
+void* PhysicsBackend::CreateSphericalJoint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxSphericalJoint* joint = PxSphericalJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("SphericalJoint");
+#endif
+ return joint;
+}
+
+void* PhysicsBackend::CreateD6Joint(const PhysicsJointDesc& desc)
+{
+ const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0));
+ const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1));
+ PxD6Joint* joint = PxD6JointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1);
+ joint->userData = desc.Joint;
+#if PHYSX_DEBUG_NAMING
+ joint->setName("D6Joint");
+#endif
+ return joint;
+}
+
+void PhysicsBackend::SetDistanceJointFlags(void* joint, DistanceJointFlag flags)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ jointPhysX->setDistanceJointFlags((PxDistanceJointFlag::Enum)flags);
+}
+
+void PhysicsBackend::SetDistanceJointMinDistance(void* joint, float value)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ jointPhysX->setMinDistance(value);
+}
+
+void PhysicsBackend::SetDistanceJointMaxDistance(void* joint, float value)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ jointPhysX->setMaxDistance(value);
+}
+
+void PhysicsBackend::SetDistanceJointTolerance(void* joint, float value)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ jointPhysX->setTolerance(value);
+}
+
+void PhysicsBackend::SetDistanceJointSpring(void* joint, const SpringParameters& value)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ jointPhysX->setStiffness(value.Stiffness);
+ jointPhysX->setDamping(value.Damping);
+}
+
+float PhysicsBackend::GetDistanceJointDistance(void* joint)
+{
+ auto jointPhysX = (PxDistanceJoint*)joint;
+ return jointPhysX->getDistance();
+}
+
+void PhysicsBackend::SetHingeJointFlags(void* joint, HingeJointFlag value, bool driveFreeSpin)
+{
+ auto jointPhysX = (PxRevoluteJoint*)joint;
+ PxRevoluteJointFlags flags = (PxRevoluteJointFlags)0;
+ if (value & HingeJointFlag::Limit)
+ flags |= PxRevoluteJointFlag::eLIMIT_ENABLED;
+ if (value & HingeJointFlag::Drive)
+ flags |= PxRevoluteJointFlag::eDRIVE_ENABLED;
+ if (driveFreeSpin)
+ flags |= PxRevoluteJointFlag::eDRIVE_FREESPIN;
+ jointPhysX->setRevoluteJointFlags(flags);
+}
+
+void PhysicsBackend::SetHingeJointLimit(void* joint, const LimitAngularRange& value)
+{
+ auto jointPhysX = (PxRevoluteJoint*)joint;
+ PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setLimit(limit);
+}
+
+void PhysicsBackend::SetHingeJointDrive(void* joint, const HingeJointDrive& value)
+{
+ auto jointPhysX = (PxRevoluteJoint*)joint;
+ jointPhysX->setDriveVelocity(Math::Max(value.Velocity, 0.0f));
+ jointPhysX->setDriveForceLimit(Math::Max(value.ForceLimit, 0.0f));
+ jointPhysX->setDriveGearRatio(Math::Max(value.GearRatio, 0.0f));
+ jointPhysX->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, value.FreeSpin);
+}
+
+float PhysicsBackend::GetHingeJointAngle(void* joint)
+{
+ auto jointPhysX = (PxRevoluteJoint*)joint;
+ return jointPhysX->getAngle();
+}
+
+float PhysicsBackend::GetHingeJointVelocity(void* joint)
+{
+ auto jointPhysX = (PxRevoluteJoint*)joint;
+ return jointPhysX->getVelocity();
+}
+
+void PhysicsBackend::SetSliderJointFlags(void* joint, SliderJointFlag value)
+{
+ auto jointPhysX = (PxPrismaticJoint*)joint;
+ jointPhysX->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, (value & SliderJointFlag::Limit) != 0);
+}
+
+void PhysicsBackend::SetSliderJointLimit(void* joint, const LimitLinearRange& value)
+{
+ auto jointPhysX = (PxPrismaticJoint*)joint;
+ PxJointLinearLimitPair limit(ToleranceScale, value.Lower, value.Upper, value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setLimit(limit);
+}
+
+float PhysicsBackend::GetSliderJointPosition(void* joint)
+{
+ auto jointPhysX = (PxPrismaticJoint*)joint;
+ return jointPhysX->getPosition();
+}
+
+float PhysicsBackend::GetSliderJointVelocity(void* joint)
+{
+ auto jointPhysX = (PxPrismaticJoint*)joint;
+ return jointPhysX->getVelocity();
+}
+
+void PhysicsBackend::SetSphericalJointFlags(void* joint, SphericalJointFlag value)
+{
+ auto jointPhysX = (PxSphericalJoint*)joint;
+ jointPhysX->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, (value & SphericalJointFlag::Limit) != 0);
+}
+
+void PhysicsBackend::SetSphericalJointLimit(void* joint, const LimitConeRange& value)
+{
+ auto jointPhysX = (PxSphericalJoint*)joint;
+ PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setLimitCone(limit);
+}
+
+void PhysicsBackend::SetD6JointMotion(void* joint, D6JointAxis axis, D6JointMotion value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ jointPhysX->setMotion(static_cast(axis), static_cast(value));
+}
+
+void PhysicsBackend::SetD6JointDrive(void* joint, const D6JointDriveType index, const D6JointDrive& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxD6JointDrive drive;
+ if (value.Acceleration)
+ drive.flags = PxD6JointDriveFlag::eACCELERATION;
+ drive.stiffness = value.Stiffness;
+ drive.damping = value.Damping;
+ drive.forceLimit = value.ForceLimit;
+ ASSERT_LOW_LAYER(drive.isValid());
+ jointPhysX->setDrive(static_cast(index), drive);
+}
+
+void PhysicsBackend::SetD6JointLimitLinear(void* joint, const LimitLinear& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxJointLinearLimit limit(ToleranceScale, Math::Max(value.Extent, ZeroTolerance), value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setLinearLimit(limit);
+}
+
+void PhysicsBackend::SetD6JointLimitTwist(void* joint, const LimitAngularRange& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setTwistLimit(limit);
+}
+
+void PhysicsBackend::SetD6JointLimitSwing(void* joint, const LimitConeRange& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist);
+ limit.stiffness = value.Spring.Stiffness;
+ limit.damping = value.Spring.Damping;
+ limit.restitution = value.Restitution;
+ ASSERT_LOW_LAYER(limit.isValid());
+ jointPhysX->setSwingLimit(limit);
+}
+
+Vector3 PhysicsBackend::GetD6JointDrivePosition(void* joint)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ return P2C(jointPhysX->getDrivePosition().p);
+}
+
+void PhysicsBackend::SetD6JointDrivePosition(void* joint, const Vector3& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxTransform t = jointPhysX->getDrivePosition();
+ t.p = C2P(value);
+ jointPhysX->setDrivePosition(t);
+}
+
+Quaternion PhysicsBackend::GetD6JointDriveRotation(void* joint)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ return P2C(jointPhysX->getDrivePosition().q);
+}
+
+void PhysicsBackend::SetD6JointDriveRotation(void* joint, const Quaternion& value)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxTransform t = jointPhysX->getDrivePosition();
+ t.q = C2P(value);
+ jointPhysX->setDrivePosition(t);
+}
+
+void PhysicsBackend::GetD6JointDriveVelocity(void* joint, Vector3& linear, Vector3& angular)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ PxVec3 linearPhysX, angularPhysX;
+ jointPhysX->getDriveVelocity(linearPhysX, angularPhysX);
+ linear = P2C(linearPhysX);
+ angular = P2C(angularPhysX);
+}
+
+void PhysicsBackend::SetD6JointDriveVelocity(void* joint, const Vector3& linear, const Vector3& angular)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ jointPhysX->setDriveVelocity(C2P(linear), C2P(angular));
+}
+
+float PhysicsBackend::GetD6JointTwist(void* joint)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ return jointPhysX->getTwistAngle();
+}
+
+float PhysicsBackend::GetD6JointSwingY(void* joint)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ return jointPhysX->getSwingYAngle();
+}
+
+float PhysicsBackend::GetD6JointSwingZ(void* joint)
+{
+ auto jointPhysX = (PxD6Joint*)joint;
+ return jointPhysX->getSwingZAngle();
+}
+
+void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, PhysicsColliderActor* collider, float contactOffset, const Vector3& position, float slopeLimit, int32 nonWalkableMode, JsonAsset* material, float radius, float height, float stepOffset, void*& shape)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ PxCapsuleControllerDesc desc;
+ desc.userData = actor;
+ desc.contactOffset = Math::Max(contactOffset, ZeroTolerance);
+ desc.position = PxExtendedVec3(position.X, position.Y, position.Z);
+ desc.slopeLimit = Math::Cos(slopeLimit * DegreesToRadians);
+ desc.nonWalkableMode = static_cast(nonWalkableMode);
+ desc.climbingMode = PxCapsuleClimbingMode::eEASY;
+ if (material && !material->WaitForLoaded())
+ desc.material = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
+ else
+ desc.material = DefaultMaterial;
+ const float minSize = 0.001f;
+ desc.height = Math::Max(height, minSize);
+ desc.radius = Math::Max(radius - desc.contactOffset, minSize);
+ desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize);
+ auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
+ PxRigidActor* actorPhysX = controllerPhysX->getActor();
+ ASSERT(actorPhysX && actorPhysX->getNbShapes() == 1);
+ actorPhysX->getShapes((PxShape**)&shape, 1);
+ actorPhysX->userData = actor;
+ auto shapePhysX = (PxShape*)shape;
+ shapePhysX->userData = collider;
+#if PHYSX_DEBUG_NAMING
+ actorPhysX->setName("CCActor");
+ shapePhysX->setName("CCShape");
+#endif
+ return controllerPhysX;
+}
+
+void* PhysicsBackend::GetControllerRigidDynamicActor(void* controller)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ return controllerPhysX->getActor();
+}
+
+void PhysicsBackend::SetControllerSize(void* controller, float radius, float height)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setRadius(radius);
+ controllerPhysX->resize(height);
+}
+
+void PhysicsBackend::SetControllerSlopeLimit(void* controller, float value)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setSlopeLimit(Math::Cos(value * DegreesToRadians));
+}
+
+void PhysicsBackend::SetControllerNonWalkableMode(void* controller, int32 value)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setNonWalkableMode(static_cast(value));
+}
+
+void PhysicsBackend::SetControllerStepOffset(void* controller, float value)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setStepOffset(value);
+}
+
+Vector3 PhysicsBackend::GetControllerUpDirection(void* controller)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ return P2C(controllerPhysX->getUpDirection());
+}
+
+void PhysicsBackend::SetControllerUpDirection(void* controller, const Vector3& value)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setUpDirection(C2P(value));
+}
+
+Vector3 PhysicsBackend::GetControllerPosition(void* controller)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ return P2C(controllerPhysX->getPosition());
+}
+
+void PhysicsBackend::SetControllerPosition(void* controller, const Vector3& value)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ controllerPhysX->setPosition(PxExtendedVec3(value.X, value.Y, value.Z));
+}
+
+int32 PhysicsBackend::MoveController(void* controller, void* shape, const Vector3& displacement, float minMoveDistance, float deltaTime)
+{
+ auto controllerPhysX = (PxCapsuleController*)controller;
+ auto shapePhysX = (PxShape*)shape;
+ PxFilterData filterData = shapePhysX->getSimulationFilterData();
+ PxControllerFilters filters;
+ filters.mFilterData = &filterData;
+ filters.mFilterCallback = &CharacterQueryFilter;
+ filters.mFilterFlags = PxQueryFlag::eDYNAMIC | PxQueryFlag::eSTATIC | PxQueryFlag::ePREFILTER;
+ filters.mCCTFilterCallback = &CharacterControllerFilter;
+ return (byte)controllerPhysX->move(C2P(displacement), minMoveDistance, deltaTime, filters);
+}
+
+#if WITH_VEHICLE
+
+void* PhysicsBackend::CreateVehicle(WheeledVehicle* actor)
+{
+ // Get wheels
+ Array> wheels;
+ for (auto& wheel : actor->_wheels)
+ {
+ if (!wheel.Collider)
+ {
+ LOG(Warning, "Missing wheel collider in vehicle {0}", actor->ToString());
+ continue;
+ }
+ if (wheel.Collider->GetParent() != actor)
+ {
+ LOG(Warning, "Invalid wheel collider {1} in vehicle {0} attached to {2} (wheels needs to be added as children to vehicle)", actor->ToString(), wheel.Collider->ToString(), wheel.Collider->GetParent() ? wheel.Collider->GetParent()->ToString() : String::Empty);
+ continue;
+ }
+ if (wheel.Collider->GetIsTrigger())
+ {
+ LOG(Warning, "Invalid wheel collider {1} in vehicle {0} cannot be a trigger", actor->ToString(), wheel.Collider->ToString());
+ continue;
+ }
+ if (wheel.Collider->IsDuringPlay())
+ {
+ wheels.Add(&wheel);
+ }
+ }
+ if (wheels.IsEmpty())
+ {
+ // No wheel, no car
+ // No woman, no cry
+ return nullptr;
+ }
+ actor->_wheelsData.Resize(wheels.Count());
+ auto actorPhysX = (PxRigidDynamic*)actor->GetPhysicsActor();
+
+ InitVehicleSDK();
+
+ // Get linked shapes for the wheels mapping
+ Array> shapes;
+ shapes.Resize(actorPhysX->getNbShapes());
+ actorPhysX->getShapes(shapes.Get(), shapes.Count(), 0);
+ const PxTransform centerOfMassOffset = actorPhysX->getCMassLocalPose();
+
+ // Initialize wheels simulation data
+ PxVec3 offsets[PX_MAX_NB_WHEELS];
+ for (int32 i = 0; i < wheels.Count(); i++)
+ {
+ auto& wheel = *wheels[i];
+ offsets[i] = C2P(wheel.Collider->GetLocalPosition());
+ }
+ PxF32 sprungMasses[PX_MAX_NB_WHEELS];
+ const float mass = actorPhysX->getMass();
+ PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses);
+ PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
+ for (int32 i = 0; i < wheels.Count(); i++)
+ {
+ auto& wheel = *wheels[i];
+
+ auto& data = actor->_wheelsData[i];
+ data.Collider = wheel.Collider;
+ data.LocalOrientation = wheel.Collider->GetLocalOrientation();
+
+ PxVehicleSuspensionData suspensionData;
+ const float suspensionFrequency = 7.0f;
+ suspensionData.mMaxCompression = wheel.SuspensionMaxRaise;
+ suspensionData.mMaxDroop = wheel.SuspensionMaxDrop;
+ suspensionData.mSprungMass = sprungMasses[i];
+ suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass;
+ suspensionData.mSpringDamperRate = wheel.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass);
+
+ PxVehicleTireData tire;
+ tire.mType = 0;
+ tire.mLatStiffX = wheel.TireLateralMax;
+ tire.mLatStiffY = wheel.TireLateralStiffness;
+ tire.mLongitudinalStiffnessPerUnitGravity = wheel.TireLongitudinalStiffness;
+
+ PxVehicleWheelData wheelData;
+ wheelData.mMass = wheel.Mass;
+ wheelData.mRadius = wheel.Radius;
+ wheelData.mWidth = wheel.Width;
+ wheelData.mMOI = 0.5f * wheelData.mMass * Math::Square(wheelData.mRadius);
+ wheelData.mDampingRate = M2ToCm2(wheel.DampingRate);
+ wheelData.mMaxSteer = wheel.MaxSteerAngle * DegreesToRadians;
+ wheelData.mMaxBrakeTorque = M2ToCm2(wheel.MaxBrakeTorque);
+ wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque);
+
+ PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]);
+ PxVec3 forceAppPointOffset(centreOffset.x, wheel.SuspensionForceOffset, centreOffset.z);
+
+ wheelsSimData->setTireData(i, tire);
+ wheelsSimData->setWheelData(i, wheelData);
+ wheelsSimData->setSuspensionData(i, suspensionData);
+ wheelsSimData->setSuspTravelDirection(i, centerOfMassOffset.rotate(PxVec3(0.0f, -1.0f, 0.0f)));
+ wheelsSimData->setWheelCentreOffset(i, centreOffset);
+ wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset);
+ wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset);
+ wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1);
+ wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f);
+
+ PxShape* wheelShape = (PxShape*)wheel.Collider->GetPhysicsShape();
+ if (wheel.Collider->IsActiveInHierarchy())
+ {
+ wheelsSimData->setWheelShapeMapping(i, shapes.Find(wheelShape));
+
+ // Setup Vehicle ID inside word3 for suspension raycasts to ignore self
+ PxFilterData filter = wheelShape->getQueryFilterData();
+ filter.word3 = actor->GetID().D + 1;
+ wheelShape->setQueryFilterData(filter);
+ wheelShape->setSimulationFilterData(filter);
+ wheelsSimData->setSceneQueryFilterData(i, filter);
+
+ // Remove wheels from the simulation (suspension force hold the vehicle)
+ wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
+ }
+ else
+ {
+ wheelsSimData->setWheelShapeMapping(i, -1);
+ wheelsSimData->disableWheel(i);
+ }
+ }
+ for (auto child : actor->Children)
+ {
+ auto collider = ScriptingObject::Cast(child);
+ if (collider && collider->GetAttachedRigidBody() == actor)
+ {
+ bool isWheel = false;
+ for (auto& w : wheels)
+ {
+ if (w->Collider == collider)
+ {
+ isWheel = true;
+ break;
+ }
+ }
+ if (!isWheel)
+ {
+ // Setup Vehicle ID inside word3 for suspension raycasts to ignore self
+ PxShape* shape = (PxShape*)collider->GetPhysicsShape();
+ PxFilterData filter = shape->getQueryFilterData();
+ filter.word3 = actor->GetID().D + 1;
+ shape->setQueryFilterData(filter);
+ shape->setSimulationFilterData(filter);
+ }
+ }
+ }
+
+ // Initialize vehicle drive
+ void* vehicle = nullptr;
+ const auto& differential = actor->_differential;
+ const auto& engine = actor->_engine;
+ const auto& gearbox = actor->_gearbox;
+ switch (actor->_driveType)
+ {
+ case WheeledVehicle::DriveTypes::Drive4W:
+ {
+ PxVehicleDriveSimData4W driveSimData;
+
+ // Differential
+ PxVehicleDifferential4WData differential4WData;
+ differential4WData.mType = (PxVehicleDifferential4WData::Enum)differential.Type;
+ differential4WData.mFrontRearSplit = differential.FrontRearSplit;
+ differential4WData.mFrontLeftRightSplit = differential.FrontLeftRightSplit;
+ differential4WData.mRearLeftRightSplit = differential.RearLeftRightSplit;
+ differential4WData.mCentreBias = differential.CentreBias;
+ differential4WData.mFrontBias = differential.FrontBias;
+ differential4WData.mRearBias = differential.RearBias;
+ driveSimData.setDiffData(differential4WData);
+
+ // Engine
+ PxVehicleEngineData engineData;
+ engineData.mMOI = M2ToCm2(engine.MOI);
+ engineData.mPeakTorque = M2ToCm2(engine.MaxTorque);
+ engineData.mMaxOmega = RpmToRadPerS(engine.MaxRotationSpeed);
+ engineData.mDampingRateFullThrottle = M2ToCm2(0.15f);
+ engineData.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f);
+ engineData.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f);
+ driveSimData.setEngineData(engineData);
+
+ // Gears
+ PxVehicleGearsData gears;
+ gears.mSwitchTime = Math::Max(gearbox.SwitchTime, 0.0f);
+ driveSimData.setGearsData(gears);
+
+ // Auto Box
+ PxVehicleAutoBoxData autoBox;
+ driveSimData.setAutoBoxData(autoBox);
+
+ // Clutch
+ PxVehicleClutchData clutch;
+ clutch.mStrength = M2ToCm2(gearbox.ClutchStrength);
+ driveSimData.setClutchData(clutch);
+
+ // Ackermann steer accuracy
+ PxVehicleAckermannGeometryData ackermann;
+ ackermann.mAxleSeparation = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).x - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).x);
+ ackermann.mFrontWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z);
+ ackermann.mRearWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z);
+ driveSimData.setAckermannGeometryData(ackermann);
+
+ // Create vehicle drive
+ auto drive4W = PxVehicleDrive4W::allocate(wheels.Count());
+ drive4W->setup(PhysX, actorPhysX, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0));
+ drive4W->setToRestState();
+ drive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
+ drive4W->mDriveDynData.setUseAutoGears(gearbox.AutoGear);
+ vehicle = drive4W;
+ break;
+ }
+ case WheeledVehicle::DriveTypes::DriveNW:
+ {
+ PxVehicleDriveSimDataNW driveSimData;
+
+ // Differential
+ PxVehicleDifferentialNWData differentialNwData;
+ for (int32 i = 0; i < wheels.Count(); i++)
+ differentialNwData.setDrivenWheel(i, true);
+ driveSimData.setDiffData(differentialNwData);
+
+ // Engine
+ PxVehicleEngineData engineData;
+ engineData.mMOI = M2ToCm2(engine.MOI);
+ engineData.mPeakTorque = M2ToCm2(engine.MaxTorque);
+ engineData.mMaxOmega = RpmToRadPerS(engine.MaxRotationSpeed);
+ engineData.mDampingRateFullThrottle = M2ToCm2(0.15f);
+ engineData.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f);
+ engineData.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f);
+ driveSimData.setEngineData(engineData);
+
+ // Gears
+ PxVehicleGearsData gears;
+ gears.mSwitchTime = Math::Max(gearbox.SwitchTime, 0.0f);
+ driveSimData.setGearsData(gears);
+
+ // Auto Box
+ PxVehicleAutoBoxData autoBox;
+ driveSimData.setAutoBoxData(autoBox);
+
+ // Clutch
+ PxVehicleClutchData clutch;
+ clutch.mStrength = M2ToCm2(gearbox.ClutchStrength);
+ driveSimData.setClutchData(clutch);
+
+ // Create vehicle drive
+ auto driveNW = PxVehicleDriveNW::allocate(wheels.Count());
+ driveNW->setup(PhysX, actorPhysX, *wheelsSimData, driveSimData, wheels.Count());
+ driveNW->setToRestState();
+ driveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
+ driveNW->mDriveDynData.setUseAutoGears(gearbox.AutoGear);
+ vehicle = driveNW;
+ break;
+ }
+ case WheeledVehicle::DriveTypes::NoDrive:
+ {
+ // Create vehicle drive
+ auto driveNo = PxVehicleNoDrive::allocate(wheels.Count());
+ driveNo->setup(PhysX, actorPhysX, *wheelsSimData);
+ driveNo->setToRestState();
+ vehicle = driveNo;
+ break;
+ }
+ default:
+ CRASH;
+ }
+ wheelsSimData->free();
+
+ return vehicle;
+}
+
+void PhysicsBackend::DestroyVehicle(void* vehicle, int32 driveType)
+{
+ switch ((WheeledVehicle::DriveTypes)driveType)
+ {
+ case WheeledVehicle::DriveTypes::Drive4W:
+ ((PxVehicleDrive4W*)vehicle)->free();
+ break;
+ case WheeledVehicle::DriveTypes::DriveNW:
+ ((PxVehicleDriveNW*)vehicle)->free();
+ break;
+ case WheeledVehicle::DriveTypes::NoDrive:
+ ((PxVehicleNoDrive*)vehicle)->free();
+ break;
+ }
+}
+
+void PhysicsBackend::SetVehicleGearbox(void* vehicle, const void* value)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ auto& gearbox = *(const WheeledVehicle::GearboxSettings*)value;
+ drive->mDriveDynData.setUseAutoGears(gearbox.AutoGear);
+ drive->mDriveDynData.setAutoBoxSwitchTime(Math::Max(gearbox.SwitchTime, 0.0f));
+}
+
+int32 PhysicsBackend::GetVehicleTargetGear(void* vehicle)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ return (int32)drive->mDriveDynData.getTargetGear() - 1;
+}
+
+void PhysicsBackend::SetVehicleTargetGear(void* vehicle, int32 value)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ drive->mDriveDynData.startGearChange((PxU32)(value + 1));
+}
+
+int32 PhysicsBackend::GetVehicleCurrentGear(void* vehicle)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ return (int32)drive->mDriveDynData.getCurrentGear() - 1;
+}
+
+void PhysicsBackend::SetVehicleCurrentGear(void* vehicle, int32 value)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ drive->mDriveDynData.forceGearChange((PxU32)(value + 1));
+}
+
+float PhysicsBackend::GetVehicleForwardSpeed(void* vehicle)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ return drive->computeForwardSpeed();
+}
+
+float PhysicsBackend::GetVehicleSidewaysSpeed(void* vehicle)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ return drive->computeSidewaysSpeed();
+}
+
+float PhysicsBackend::GetVehicleEngineRotationSpeed(void* vehicle)
+{
+ auto drive = (PxVehicleDrive*)vehicle;
+ return RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed());
+}
+
+void PhysicsBackend::AddVehicle(void* scene, WheeledVehicle* actor)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ scenePhysX->WheelVehicles.Add(actor);
+}
+
+void PhysicsBackend::RemoveVehicle(void* scene, WheeledVehicle* actor)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ scenePhysX->WheelVehicles.Remove(actor);
+}
+
+#endif
+
+void* PhysicsBackend::CreateConvexMesh(byte* data, int32 dataSize, BoundingBox& localBounds)
+{
+ PxDefaultMemoryInputData input(data, dataSize);
+ PxConvexMesh* convexMesh = PhysX->createConvexMesh(input);
+ localBounds = P2C(convexMesh->getLocalBounds());
+ return convexMesh;
+}
+
+void* PhysicsBackend::CreateTriangleMesh(byte* data, int32 dataSize, BoundingBox& localBounds)
+{
+ PxDefaultMemoryInputData input(data, dataSize);
+ PxTriangleMesh* triangleMesh = PhysX->createTriangleMesh(input);
+ localBounds = P2C(triangleMesh->getLocalBounds());
+ return triangleMesh;
+}
+
+void* PhysicsBackend::CreateHeightField(byte* data, int32 dataSize)
+{
+ PxDefaultMemoryInputData input(data, dataSize);
+ PxHeightField* heightField = PhysX->createHeightField(input);
+ return heightField;
+}
+
+void PhysicsBackend::GetConvexMeshTriangles(void* contextMesh, Array& vertexBuffer, Array& indexBuffer)
+{
+ auto contextMeshPhysX = (PxConvexMesh*)contextMesh;
+ uint32 numIndices = 0;
+ uint32 numVertices = contextMeshPhysX->getNbVertices();
+ const uint32 numPolygons = contextMeshPhysX->getNbPolygons();
+ for (uint32 i = 0; i < numPolygons; i++)
+ {
+ PxHullPolygon face;
+ const bool status = contextMeshPhysX->getPolygonData(i, face);
+ ASSERT(status);
+ numIndices += (face.mNbVerts - 2) * 3;
+ }
+
+ vertexBuffer.Resize(numVertices);
+ indexBuffer.Resize(numIndices);
+ auto outVertices = vertexBuffer.Get();
+ auto outIndices = indexBuffer.Get();
+ const PxVec3* convexVertices = contextMeshPhysX->getVertices();
+ const byte* convexIndices = contextMeshPhysX->getIndexBuffer();
+
+ for (uint32 i = 0; i < numVertices; i++)
+ *outVertices++ = P2C(convexVertices[i]);
+
+ for (uint32 i = 0; i < numPolygons; i++)
+ {
+ PxHullPolygon face;
+ contextMeshPhysX->getPolygonData(i, face);
+
+ const PxU8* faceIndices = convexIndices + face.mIndexBase;
+ for (uint32 j = 2; j < face.mNbVerts; j++)
+ {
+ *outIndices++ = faceIndices[0];
+ *outIndices++ = faceIndices[j];
+ *outIndices++ = faceIndices[j - 1];
+ }
+ }
+}
+
+void PhysicsBackend::GetTriangleMeshTriangles(void* triangleMesh, Array& vertexBuffer, Array& indexBuffer)
+{
+ auto triangleMeshPhysX = (PxTriangleMesh*)triangleMesh;
+ uint32 numVertices = triangleMeshPhysX->getNbVertices();
+ uint32 numIndices = triangleMeshPhysX->getNbTriangles() * 3;
+
+ vertexBuffer.Resize(numVertices);
+ indexBuffer.Resize(numIndices);
+ auto outVertices = vertexBuffer.Get();
+ auto outIndices = indexBuffer.Get();
+ const PxVec3* vertices = triangleMeshPhysX->getVertices();
+ for (uint32 i = 0; i < numVertices; i++)
+ *outVertices++ = P2C(vertices[i]);
+
+ if (triangleMeshPhysX->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
+ {
+ const uint16* indices = (const uint16*)triangleMeshPhysX->getTriangles();
+
+ uint32 numTriangles = numIndices / 3;
+ for (uint32 i = 0; i < numTriangles; i++)
+ {
+ outIndices[i * 3 + 0] = (uint32)indices[i * 3 + 0];
+ outIndices[i * 3 + 1] = (uint32)indices[i * 3 + 1];
+ outIndices[i * 3 + 2] = (uint32)indices[i * 3 + 2];
+ }
+ }
+ else
+ {
+ const uint32* indices = (const uint32*)triangleMeshPhysX->getTriangles();
+
+ uint32 numTriangles = numIndices / 3;
+ for (uint32 i = 0; i < numTriangles; i++)
+ {
+ outIndices[i * 3 + 0] = indices[i * 3 + 0];
+ outIndices[i * 3 + 1] = indices[i * 3 + 1];
+ outIndices[i * 3 + 2] = indices[i * 3 + 2];
+ }
+ }
+}
+
+const uint32* PhysicsBackend::GetTriangleMeshRemap(void* triangleMesh, uint32& count)
+{
+ auto triangleMeshPhysX = (PxTriangleMesh*)triangleMesh;
+ count = triangleMeshPhysX->getNbTriangles();
+ return triangleMeshPhysX->getTrianglesRemap();
+}
+
+void PhysicsBackend::GetHeightFieldSize(void* heightField, int32& rows, int32& columns)
+{
+ auto heightFieldPhysX = (PxHeightField*)heightField;
+ rows = (int32)heightFieldPhysX->getNbRows();
+ columns = (int32)heightFieldPhysX->getNbColumns();
+}
+
+float PhysicsBackend::GetHeightFieldHeight(void* heightField, float x, float z)
+{
+ auto heightFieldPhysX = (PxHeightField*)heightField;
+ return heightFieldPhysX->getHeight(x, z);
+}
+
+bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data)
+{
+ auto heightFieldPhysX = (PxHeightField*)heightField;
+ PxHeightFieldDesc heightFieldDesc;
+ heightFieldDesc.format = PxHeightFieldFormat::eS16_TM;
+ heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES;
+ heightFieldDesc.nbColumns = cols;
+ heightFieldDesc.nbRows = rows;
+ heightFieldDesc.samples.data = data;
+ heightFieldDesc.samples.stride = sizeof(HeightFieldSample);
+ return !heightFieldPhysX->modifySamples(startCol, startRow, heightFieldDesc, true);
+}
+
+void PhysicsBackend::FlushRequests()
+{
+ FlushLocker.Lock();
+
+ // Delete objects
+ for (int32 i = 0; i < DeleteObjects.Count(); i++)
+ DeleteObjects[i]->release();
+ DeleteObjects.Clear();
+
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::FlushRequests(void* scene)
+{
+ auto scenePhysX = (ScenePhysX*)scene;
+ FlushLocker.Lock();
+
+ // Add objects
+ if (scenePhysX->AddActors.HasItems())
+ {
+ scenePhysX->Scene->addActors(scenePhysX->AddActors.Get(), scenePhysX->AddActors.Count());
+ scenePhysX->AddActors.Clear();
+ }
+
+ // Perform latent actions
+ for (int32 i = 0; i < scenePhysX->Actions.Count(); i++)
+ {
+ const auto action = scenePhysX->Actions[i];
+ switch (action.Type)
+ {
+ case ActionType::Sleep:
+ static_cast(action.Actor)->putToSleep();
+ break;
+ }
+ }
+ scenePhysX->Actions.Clear();
+
+ // Remove objects
+ if (scenePhysX->RemoveActors.HasItems())
+ {
+ scenePhysX->Scene->removeActors(scenePhysX->RemoveActors.Get(), scenePhysX->RemoveActors.Count(), true);
+ scenePhysX->RemoveActors.Clear();
+ }
+ if (scenePhysX->RemoveColliders.HasItems())
+ {
+ for (int32 i = 0; i < scenePhysX->RemoveColliders.Count(); i++)
+ scenePhysX->EventsCallback.OnColliderRemoved(scenePhysX->RemoveColliders[i]);
+ scenePhysX->RemoveColliders.Clear();
+ }
+ if (scenePhysX->RemoveJoints.HasItems())
+ {
+ for (int32 i = 0; i < scenePhysX->RemoveJoints.Count(); i++)
+ scenePhysX->EventsCallback.OnJointRemoved(scenePhysX->RemoveJoints[i]);
+ scenePhysX->RemoveJoints.Clear();
+ }
+
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::DestroyActor(void* actor)
+{
+ ASSERT_LOW_LAYER(actor);
+ auto actorPhysX = (PxActor*)actor;
+ actorPhysX->userData = nullptr;
+ FlushLocker.Lock();
+ DeleteObjects.Add(actorPhysX);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::DestroyShape(void* shape)
+{
+ ASSERT_LOW_LAYER(shape);
+ auto shapePhysX = (PxShape*)shape;
+ shapePhysX->userData = nullptr;
+ FlushLocker.Lock();
+ DeleteObjects.Add(shapePhysX);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::DestroyJoint(void* joint)
+{
+ ASSERT_LOW_LAYER(joint);
+ auto jointPhysX = (PxJoint*)joint;
+ jointPhysX->userData = nullptr;
+ FlushLocker.Lock();
+ DeleteObjects.Add(jointPhysX);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::DestroyController(void* controller)
+{
+ ASSERT_LOW_LAYER(controller);
+ auto controllerPhysX = (PxController*)controller;
+ controllerPhysX->getActor()->userData = nullptr;
+ controllerPhysX->release();
+}
+
+void PhysicsBackend::DestroyObject(void* object)
+{
+ ASSERT_LOW_LAYER(object);
+ auto objectPhysX = (PxBase*)object;
+ FlushLocker.Lock();
+ DeleteObjects.Add(objectPhysX);
+ FlushLocker.Unlock();
+}
+
+void PhysicsBackend::RemoveCollider(PhysicsColliderActor* collider)
+{
+ for (auto scene : Physics::Scenes)
+ {
+ auto scenePhysX = (ScenePhysX*)scene->GetPhysicsScene();
+ scenePhysX->RemoveColliders.Add(collider);
+ }
+}
+
+void PhysicsBackend::RemoveJoint(Joint* joint)
+{
+ for (auto scene : Physics::Scenes)
+ {
+ auto scenePhysX = (ScenePhysX*)scene->GetPhysicsScene();
+ scenePhysX->RemoveJoints.Add(joint);
+ }
+}
+
+#endif
diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h
new file mode 100644
index 000000000..c8d71a7ec
--- /dev/null
+++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if COMPILE_WITH_PHYSX
+
+#include "Engine/Physics/PhysicsBackend.h"
+#include "Types.h"
+
+///
+/// Implementation of the physical simulation using PhysX.
+///
+class PhysicsBackendPhysX
+{
+public:
+ static PxPhysics* GetPhysics();
+#if COMPILE_WITH_PHYSICS_COOKING
+ static PxCooking* GetCooking();
+#endif
+ static PxMaterial* GetDefaultMaterial();
+};
+
+#endif
diff --git a/Source/Engine/Physics/PhysicsStepper.cpp b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp
similarity index 94%
rename from Source/Engine/Physics/PhysicsStepper.cpp
rename to Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp
index 7a864e4b8..887353f49 100644
--- a/Source/Engine/Physics/PhysicsStepper.cpp
+++ b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp
@@ -1,7 +1,9 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
-#include "PhysicsStepper.h"
-#include "Physics.h"
+#if COMPILE_WITH_PHYSX
+
+#include "PhysicsStepperPhysX.h"
+#include "Engine/Physics/Physics.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include
#include
@@ -138,3 +140,5 @@ void FixedStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, P
mAccumulator -= PxReal(substepCount) * substepSize;
}
+
+#endif
diff --git a/Source/Engine/Physics/PhysicsStepper.h b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h
similarity index 98%
rename from Source/Engine/Physics/PhysicsStepper.h
rename to Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h
index 7e394fdcf..d871591b4 100644
--- a/Source/Engine/Physics/PhysicsStepper.h
+++ b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h
@@ -1,7 +1,9 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
+#if COMPILE_WITH_PHYSX
+
#include "Types.h"
#include
#include
@@ -215,3 +217,5 @@ public:
mMaxSubSteps = maxSteps;
}
};
+
+#endif
diff --git a/Source/Engine/Physics/SimulationEventCallback.cpp b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
similarity index 94%
rename from Source/Engine/Physics/SimulationEventCallback.cpp
rename to Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
index 27c8aa785..b17ef3ce3 100644
--- a/Source/Engine/Physics/SimulationEventCallback.cpp
+++ b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
-#include "SimulationEventCallback.h"
-#include "Utilities.h"
-#include "Colliders/Collider.h"
-#include "Joints/Joint.h"
-#include "Actors/RigidBody.h"
+#if COMPILE_WITH_PHYSX
+
+#include "SimulationEventCallbackPhysX.h"
+#include "Engine/Physics/Colliders/Collider.h"
+#include "Engine/Physics/Joints/Joint.h"
+#include "Engine/Physics/Actors/RigidBody.h"
#include
#include
@@ -136,7 +137,6 @@ void SimulationEventCallback::onConstraintBreak(PxConstraintInfo* constraints, P
for (uint32 i = 0; i < count; i++)
{
PxJoint* joint = reinterpret_cast(constraints[i].externalReference);
-
if (joint->userData)
BrokenJoints.Add(static_cast(joint->userData));
}
@@ -177,6 +177,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
c.ThisActor = static_cast(pair.shapes[0]->userData);
c.OtherActor = static_cast(pair.shapes[1]->userData);
+ ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor);
while (i.hasNextPatch())
{
@@ -219,6 +220,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
const PxContactPair& pair = pairs[i.contactPairIndex];
c.ThisActor = static_cast(pair.shapes[0]->userData);
c.OtherActor = static_cast(pair.shapes[1]->userData);
+ ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor);
Collision& collision = Collisions[CollidersPair(c.ThisActor, c.OtherActor)];
collision.ThisVelocity = P2C(linearVelocityActor0);
@@ -239,6 +241,7 @@ void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count)
auto trigger = static_cast(pair.triggerShape->userData);
auto otherCollider = static_cast(pair.otherShape->userData);
+ ASSERT_LOW_LAYER(trigger && otherCollider);
CollidersPair collidersPair(trigger, otherCollider);
if (pair.status & PxPairFlag::eNOTIFY_TOUCH_LOST)
@@ -256,3 +259,5 @@ void SimulationEventCallback::onAdvance(const PxRigidBody* const* bodyBuffer, co
{
// Not used
}
+
+#endif
diff --git a/Source/Engine/Physics/SimulationEventCallback.h b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h
similarity index 94%
rename from Source/Engine/Physics/SimulationEventCallback.h
rename to Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h
index c2705d255..c6f3019c5 100644
--- a/Source/Engine/Physics/SimulationEventCallback.h
+++ b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h
@@ -1,10 +1,12 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
+#if COMPILE_WITH_PHYSX
+
#include "Types.h"
-#include "Collisions.h"
-#include "Colliders/Collider.h"
+#include "Engine/Physics/Collisions.h"
+#include "Engine/Physics/Colliders/Collider.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Core/Collections/Dictionary.h"
#include
@@ -12,7 +14,6 @@
///
/// Default implementation of the PxSimulationEventCallback to send physics events to the other engine services.
///
-///
class SimulationEventCallback : public PxSimulationEventCallback
{
public:
@@ -106,3 +107,5 @@ public:
void onTrigger(PxTriggerPair* pairs, PxU32 count) override;
void onAdvance(const PxRigidBody* const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) override;
};
+
+#endif
diff --git a/Source/Engine/Physics/PhysX/Types.h b/Source/Engine/Physics/PhysX/Types.h
new file mode 100644
index 000000000..9d049e6d0
--- /dev/null
+++ b/Source/Engine/Physics/PhysX/Types.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if COMPILE_WITH_PHYSX
+
+#include "Engine/Physics/Types.h"
+#include "Engine/Core/Math/Vector2.h"
+#include "Engine/Core/Math/Vector3.h"
+#include "Engine/Core/Math/Vector4.h"
+#include "Engine/Core/Math/Quaternion.h"
+#include "Engine/Core/Math/BoundingBox.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace physx
+{
+ class PxScene;
+ class PxConvexMesh;
+ class PxTriangleMesh;
+ class PxCooking;
+ class PxPhysics;
+ class PxVec3;
+ class PxVec4;
+ class PxTransform;
+ class PxJoint;
+ class PxMat44;
+ class PxCpuDispatcher;
+ class PxGpuDispatcher;
+ class PxSimulationEventCallback;
+ struct PxActiveTransform;
+ class PxActor;
+ class PxRigidActor;
+ class PxRigidDynamic;
+ class PxRigidStatic;
+ class PxFoundation;
+ class PxShape;
+ class PxGeometry;
+ class PxGeometryHolder;
+ class PxProfileZoneManager;
+ class PxMaterial;
+ class PxPvd;
+ class PxBase;
+ class PxTolerancesScale;
+ class PxBaseTask;
+ class PxControllerManager;
+ class PxController;
+ class PxCapsuleController;
+ class PxQueryFilterCallback;
+ class PxControllerFilterCallback;
+ class PxHeightField;
+ struct PxFilterData;
+ struct PxRaycastHit;
+ struct PxSweepHit;
+}
+
+using namespace physx;
+
+#define RELEASE_PHYSX(x) if(x) { (x)->release(); x = nullptr; }
+
+inline PxVec2& C2P(const Vector2& v)
+{
+ return *(PxVec2*)&v;
+}
+
+inline PxVec3& C2P(const Vector3& v)
+{
+ return *(PxVec3*)&v;
+}
+
+inline PxVec4& C2P(const Vector4& v)
+{
+ return *(PxVec4*)&v;
+}
+
+inline PxQuat& C2P(const Quaternion& v)
+{
+ return *(PxQuat*)&v;
+}
+
+inline PxBounds3& C2P(const BoundingBox& v)
+{
+ return *(PxBounds3*)&v;
+}
+
+inline Vector2& P2C(const PxVec2& v)
+{
+ return *(Vector2*)&v;
+}
+
+inline Vector3& P2C(const PxVec3& v)
+{
+ return *(Vector3*)&v;
+}
+
+inline Vector4& P2C(const PxVec4& v)
+{
+ return *(Vector4*)&v;
+}
+
+inline Quaternion& P2C(const PxQuat& v)
+{
+ return *(Quaternion*)&v;
+}
+
+inline BoundingBox& P2C(const PxBounds3& v)
+{
+ return *(BoundingBox*)&v;
+}
+
+inline Vector3 P2C(const PxExtendedVec3& v)
+{
+#ifdef PX_BIG_WORLDS
+ return Vector3((float)v.x, (float)v.y, (float)v.z);
+#else
+ return *(Vector3*)&v;
+#endif
+}
+
+inline float M2ToCm2(float v)
+{
+ return v * (100.0f * 100.0f);
+}
+
+inline float Cm2ToM2(float v)
+{
+ return v / (100.0f * 100.0f);
+}
+
+inline float KgPerM3ToKgPerCm3(float v)
+{
+ return v / (100.0f * 100.0f * 100.0f);
+}
+
+inline float RpmToRadPerS(float v)
+{
+ return v * (PI / 30.0f);
+}
+
+inline float RadPerSToRpm(float v)
+{
+ return v * (30.0f / PI);
+}
+
+inline void P2C(const PxRaycastHit& hit, RayCastHit& result)
+{
+ result.Point = P2C(hit.position);
+ result.Normal = P2C(hit.normal);
+ result.Distance = hit.distance;
+ result.Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr;
+ result.FaceIndex = hit.faceIndex;
+ result.UV.X = hit.u;
+ result.UV.Y = hit.v;
+}
+
+inline void P2C(const PxSweepHit& hit, RayCastHit& result)
+{
+ result.Point = P2C(hit.position);
+ result.Normal = P2C(hit.normal);
+ result.Distance = hit.distance;
+ result.Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr;
+ result.FaceIndex = hit.faceIndex;
+ result.UV = Vector2::Zero;
+}
+
+extern PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled);
+
+#endif
diff --git a/Source/Engine/Physics/PhysicalMaterial.h b/Source/Engine/Physics/PhysicalMaterial.h
index 66b8e5c1c..9e49a1da6 100644
--- a/Source/Engine/Physics/PhysicalMaterial.h
+++ b/Source/Engine/Physics/PhysicalMaterial.h
@@ -14,7 +14,7 @@ API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial);
private:
- PxMaterial* _material;
+ void* _material;
public:
@@ -78,10 +78,10 @@ public:
/// Gets the PhysX material.
///
/// The native material object.
- PxMaterial* GetPhysXMaterial();
+ void* GetPhysicsMaterial();
///
- /// Updates the PhysX material (after any property change).
+ /// Updates the physics material (after any property change).
///
- void UpdatePhysXMaterial();
+ void UpdatePhysicsMaterial();
};
diff --git a/Source/Engine/Physics/Physics.Build.cs b/Source/Engine/Physics/Physics.Build.cs
index 555b605ba..6363e3775 100644
--- a/Source/Engine/Physics/Physics.Build.cs
+++ b/Source/Engine/Physics/Physics.Build.cs
@@ -1,5 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+using System;
using Flax.Build;
using Flax.Build.NativeCpp;
@@ -13,16 +14,26 @@ public class Physics : EngineModule
///
public static bool WithCooking = true;
+ ///
+ /// Physics system extension event to override for custom physics backend plugin.
+ ///
+ public static Action SetupPhysicsBackend = SetupPhysicsBackendPhysX;
+
///
public override void Setup(BuildOptions options)
{
base.Setup(options);
- options.PrivateDependencies.Add("PhysX");
+ SetupPhysicsBackend(this, options);
if (WithCooking)
{
options.PublicDefinitions.Add("COMPILE_WITH_PHYSICS_COOKING");
}
}
+
+ private static void SetupPhysicsBackendPhysX(Physics physics, BuildOptions options)
+ {
+ options.PrivateDependencies.Add("PhysX");
+ }
}
diff --git a/Source/Engine/Physics/Physics.Queries.cpp b/Source/Engine/Physics/Physics.Queries.cpp
deleted file mode 100644
index b8c691c21..000000000
--- a/Source/Engine/Physics/Physics.Queries.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
-
-#include "Physics.h"
-#include "Utilities.h"
-#include "CollisionData.h"
-#include "PhysicsScene.h"
-#include "Actors/PhysicsColliderActor.h"
-
-bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers);
-}
-
-bool Physics::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CheckBox(center, halfExtents, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CheckSphere(center, radius, layerMask, hitTriggers);
-}
-
-bool Physics::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CheckCapsule(center, radius, height, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->CheckConvex(center, convexMesh, scale, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers);
-}
-
-bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
-}
diff --git a/Source/Engine/Physics/Physics.cpp b/Source/Engine/Physics/Physics.cpp
index 6198accfc..7ef1d4910 100644
--- a/Source/Engine/Physics/Physics.cpp
+++ b/Source/Engine/Physics/Physics.cpp
@@ -2,94 +2,14 @@
#include "Physics.h"
#include "PhysicsScene.h"
+#include "PhysicsBackend.h"
#include "PhysicalMaterial.h"
-
-#include "Engine/Core/Log.h"
-#include "Engine/Platform/CPUInfo.h"
#include "PhysicsSettings.h"
-#include "Utilities.h"
-#include "PhysicsStepper.h"
-
-#include "Engine/Level/Level.h"
-#include "Engine/Profiler/ProfilerCPU.h"
-#include "Engine/Core/Memory/Memory.h"
-#include "Engine/Engine/EngineService.h"
-#include "Engine/Serialization/Serialization.h"
#include "Engine/Engine/Time.h"
-#include
-#if WITH_PVD
-#include
-#endif
-
-#define PHYSX_VEHICLE_DEBUG_TELEMETRY 0
-
-#if PHYSX_VEHICLE_DEBUG_TELEMETRY
-#include "Engine/Core/Utilities.h"
-#endif
-
-class PhysXAllocator : public PxAllocatorCallback
-{
-public:
-
- void* allocate(size_t size, const char* typeName, const char* filename, int line) override
- {
- return Allocator::Allocate(size, 16);
- }
-
- void deallocate(void* ptr) override
- {
- Allocator::Free(ptr);
- }
-};
-
-class PhysXError : public PxErrorCallback
-{
-public:
-
- PhysXError()
- {
- }
-
- ~PhysXError()
- {
- }
-
-public:
-
- // [PxErrorCallback]
- void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) override
- {
- LOG(Error, "PhysX Error! Code: {0}.\n{1}\nSource: {2} : {3}.", static_cast(code), String(message), String(file), line);
- }
-};
-
-PxPhysics* CPhysX = nullptr;
-#if WITH_PVD
-PxPvd* CPVD = nullptr;
-#endif
-
-namespace
-{
- PhysXAllocator PhysXAllocatorCallback;
- PhysXError PhysXErrorCallback;
- PxTolerancesScale ToleranceScale;
- bool _queriesHitTriggers = true;
- PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average;
- PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average;
- PxFoundation* _foundation = nullptr;
-#if COMPILE_WITH_PHYSICS_COOKING
- PxCooking* Cooking = nullptr;
-#endif
- PxMaterial* DefaultMaterial = nullptr;
-#if WITH_VEHICLE
- bool VehicleSDKInitialized = false;
-#endif
-
- void reset()
- {
- Physics::Scenes.Resize(1);
- }
-}
+#include "Engine/Engine/EngineService.h"
+#include "Engine/Profiler/ProfilerCPU.h"
+#include "Engine/Serialization/Serialization.h"
+#include "Engine/Threading/Threading.h"
PhysicsScene* Physics::DefaultScene = nullptr;
Array Physics::Scenes;
@@ -98,7 +18,6 @@ uint32 Physics::LayerMasks[32];
class PhysicsService : public EngineService
{
public:
-
PhysicsService()
: EngineService(TEXT("Physics"), 0)
{
@@ -113,74 +32,14 @@ public:
PhysicsService PhysicsServiceInstance;
-PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled)
-{
-#if WITH_PVD
- PxShapeFlags flags = PxShapeFlag::eVISUALIZATION;
-#else
- PxShapeFlags flags = static_cast(0);
-#endif
-
- if (isEnabled)
- {
- if (isTrigger)
- {
- flags |= PxShapeFlag::eTRIGGER_SHAPE;
- if (_queriesHitTriggers)
- flags |= PxShapeFlag::eSCENE_QUERY_SHAPE;
- }
- else
- {
- flags = PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eSCENE_QUERY_SHAPE;
- }
- }
-
- return flags;
-}
-
-#if WITH_VEHICLE
-
-void InitVehicleSDK()
-{
- if (!VehicleSDKInitialized)
- {
- VehicleSDKInitialized = true;
- PxInitVehicleSDK(*CPhysX);
- PxVehicleSetBasisVectors(PxVec3(0, 1, 0), PxVec3(1, 0, 0));
- PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE);
- }
-}
-
-#endif
-
void PhysicsSettings::Apply()
{
Time::_physicsMaxDeltaTime = MaxDeltaTime;
- _queriesHitTriggers = QueriesHitTriggers;
- _frictionCombineMode = FrictionCombineMode;
- _restitutionCombineMode = RestitutionCombineMode;
Platform::MemoryCopy(Physics::LayerMasks, LayerMasks, sizeof(LayerMasks));
Physics::SetGravity(DefaultGravity);
Physics::SetBounceThresholdVelocity(BounceThresholdVelocity);
Physics::SetEnableCCD(!DisableCCD);
-
- // TODO: setting eADAPTIVE_FORCE requires PxScene setup (physx docs: This flag is not mutable, and must be set in PxSceneDesc at scene creation.)
- // TODO: update all shapes filter data
- // TODO: update all shapes flags
-
- /*
- {
- get all actors and then:
-
- const PxU32 numShapes = actor->getNbShapes();
- PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes);
- actor->getShapes(shapes, numShapes);
- for (PxU32 i = 0; i < numShapes; i++)
- {
- ..
- }
- SAMPLE_FREE(shapes);
- }*/
+ PhysicsBackend::ApplySettings(*this);
}
PhysicsSettings::PhysicsSettings()
@@ -225,193 +84,77 @@ PhysicalMaterial::PhysicalMaterial()
PhysicalMaterial::~PhysicalMaterial()
{
if (_material)
- {
- for (auto scene : Physics::Scenes)
- scene->RemoveMaterial(_material);
- }
-}
-
-PxMaterial* PhysicalMaterial::GetPhysXMaterial()
-{
- if (_material == nullptr && CPhysX)
- {
- _material = CPhysX->createMaterial(Friction, Friction, Restitution);
- _material->userData = this;
-
- const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode;
- _material->setFrictionCombineMode(static_cast(useFrictionCombineMode));
-
- const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
- _material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode));
- }
-
- return _material;
-}
-
-void PhysicalMaterial::UpdatePhysXMaterial()
-{
- if (_material != nullptr)
- {
- _material->setStaticFriction(Friction);
- _material->setDynamicFriction(Friction);
-
- const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode;
- _material->setFrictionCombineMode(static_cast(useFrictionCombineMode));
-
- _material->setRestitution(Restitution);
- const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
- _material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode));
- }
+ PhysicsBackend::DestroyObject(_material);
}
bool PhysicsService::Init()
{
-#define CHECK_INIT(value, msg) if(!value) { LOG(Error, msg); return true; }
-
- auto& settings = *PhysicsSettings::Get();
-
- // Send info
- LOG(Info, "Setup NVIDIA PhysX {0}.{1}.{2}", PX_PHYSICS_VERSION_MAJOR, PX_PHYSICS_VERSION_MINOR, PX_PHYSICS_VERSION_BUGFIX);
-
- // Init PhysX foundation object
- _foundation = PxCreateFoundation(PX_PHYSICS_VERSION, PhysXAllocatorCallback, PhysXErrorCallback);
- CHECK_INIT(_foundation, "PxCreateFoundation failed!");
-
- // Config
- ToleranceScale.length = 100;
- ToleranceScale.speed = 981;
-
- PxPvd* pvd = nullptr;
-#if WITH_PVD
- {
- // Init PVD
- pvd = PxCreatePvd(*_foundation);
- PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("127.0.0.1", 5425, 100);
- //PxPvdTransport* transport = PxDefaultPvdFileTransportCreate("D:\\physx_sample.pxd2");
- if (transport)
- {
- const bool isConnected = pvd->connect(*transport, PxPvdInstrumentationFlag::eALL);
- if (isConnected)
- {
- LOG(Info, "Connected to PhysX Visual Debugger (PVD)");
- }
- }
- CPVD = pvd;
- }
-
-#endif
-
- // Init PhysX
- CPhysX = PxCreatePhysics(PX_PHYSICS_VERSION, *_foundation, ToleranceScale, false, pvd);
- CHECK_INIT(CPhysX, "PxCreatePhysics failed!");
-
- // Init extensions
- const bool extensionsInit = PxInitExtensions(*CPhysX, pvd);
- CHECK_INIT(extensionsInit, "PxInitExtensions failed!");
-
- // Init collision cooking
-#if COMPILE_WITH_PHYSICS_COOKING
-#if !USE_EDITOR
- if (settings.SupportCookingAtRuntime)
-#endif
- {
- PxCookingParams cookingParams(ToleranceScale);
- cookingParams.meshWeldTolerance = 0.1f; // Weld to 1mm precision
- cookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES);
- Cooking = PxCreateCooking(PX_PHYSICS_VERSION, *_foundation, cookingParams);
- CHECK_INIT(Cooking, "PxCreateCooking failed!");
- }
-#endif
+ // Initialize backend
+ if (PhysicsBackend::Init())
+ return true;
+ // Create default scene
Physics::DefaultScene = Physics::FindOrCreateScene(TEXT("Default"));
-
- // Create default resources
- DefaultMaterial = CPhysX->createMaterial(0.7f, 0.7f, 0.3f);
-
- return false;
-
-#undef CHECK_INIT
+ return Physics::DefaultScene == nullptr;
}
void PhysicsService::LateUpdate()
{
- for (auto scene : Physics::Scenes)
- scene->FlushRequests();
+ Physics::FlushRequests();
}
void PhysicsService::Dispose()
{
// Ensure to finish (wait for simulation end)
-
- for (auto scene : Physics::Scenes)
+ for (PhysicsScene* scene : Physics::Scenes)
{
scene->CollectResults();
-
- if (CPhysX)
- scene->FlushRequests();
}
-#if WITH_VEHICLE
- if (VehicleSDKInitialized)
+ // Dispose scenes
+ for (PhysicsScene* scene : Physics::Scenes)
{
- VehicleSDKInitialized = false;
- PxCloseVehicleSDK();
+ Delete(scene);
}
-#endif
-
- // Cleanup
- RELEASE_PHYSX(DefaultMaterial);
-
Physics::Scenes.Resize(0);
Physics::DefaultScene = nullptr;
- // Remove all scenes still registered
- const int32 numScenes = CPhysX ? CPhysX->getNbScenes() : 0;
- if (numScenes)
- {
- Array PScenes;
- PScenes.Resize(numScenes);
- PScenes.SetAll(nullptr);
- CPhysX->getScenes(PScenes.Get(), sizeof(PxScene*) * numScenes);
+ // Dispose backend
+ PhysicsBackend::Shutdown();
+}
- for (int32 i = 0; i < numScenes; i++)
+PhysicsScene* Physics::FindOrCreateScene(const StringView& name)
+{
+ auto scene = FindScene(name);
+ if (scene == nullptr)
+ {
+ const auto& settings = *PhysicsSettings::Get();
+ scene = New();
+ if (scene->Init(name, settings))
{
- if (PScenes[i])
- {
- PScenes[i]->release();
- }
+ Delete(scene);
+ scene = nullptr;
}
+ else
+ Scenes.Add(scene);
+ return scene;
}
+ return scene;
+}
-#if COMPILE_WITH_PHYSICS_COOKING
- RELEASE_PHYSX(Cooking);
-#endif
-
- if (CPhysX)
+PhysicsScene* Physics::FindScene(const StringView& name)
+{
+ for (PhysicsScene* scene : Scenes)
{
- PxCloseExtensions();
+ if (scene->GetName() == name)
+ return scene;
}
-
- RELEASE_PHYSX(CPhysX);
-#if WITH_PVD
- RELEASE_PHYSX(CPVD);
-#endif
- RELEASE_PHYSX(_foundation);
+ return nullptr;
}
-PxPhysics* Physics::GetPhysics()
+bool Physics::GetAutoSimulation()
{
- return CPhysX;
-}
-
-PxCooking* Physics::GetCooking()
-{
- return Cooking;
-}
-
-PxTolerancesScale* Physics::GetTolerancesScale()
-{
- return &ToleranceScale;
+ return !DefaultScene || DefaultScene->GetAutoSimulation();
}
Vector3 Physics::GetGravity()
@@ -449,13 +192,7 @@ void Physics::SetBounceThresholdVelocity(const float value)
void Physics::Simulate(float dt)
{
- if (DefaultScene)
- DefaultScene->Simulate(dt);
-}
-
-void Physics::SimulateAll(float dt)
-{
- for (auto scene : Scenes)
+ for (PhysicsScene* scene : Scenes)
{
if (scene->GetAutoSimulation())
scene->Simulate(dt);
@@ -468,67 +205,373 @@ void Physics::CollectResults()
DefaultScene->CollectResults();
}
-void Physics::CollectResultsAll()
-{
- for (auto scene : Scenes)
- scene->CollectResults();
-}
-
bool Physics::IsDuringSimulation()
{
- if (DefaultScene)
- return DefaultScene->IsDuringSimulation();
-
- return false;
+ return DefaultScene && DefaultScene->IsDuringSimulation();
}
-PxMaterial* Physics::GetDefaultMaterial()
+void Physics::FlushRequests()
{
- return DefaultMaterial;
+ PROFILE_CPU_NAMED("Physics.FlushRequests");
+ for (PhysicsScene* scene : Scenes)
+ PhysicsBackend::FlushRequests(scene->GetPhysicsScene());
+ PhysicsBackend::FlushRequests();
}
-bool Physics::GetAutoSimulation()
+bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
- if (DefaultScene)
- return DefaultScene->GetAutoSimulation();
-
- return false;
+ return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers);
}
-void Physics::FlushRequestsAll()
+bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
- for (auto scene : Scenes)
- scene->FlushRequests();
+ return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers);
}
-void Physics::RemoveJoint(Joint* joint)
+bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
- for (auto scene : Scenes)
- scene->RemoveJoint(joint);
+ return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers);
}
-PhysicsScene* Physics::FindOrCreateScene(const String& name)
+bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
- auto scene = FindScene(name);
+ return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
- if (scene == nullptr)
+bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool Physics::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CheckBox(center, halfExtents, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CheckSphere(center, radius, layerMask, hitTriggers);
+}
+
+bool Physics::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CheckCapsule(center, radius, height, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->CheckConvex(center, convexMesh, scale, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers);
+}
+
+bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
+}
+
+PhysicsScene::PhysicsScene(const SpawnParams& params)
+ : ScriptingObject(params)
+{
+}
+
+PhysicsScene::~PhysicsScene()
+{
+ if (_scene)
+ PhysicsBackend::DestroyScene(_scene);
+}
+
+String PhysicsScene::GetName() const
+{
+ return _name;
+}
+
+bool PhysicsScene::GetAutoSimulation() const
+{
+ return _autoSimulation;
+}
+
+void PhysicsScene::SetAutoSimulation(bool value)
+{
+ _autoSimulation = value;
+}
+
+void PhysicsScene::SetGravity(const Vector3& value)
+{
+ PhysicsBackend::SetSceneGravity(_scene, value);
+}
+
+Vector3 PhysicsScene::GetGravity()
+{
+ return PhysicsBackend::GetSceneGravity(_scene);
+}
+
+bool PhysicsScene::GetEnableCCD()
+{
+ return PhysicsBackend::GetSceneEnableCCD(_scene);
+}
+
+void PhysicsScene::SetEnableCCD(bool value)
+{
+ PhysicsBackend::SetSceneEnableCCD(_scene, value);
+}
+
+float PhysicsScene::GetBounceThresholdVelocity()
+{
+ return PhysicsBackend::GetSceneBounceThresholdVelocity(_scene);
+}
+
+void PhysicsScene::SetBounceThresholdVelocity(float value)
+{
+ PhysicsBackend::SetSceneBounceThresholdVelocity(_scene, value);
+}
+
+bool PhysicsScene::Init(const StringView& name, const PhysicsSettings& settings)
+{
+ if (_scene)
{
- auto& settings = *PhysicsSettings::Get();
-
- scene = New(name, settings);
- Scenes.Add(scene);
+ PhysicsBackend::DestroyScene(_scene);
}
-
- return scene;
+ _name = name;
+ _scene = PhysicsBackend::CreateScene(settings);
+ return _scene == nullptr;
}
-PhysicsScene* Physics::FindScene(const String& name)
+void PhysicsScene::Simulate(float dt)
{
- for (auto scene : Scenes)
- {
- if (scene->GetName() == name)
- return scene;
- }
-
- return nullptr;
+ ASSERT(IsInMainThread() && !_isDuringSimulation);
+ _isDuringSimulation = true;
+ PhysicsBackend::StartSimulateScene(_scene, dt);
+}
+
+bool PhysicsScene::IsDuringSimulation() const
+{
+ return _isDuringSimulation;
+}
+
+void PhysicsScene::CollectResults()
+{
+ if (!_isDuringSimulation)
+ return;
+ ASSERT(IsInMainThread());
+ PhysicsBackend::EndSimulateScene(_scene);
+ _isDuringSimulation = false;
+}
+
+bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::RayCast(_scene, origin, direction, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::RayCast(_scene, origin, direction, hitInfo, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::RayCastAll(_scene, origin, direction, results, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::BoxCastAll(_scene, center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::SphereCast(_scene, center, radius, direction, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::SphereCast(_scene, center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::SphereCastAll(_scene, center, radius, direction, results, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CapsuleCastAll(_scene, center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::ConvexCastAll(_scene, center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CheckBox(_scene, center, halfExtents, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CheckSphere(_scene, center, radius, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CheckCapsule(_scene, center, radius, height, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::CheckConvex(_scene, center, convexMesh, scale, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapBox(_scene, center, halfExtents, results, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapSphere(_scene, center, radius, results, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapCapsule(_scene, center, radius, height, results, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapConvex(_scene, center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapBox(_scene, center, halfExtents, results, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapSphere(_scene, center, radius, results, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapCapsule(_scene, center, radius, height, results, rotation, layerMask, hitTriggers);
+}
+
+bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
+{
+ return PhysicsBackend::OverlapConvex(_scene, center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
}
diff --git a/Source/Engine/Physics/Physics.h b/Source/Engine/Physics/Physics.h
index f2317288a..01b8d6e4b 100644
--- a/Source/Engine/Physics/Physics.h
+++ b/Source/Engine/Physics/Physics.h
@@ -2,125 +2,35 @@
#pragma once
-#include "Engine/Core/Math/Vector2.h"
-#include "Engine/Core/Math/Vector3.h"
#include "Engine/Core/Math/Quaternion.h"
-#include "Engine/Scripting/ScriptingType.h"
#include "Types.h"
-class PhysicsColliderActor;
-class PhysicsScene;
-class Joint;
-class Collider;
-class CollisionData;
-
-///
-/// Raycast hit result data.
-///
-API_STRUCT() struct RayCastHit
-{
-DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
-
- ///
- /// The collider that was hit.
- ///
- API_FIELD() PhysicsColliderActor* Collider = nullptr;
-
- ///
- /// The normal of the surface the ray hit.
- ///
- API_FIELD() Vector3 Normal;
-
- ///
- /// The distance from the ray's origin to the hit location.
- ///
- API_FIELD() float Distance;
-
- ///
- /// The point in the world space where ray hit the collider.
- ///
- API_FIELD() Vector3 Point;
-
- ///
- /// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
- ///
- ///
- API_FIELD() uint32 FaceIndex;
-
- ///
- /// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
- ///
- API_FIELD() Vector2 UV;
-
-public:
-
- ///
- /// Gathers the data from the specified hit (PhysX).
- ///
- /// The hit.
- void Gather(const PxRaycastHit& hit);
-
- ///
- /// Gathers the data from the specified hit (PhysX).
- ///
- /// The hit.
- void Gather(const PxSweepHit& hit);
-};
-
///
/// Physics simulation system.
///
API_CLASS(Static) class FLAXENGINE_API Physics
{
-DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics);
+ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics);
- ///
- /// Gets the master physics object.
- ///
- static PxPhysics* GetPhysics();
-
-#if COMPILE_WITH_PHYSICS_COOKING
-
- ///
- /// Gets physics cooking object
- ///
- static PxCooking* GetCooking();
-
-#endif
-
- ///
- /// Gets the physics tolerances scale.
- ///
- static PxTolerancesScale* GetTolerancesScale();
-
- ///
- /// Gets the default physical material.
- ///
- static PxMaterial* GetDefaultMaterial();
-
-public:
-
///
/// The default physics scene.
///
- API_FIELD(ReadOnly)
- static PhysicsScene* DefaultScene;
+ API_FIELD(ReadOnly) static PhysicsScene* DefaultScene;
///
/// List with all physics scenes (readonly).
///
- API_FIELD(ReadOnly)
- static Array Scenes;
+ API_FIELD(ReadOnly) static Array Scenes;
///
/// Finds an existing or creates it if it does not exist.
///
- API_FUNCTION() static PhysicsScene* FindOrCreateScene(const String& name);
+ API_FUNCTION() static PhysicsScene* FindOrCreateScene(const StringView& name);
///
- ///Finds an existing scene.
+ /// Finds an existing scene.
///
- API_FUNCTION() static PhysicsScene* FindScene(const String& name);
+ API_FUNCTION() static PhysicsScene* FindScene(const StringView& name);
public:
///
@@ -162,9 +72,29 @@ public:
/// The collision layers masks. Used to define layer-based collision detection.
///
static uint32 LayerMasks[32];
+public:
+ ///
+ /// Called during main engine loop to start physic simulation. Use CollectResults after.
+ ///
+ /// The delta time (in seconds).
+ API_FUNCTION() static void Simulate(float dt);
+
+ ///
+ /// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events.
+ ///
+ API_FUNCTION() static void CollectResults();
+
+ ///
+ /// Checks if physical simulation is running.
+ ///
+ API_PROPERTY() static bool IsDuringSimulation();
+
+ ///
+ /// Flushes any latent physics actions (eg. object destroy, actor add/remove to the scene, etc.).
+ ///
+ API_FUNCTION() static void FlushRequests();
public:
-
///
/// Performs a raycast against objects in the scene.
///
@@ -509,84 +439,4 @@ public:
/// If set to true triggers will be hit, otherwise will skip them.
/// True if convex mesh overlaps any matching object, otherwise false.
API_FUNCTION() static bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array& results, const Quaternion& rotation = Quaternion::Identity, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
-
-public:
-
- ///
- /// Called during main engine loop to start physic simulation. Use CollectResults after.
- ///
- /// The delta time (in seconds).
- API_FUNCTION() static void Simulate(float dt);
-
- ///
- /// Called during main engine loop to start physic simulation on all registered scenes.
- ///
- /// The delta time (in seconds).
- static void SimulateAll(float dt);
-
- ///
- /// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events.
- ///
- API_FUNCTION() static void CollectResults();
-
- ///
- /// Called during main engine loop to collect physic simulation results on all registered scenes and apply them as well as fire collision events.
- ///
- static void CollectResultsAll();
-
- ///
- /// Checks if physical simulation is running
- ///
- /// True if simulation is active, otherwise false
- API_PROPERTY() static bool IsDuringSimulation();
-
-public:
-
- ///
- /// Flushes the async requests to add/remove actors, remove materials, etc..
- ///
- static void FlushRequestsAll();
-
- ///
- /// Removes the material (using safe async request).
- ///
- /// The material.
- static void RemoveMaterial(PxMaterial* material);
-
- ///
- /// Removes the physX object via calling release() on it (using safe async request).
- ///
- /// The obj.
- static void RemoveObject(PxBase* obj);
-
- ///
- /// Adds the actor (using safe async request).
- ///
- /// The actor.
- static void AddActor(PxActor* actor);
-
- ///
- /// Adds the actor (using safe async request).
- ///
- /// The actor.
- /// If set to true will put actor to sleep after spawning.
- static void AddActor(PxRigidDynamic* actor, bool putToSleep = false);
-
- ///
- /// Removes the actor (using safe async request).
- ///
- /// The actor.
- static void RemoveActor(PxActor* actor);
-
- ///
- /// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object).
- ///
- /// The collider.
- static void RemoveCollider(PhysicsColliderActor* collider);
-
- ///
- /// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object).
- ///
- /// The joint.
- static void RemoveJoint(Joint* joint);
};
diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h
new file mode 100644
index 000000000..1e9993fb0
--- /dev/null
+++ b/Source/Engine/Physics/PhysicsBackend.h
@@ -0,0 +1,294 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Physics.h"
+#include "PhysicsSettings.h"
+
+struct HingeJointDrive;
+struct SpringParameters;
+struct LimitLinearRange;
+struct LimitAngularRange;
+struct LimitConeRange;
+struct LimitLinear;
+struct D6JointDrive;
+enum class HingeJointFlag;
+enum class DistanceJointFlag;
+enum class SliderJointFlag;
+enum class SphericalJointFlag;
+enum class D6JointAxis;
+enum class D6JointMotion;
+enum class D6JointDriveType;
+class IPhysicsActor;
+class PhysicalMaterial;
+class JsonAsset;
+
+struct PhysicsJointDesc
+{
+ Joint* Joint;
+ void* Actor0;
+ void* Actor1;
+ Quaternion Rot0;
+ Quaternion Rot1;
+ Vector3 Pos0;
+ Vector3 Pos1;
+};
+
+///
+/// Interface for the physical simulation backend implementation.
+///
+class PhysicsBackend
+{
+public:
+ enum class ActorFlags
+ {
+ None = 0,
+ NoGravity = 1 << 0,
+ NoSimulation = 1 << 1,
+ };
+
+ enum class RigidDynamicFlags
+ {
+ None = 0,
+ Kinematic = 1 << 0,
+ CCD = 1 << 1,
+ };
+
+ enum class JointFlags
+ {
+ None = 0,
+ Collision = 1 << 0,
+ };
+
+ enum class ActionType
+ {
+ Sleep,
+ };
+
+ struct HeightFieldSample
+ {
+ int16 Height;
+ uint8 MaterialIndex0;
+ uint8 MaterialIndex1;
+ };
+
+ enum class HeightFieldMaterial
+ {
+ Hole = 127,
+ };
+
+public:
+ // General
+ static bool Init();
+ static void Shutdown();
+ static void ApplySettings(const PhysicsSettings& settings);
+
+ // Scene
+ static void* CreateScene(const PhysicsSettings& settings);
+ static void DestroyScene(void* scene);
+ static void StartSimulateScene(void* scene, float dt);
+ static void EndSimulateScene(void* scene);
+ static Vector3 GetSceneGravity(void* scene);
+ static void SetSceneGravity(void* scene, const Vector3& value);
+ static bool GetSceneEnableCCD(void* scene);
+ static void SetSceneEnableCCD(void* scene, bool value);
+ static float GetSceneBounceThresholdVelocity(void* scene);
+ static void SetSceneBounceThresholdVelocity(void* scene, float value);
+ static void AddSceneActor(void* scene, void* actor);
+ static void RemoveSceneActor(void* scene, void* actor);
+ static void AddSceneActorAction(void* scene, void* actor, ActionType action);
+
+ // Scene Queries
+ static bool RayCast(void* scene, const Vector3& origin, const Vector3& direction, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool RayCastAll(void* scene, const Vector3& origin, const Vector3& direction, Array& results, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool BoxCastAll(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool SphereCast(void* scene, const Vector3& center, float radius, const Vector3& direction, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool SphereCast(void* scene, const Vector3& center, float radius, const Vector3& direction, RayCastHit& hitInfo, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool SphereCastAll(void* scene, const Vector3& center, float radius, const Vector3& direction, Array& results, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool CapsuleCast(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool CapsuleCast(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool CapsuleCastAll(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool ConvexCastAll(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers);
+ static bool CheckBox(void* scene, const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool CheckSphere(void* scene, const Vector3& center, float radius, uint32 layerMask, bool hitTriggers);
+ static bool CheckCapsule(void* scene, const Vector3& center, float radius, float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool CheckConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array& results, uint32 layerMask, bool hitTriggers);
+ static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array& results, uint32 layerMask, bool hitTriggers);
+ static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+ static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
+
+ // Actors
+ static ActorFlags GetActorFlags(void* actor);
+ static void SetActorFlags(void* actor, ActorFlags value);
+ static void GetActorBounds(void* actor, BoundingBox& bounds);
+ static void* CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation);
+ static void* CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation);
+ static RigidDynamicFlags GetRigidDynamicActorFlags(void* actor);
+ static void SetRigidDynamicActorFlags(void* actor, RigidDynamicFlags value);
+ static void GetRigidActorPose(void* actor, Vector3& position, Quaternion& orientation);
+ static void SetRigidActorPose(void* actor, const Vector3& position, const Quaternion& orientation, bool kinematic = false, bool wakeUp = false);
+ static void SetRigidDynamicActorLinearDamping(void* actor, float value);
+ static void SetRigidDynamicActorAngularDamping(void* actor, float value);
+ static void SetRigidDynamicActorMaxAngularVelocity(void* actor, float value);
+ static void SetRigidDynamicActorConstraints(void* actor, RigidbodyConstraints value);
+ static Vector3 GetRigidDynamicActorLinearVelocity(void* actor);
+ static void SetRigidDynamicActorLinearVelocity(void* actor, const Vector3& value, bool wakeUp);
+ static Vector3 GetRigidDynamicActorAngularVelocity(void* actor);
+ static void SetRigidDynamicActorAngularVelocity(void* actor, const Vector3& value, bool wakeUp);
+ static Vector3 GetRigidDynamicActorCenterOfMass(void* actor);
+ static void SetRigidDynamicActorCenterOfMassOffset(void* actor, const Vector3& value);
+ static bool GetRigidDynamicActorIsSleeping(void* actor);
+ static void GetRigidActorSleep(void* actor);
+ static void GetRigidDynamicActorWakeUp(void* actor);
+ static float GetRigidDynamicActorSleepThreshold(void* actor);
+ static void SetRigidDynamicActorSleepThreshold(void* actor, float value);
+ static float GetRigidDynamicActorMaxDepenetrationVelocity(void* actor);
+ static void SetRigidDynamicActorMaxDepenetrationVelocity(void* actor, float value);
+ static void SetRigidDynamicActorSolverIterationCounts(void* actor, int32 minPositionIters, int32 minVelocityIters);
+ static void UpdateRigidDynamicActorMass(void* actor, float& mass, float massScale, bool autoCalculate);
+ static void AddRigidDynamicActorForce(void* actor, const Vector3& force, ForceMode mode);
+ static void AddRigidDynamicActorForceAtPosition(void* actor, const Vector3& force, const Vector3& position, ForceMode mode);
+ static void AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode);
+
+ // Shapes
+ static void* CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger);
+ static void SetShapeState(void* shape, bool enabled, bool trigger);
+ static void SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1);
+ static void* GetShapeActor(void* shape);
+ static void GetShapePose(void* shape, Vector3& position, Quaternion& orientation);
+ static CollisionShape::Types GetShapeType(void* shape);
+ static void GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation);
+ static void SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation);
+ static void SetShapeContactOffset(void* shape, float value);
+ static void SetShapeMaterial(void* shape, JsonAsset* material);
+ static void SetShapeGeometry(void* shape, const CollisionShape& geometry);
+ static void AttachShape(void* shape, void* actor);
+ static void DetachShape(void* shape, void* actor);
+ static bool ComputeShapesPenetration(void* shapeA, void* shapeB, const Vector3& positionA, const Quaternion& orientationA, const Vector3& positionB, const Quaternion& orientationB, Vector3& direction, float& distance);
+ static float ComputeShapeSqrDistanceToPoint(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& point, Vector3* closestPoint = nullptr);
+ static bool RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance);
+ static bool RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance);
+
+ // Joints
+ static void SetJointFlags(void* joint, JointFlags value);
+ static void SetJointActors(void* joint, void* actors0, void* actor1);
+ static void SetJointActorPose(void* joint, const Vector3& position, const Quaternion& orientation, uint8 index);
+ static void SetJointBreakForce(void* joint, float force, float torque);
+ static void GetJointForce(void* joint, Vector3& linear, Vector3& angular);
+ static void* CreateFixedJoint(const PhysicsJointDesc& desc);
+ static void* CreateDistanceJoint(const PhysicsJointDesc& desc);
+ static void* CreateHingeJoint(const PhysicsJointDesc& desc);
+ static void* CreateSliderJoint(const PhysicsJointDesc& desc);
+ static void* CreateSphericalJoint(const PhysicsJointDesc& desc);
+ static void* CreateD6Joint(const PhysicsJointDesc& desc);
+ static void SetDistanceJointFlags(void* joint, DistanceJointFlag flags);
+ static void SetDistanceJointMinDistance(void* joint, float value);
+ static void SetDistanceJointMaxDistance(void* joint, float value);
+ static void SetDistanceJointTolerance(void* joint, float value);
+ static void SetDistanceJointSpring(void* joint, const SpringParameters& value);
+ static float GetDistanceJointDistance(void* joint);
+ static void SetHingeJointFlags(void* joint, HingeJointFlag value, bool driveFreeSpin);
+ static void SetHingeJointLimit(void* joint, const LimitAngularRange& value);
+ static void SetHingeJointDrive(void* joint, const HingeJointDrive& value);
+ static float GetHingeJointAngle(void* joint);
+ static float GetHingeJointVelocity(void* joint);
+ static void SetSliderJointFlags(void* joint, SliderJointFlag value);
+ static void SetSliderJointLimit(void* joint, const LimitLinearRange& value);
+ static float GetSliderJointPosition(void* joint);
+ static float GetSliderJointVelocity(void* joint);
+ static void SetSphericalJointFlags(void* joint, SphericalJointFlag value);
+ static void SetSphericalJointLimit(void* joint, const LimitConeRange& value);
+ static void SetD6JointMotion(void* joint, D6JointAxis axis, D6JointMotion value);
+ static void SetD6JointDrive(void* joint, const D6JointDriveType index, const D6JointDrive& value);
+ static void SetD6JointLimitLinear(void* joint, const LimitLinear& value);
+ static void SetD6JointLimitTwist(void* joint, const LimitAngularRange& value);
+ static void SetD6JointLimitSwing(void* joint, const LimitConeRange& value);
+ static Vector3 GetD6JointDrivePosition(void* joint);
+ static void SetD6JointDrivePosition(void* joint, const Vector3& value);
+ static Quaternion GetD6JointDriveRotation(void* joint);
+ static void SetD6JointDriveRotation(void* joint, const Quaternion& value);
+ static void GetD6JointDriveVelocity(void* joint, Vector3& linear, Vector3& angular);
+ static void SetD6JointDriveVelocity(void* joint, const Vector3& linear, const Vector3& angular);
+ static float GetD6JointTwist(void* joint);
+ static float GetD6JointSwingY(void* joint);
+ static float GetD6JointSwingZ(void* joint);
+
+ // Character Controllers
+ static void* CreateController(void* scene, IPhysicsActor* actor, PhysicsColliderActor* collider, float contactOffset, const Vector3& position, float slopeLimit, int32 nonWalkableMode, JsonAsset* material, float radius, float height, float stepOffset, void*& shape);
+ static void* GetControllerRigidDynamicActor(void* controller);
+ static void SetControllerSize(void* controller, float radius, float height);
+ static void SetControllerSlopeLimit(void* controller, float value);
+ static void SetControllerNonWalkableMode(void* controller, int32 value);
+ static void SetControllerStepOffset(void* controller, float value);
+ static Vector3 GetControllerUpDirection(void* controller);
+ static void SetControllerUpDirection(void* controller, const Vector3& value);
+ static Vector3 GetControllerPosition(void* controller);
+ static void SetControllerPosition(void* controller, const Vector3& value);
+ static int32 MoveController(void* controller, void* shape, const Vector3& displacement, float minMoveDistance, float deltaTime);
+
+#if WITH_VEHICLE
+ // Vehicles
+ static void* CreateVehicle(class WheeledVehicle* actor);
+ static void DestroyVehicle(void* vehicle, int32 driveType);
+ static void SetVehicleGearbox(void* vehicle, const void* value);
+ static int32 GetVehicleTargetGear(void* vehicle);
+ static void SetVehicleTargetGear(void* vehicle, int32 value);
+ static int32 GetVehicleCurrentGear(void* vehicle);
+ static void SetVehicleCurrentGear(void* vehicle, int32 value);
+ static float GetVehicleForwardSpeed(void* vehicle);
+ static float GetVehicleSidewaysSpeed(void* vehicle);
+ static float GetVehicleEngineRotationSpeed(void* vehicle);
+ static void AddVehicle(void* scene, WheeledVehicle* actor);
+ static void RemoveVehicle(void* scene, WheeledVehicle* actor);
+#endif
+
+ // Resources
+ static void* CreateConvexMesh(byte* data, int32 dataSize, BoundingBox& localBounds);
+ static void* CreateTriangleMesh(byte* data, int32 dataSize, BoundingBox& localBounds);
+ static void* CreateHeightField(byte* data, int32 dataSize);
+ static void GetConvexMeshTriangles(void* contextMesh, Array& vertexBuffer, Array& indexBuffer);
+ static void GetTriangleMeshTriangles(void* triangleMesh, Array& vertexBuffer, Array& indexBuffer);
+ static const uint32* GetTriangleMeshRemap(void* triangleMesh, uint32& count);
+ static void GetHeightFieldSize(void* heightField, int32& rows, int32& columns);
+ static float GetHeightFieldHeight(void* heightField, float x, float z);
+ static bool ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data);
+ static void FlushRequests();
+ static void FlushRequests(void* scene);
+ static void DestroyActor(void* actor);
+ static void DestroyShape(void* shape);
+ static void DestroyJoint(void* joint);
+ static void DestroyController(void* controller);
+ static void DestroyObject(void* object);
+ static void RemoveCollider(PhysicsColliderActor* collider);
+ static void RemoveJoint(Joint* joint);
+
+public:
+ // Utilities
+ FORCE_INLINE static void SetActorFlag(void* actor, ActorFlags flag, bool value)
+ {
+ auto flags = GetActorFlags(actor);
+ flags = (ActorFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0));
+ SetActorFlags(actor, flags);
+ }
+
+ FORCE_INLINE static void SetRigidDynamicActorFlag(void* actor, RigidDynamicFlags flag, bool value)
+ {
+ auto flags = GetRigidDynamicActorFlags(actor);
+ flags = (RigidDynamicFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0));
+ SetRigidDynamicActorFlags(actor, flags);
+ }
+};
+
+DECLARE_ENUM_OPERATORS(PhysicsBackend::ActorFlags);
+DECLARE_ENUM_OPERATORS(PhysicsBackend::RigidDynamicFlags);
+DECLARE_ENUM_OPERATORS(PhysicsBackend::JointFlags);
diff --git a/Source/Engine/Physics/PhysicsScene.Queries.cpp b/Source/Engine/Physics/PhysicsScene.Queries.cpp
deleted file mode 100644
index 87fa78529..000000000
--- a/Source/Engine/Physics/PhysicsScene.Queries.cpp
+++ /dev/null
@@ -1,697 +0,0 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
-
-#include "Physics.h"
-#include "PhysicsScene.h"
-#include "Utilities.h"
-#include "CollisionData.h"
-#include "Actors/PhysicsColliderActor.h"
-#include
-#include
-
-// Temporary result buffer size
-#define HIT_BUFFER_SIZE 128
-
-template
-class DynamicHitBuffer : public PxHitCallback
-{
-private:
-
- uint32 _count;
- HitType _buffer[HIT_BUFFER_SIZE];
-
-public:
-
- DynamicHitBuffer()
- : PxHitCallback(_buffer, HIT_BUFFER_SIZE)
- , _count(0)
- {
- }
-
-public:
-
- // Computes the number of any hits in this result, blocking or touching.
- PX_INLINE PxU32 getNbAnyHits() const
- {
- return getNbTouches();
- }
-
- // Convenience iterator used to access any hits in this result, blocking or touching.
- PX_INLINE const HitType& getAnyHit(const PxU32 index) const
- {
- PX_ASSERT(index < getNbTouches() + PxU32(this->hasBlock));
- return index < getNbTouches() ? getTouches()[index] : this->block;
- }
-
- PX_INLINE PxU32 getNbTouches() const
- {
- return _count;
- }
-
- PX_INLINE const HitType* getTouches() const
- {
- return _buffer;
- }
-
- PX_INLINE const HitType& getTouch(const PxU32 index) const
- {
- PX_ASSERT(index < getNbTouches());
- return _buffer[index];
- }
-
- PX_INLINE PxU32 getMaxNbTouches() const
- {
- return HIT_BUFFER_SIZE;
- }
-
-protected:
-
- PxAgain processTouches(const HitType* buffer, PxU32 nbHits) override
- {
- nbHits = Math::Min(nbHits, HIT_BUFFER_SIZE - _count);
- for (PxU32 i = 0; i < nbHits; i++)
- {
- _buffer[_count + i] = buffer[i];
- }
- _count += nbHits;
- return true;
- }
-
- void finalizeQuery() override
- {
- if (this->hasBlock)
- {
- // Blocking hits go to hits
- processTouches(&this->block, 1);
- }
- }
-};
-
-#define SCENE_QUERY_SETUP(blockSingle) if (GetScene() == nullptr) return false; \
- const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; \
- PxQueryFilterData filterData = PxQueryFilterData(); \
- filterData.flags |= PxQueryFlag::ePREFILTER; \
- filterData.data.word0 = layerMask; \
- filterData.data.word1 = blockSingle ? 1 : 0; \
- filterData.data.word2 = hitTriggers ? 1 : 0
-
-#define SCENE_QUERY_SETUP_SWEEP_1() SCENE_QUERY_SETUP(true); \
- PxSweepBufferN<1> buffer
-
-#define SCENE_QUERY_SETUP_SWEEP() SCENE_QUERY_SETUP(false); \
- DynamicHitBuffer buffer
-
-#define SCENE_QUERY_SETUP_OVERLAP_1() SCENE_QUERY_SETUP(false); \
- PxOverlapBufferN<1> buffer
-
-#define SCENE_QUERY_SETUP_OVERLAP() SCENE_QUERY_SETUP(false); \
- DynamicHitBuffer buffer
-
-#define SCENE_QUERY_COLLECT_SINGLE() const auto& hit = buffer.getAnyHit(0); \
- hitInfo.Gather(hit)
-
-#define SCENE_QUERY_COLLECT_ALL() results.Clear(); \
- results.Resize(buffer.getNbAnyHits(), false); \
- for (int32 i = 0; i < results.Count(); i++) \
- { \
- const auto& hit = buffer.getAnyHit(i); \
- results[i].Gather(hit); \
- }
-
-#define SCENE_QUERY_COLLECT_OVERLAP() results.Clear(); \
- results.Resize(buffer.getNbTouches(), false); \
- for (int32 i = 0; i < results.Count(); i++) \
- { \
- auto& hitInfo = results[i]; \
- const auto& hit = buffer.getTouch(i); \
- hitInfo = hit.shape ? static_cast<::PhysicsColliderActor*>(hit.shape->userData) : nullptr; \
- }
-
-#define SCENE_QUERY_COLLECT_OVERLAP_COLLIDER() results.Clear(); \
- results.Resize(buffer.getNbTouches(), false); \
- for (int32 i = 0; i < results.Count(); i++) \
- { \
- auto& hitInfo = results[i]; \
- const auto& hit = buffer.getTouch(i); \
- hitInfo = hit.shape ? static_cast<::Collider*>(hit.shape->userData) : nullptr; \
- }
-
-void RayCastHit::Gather(const PxRaycastHit& hit)
-{
- Point = P2C(hit.position);
- Normal = P2C(hit.normal);
- Distance = hit.distance;
- Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr;
- FaceIndex = hit.faceIndex;
- UV.X = hit.u;
- UV.Y = hit.v;
-}
-
-void RayCastHit::Gather(const PxSweepHit& hit)
-{
- Point = P2C(hit.position);
- Normal = P2C(hit.normal);
- Distance = hit.distance;
- Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr;
- FaceIndex = hit.faceIndex;
- UV = Vector2::Zero;
-}
-
-class QueryFilter : public PxQueryFilterCallback
-{
-public:
-
- PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override
- {
- // Early out to avoid crashing
- if (!shape)
- return PxQueryHitType::eNONE;
-
- // Check mask
- const PxFilterData shapeFilter = shape->getQueryFilterData();
- if ((filterData.word0 & shapeFilter.word0) == 0)
- {
- return PxQueryHitType::eNONE;
- }
-
- // Check if skip triggers
- const bool hitTriggers = filterData.word2 != 0;
- if (!hitTriggers && shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE)
- return PxQueryHitType::eNONE;
-
- const bool blockSingle = filterData.word1 != 0;
- return blockSingle ? PxQueryHitType::eBLOCK : PxQueryHitType::eTOUCH;
- }
-
- PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override
- {
- // Not used
- return PxQueryHitType::eNONE;
- }
-};
-
-class CharacterQueryFilter : public PxQueryFilterCallback
-{
-public:
-
- PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override
- {
- // Early out to avoid crashing
- if (!shape)
- return PxQueryHitType::eNONE;
-
- // Let triggers through
- if (PxFilterObjectIsTrigger(shape->getFlags()))
- return PxQueryHitType::eNONE;
-
- // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
- const PxFilterData shapeFilter = shape->getQueryFilterData();
- if (filterData.word0 & shapeFilter.word1)
- return PxQueryHitType::eBLOCK;
-
- return PxQueryHitType::eNONE;
- }
-
- PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override
- {
- // Not used
- return PxQueryHitType::eNONE;
- }
-};
-
-class CharacterControllerFilter : public PxControllerFilterCallback
-{
-private:
-
- PxShape* getShape(const PxController& controller)
- {
- PxRigidDynamic* actor = controller.getActor();
-
- // Early out if no actor or no shapes
- if (!actor || actor->getNbShapes() < 1)
- return nullptr;
-
- // Get first shape only.
- PxShape* shape = nullptr;
- actor->getShapes(&shape, 1);
-
- return shape;
- }
-
-public:
-
- bool filter(const PxController& a, const PxController& b) override
- {
- // Early out to avoid crashing
- PxShape* shapeA = getShape(a);
- if (!shapeA)
- return false;
-
- PxShape* shapeB = getShape(b);
- if (!shapeB)
- return false;
-
- // Let triggers through
- if (PxFilterObjectIsTrigger(shapeB->getFlags()))
- return false;
-
- // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
- const PxFilterData shapeFilterA = shapeA->getQueryFilterData();
- const PxFilterData shapeFilterB = shapeB->getQueryFilterData();
- if (shapeFilterA.word0 & shapeFilterB.word1)
- return true;
-
- return false;
- }
-};
-
-PxQueryFilterCallback* PhysicsScene::GetQueryFilterCallback()
-{
- static QueryFilter Filter;
- return &Filter;
-}
-
-PxQueryFilterCallback* PhysicsScene::GetCharacterQueryFilterCallback()
-{
- static CharacterQueryFilter Filter;
- return &Filter;
-}
-
-PxControllerFilterCallback* PhysicsScene::GetCharacterControllerFilterCallback()
-{
- static CharacterControllerFilter Filter;
- return &Filter;
-}
-
-bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP(true);
- PxRaycastBuffer buffer;
-
- // Perform raycast test
- return GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP(true);
- PxRaycastBuffer buffer;
-
- // Perform raycast test
- if (!GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_SINGLE();
-
- return true;
-}
-
-bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP(false);
- DynamicHitBuffer buffer;
-
- // Perform raycast test
- if (!GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_ALL();
-
- return true;
-}
-
-bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform sweep test
- return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_SINGLE();
-
- return true;
-}
-
-bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_ALL();
-
- return true;
-}
-
-bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform sweep test
- return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_SINGLE();
-
- return true;
-}
-
-bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_ALL();
-
- return true;
-}
-
-bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform sweep test
- return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_SINGLE();
-
- return true;
-}
-
-bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_ALL();
-
- return true;
-}
-
-bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform sweep test
- return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_SINGLE();
-
- return true;
-}
-
-bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_SWEEP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform sweep test
- if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_ALL();
-
- return true;
-}
-
-bool PhysicsScene::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform overlap test
- return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP_1();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform overlap test
- return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform overlap test
- return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP_1();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform overlap test
- return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
-}
-
-bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
-
- return true;
-}
-
-bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
-
- return true;
-}
-
-bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
-
- return true;
-}
-
-bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
-
- return true;
-}
-
-bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxBoxGeometry geometry(C2P(halfExtents));
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP();
-
- return true;
-}
-
-bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center));
- const PxSphereGeometry geometry(radius);
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP();
-
- return true;
-}
-
-bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxCapsuleGeometry geometry(radius, height * 0.5f);
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP();
-
- return true;
-}
-
-bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
-{
- CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false)
-
- // Prepare data
- SCENE_QUERY_SETUP_OVERLAP();
- const PxTransform pose(C2P(center), C2P(rotation));
- const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
-
- // Perform overlap test
- if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
- return false;
-
- // Collect results
- SCENE_QUERY_COLLECT_OVERLAP();
-
- return true;
-}
diff --git a/Source/Engine/Physics/PhysicsScene.cpp b/Source/Engine/Physics/PhysicsScene.cpp
deleted file mode 100644
index 7b5520c0a..000000000
--- a/Source/Engine/Physics/PhysicsScene.cpp
+++ /dev/null
@@ -1,818 +0,0 @@
-#include "Physics.h"
-#include "PhysicsScene.h"
-#include "PhysicsSettings.h"
-#include "PhysicsStepper.h"
-#include "SimulationEventCallback.h"
-#include "Utilities.h"
-
-#include "Actors/IPhysicsActor.h"
-
-#include "Engine/Core/Log.h"
-#include "Engine/Platform/CPUInfo.h"
-#include "Engine/Profiler/ProfilerCPU.h"
-#include "Engine/Threading/Threading.h"
-#include
-
-#if WITH_VEHICLE
-#include "Actors/WheeledVehicle.h"
-#include
-#endif
-
-// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned.
-#define SCRATCH_BLOCK_SIZE (1024 * 128)
-
-PxFilterFlags FilterShader(
- PxFilterObjectAttributes attributes0, PxFilterData filterData0,
- PxFilterObjectAttributes attributes1, PxFilterData filterData1,
- PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
-{
- // Let triggers through
- if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
- {
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST;
- pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
- return PxFilterFlag::eDEFAULT;
- }
-
- // Send events for the kinematic actors but don't solve the contact
- if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1))
- {
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST;
- pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
- return PxFilterFlag::eSUPPRESS;
- }
-
- // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
- if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
- {
- pairFlags |= PxPairFlag::eSOLVE_CONTACT;
- pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;
- pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
- pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY;
- pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS;
- return PxFilterFlag::eDEFAULT;
- }
-
- // Ignore pair (no collisions nor events)
- return PxFilterFlag::eKILL;
-}
-
-enum class ActionType
-{
- Sleep,
-};
-
-struct ActionData
-{
- ActionType Type;
- PxActor* Actor;
-};
-
-#if WITH_VEHICLE
-
-static PxQueryHitType::Enum WheelRaycastPreFilter(PxFilterData filterData0, PxFilterData filterData1, const void* constantBlock, PxU32 constantBlockSize, PxHitFlags& queryFlags)
-{
- // Hardcoded id for vehicle shapes masking
- if (filterData0.word3 == filterData1.word3)
- {
- return PxQueryHitType::eNONE;
- }
-
- // Collide for pairs (A,B) where the filtermask of A contains the ID of B and vice versa
- if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
- {
- return PxQueryHitType::eBLOCK;
- }
-
- return PxQueryHitType::eNONE;
-}
-
-#endif
-
-class PhysicsScenePhysX
-{
- friend PhysicsScene;
-
-private:
- PxScene* Scene;
- PxCpuDispatcher* CpuDispatcher;
- PxControllerManager* ControllerManager;
- PxSimulationFilterShader PhysXDefaultFilterShader = PxDefaultSimulationFilterShader;
- SimulationEventCallback EventsCallback;
- CriticalSection FlushLocker;
-
- Array NewActors;
- Array DeadActors;
- Array DeadMaterials;
- Array DeadColliders;
- Array DeadJoints;
- Array Actions;
- Array DeadObjects;
-
-#if WITH_VEHICLE
- Array WheelVehiclesCache;
- Array WheelQueryResults;
- Array WheelHitResults;
- Array WheelVehiclesResultsPerWheel;
- Array WheelVehiclesResultsPerVehicle;
- PxBatchQuery* WheelRaycastBatchQuery = nullptr;
- PxVehicleDrivableSurfaceToTireFrictionPairs* WheelTireFrictions = nullptr;
- Array WheelVehicles;
-#endif
-};
-
-PhysicsScene::PhysicsScene(const String& name, const PhysicsSettings& settings)
- : PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer))
-{
-#define CHECK_INIT(value, msg) if(!value) { LOG(Error, msg); return; }
-
- mName = name;
- mPhysxImpl = New();
-
- // Create scene description
- PxSceneDesc sceneDesc(CPhysX->getTolerancesScale());
- sceneDesc.gravity = C2P(settings.DefaultGravity);
- sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVE_ACTORS;
- if (!settings.DisableCCD)
- sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
- if (settings.EnableAdaptiveForce)
- sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE;
- sceneDesc.simulationEventCallback = &mPhysxImpl->EventsCallback;
- sceneDesc.filterShader = FilterShader;
- sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity;
- if (sceneDesc.cpuDispatcher == nullptr)
- {
- mPhysxImpl->CpuDispatcher = PxDefaultCpuDispatcherCreate(Math::Clamp(Platform::GetCPUInfo().ProcessorCoreCount - 1, 1, 4));
- CHECK_INIT(mPhysxImpl->CpuDispatcher, "PxDefaultCpuDispatcherCreate failed!");
- sceneDesc.cpuDispatcher = mPhysxImpl->CpuDispatcher;
- }
- if (sceneDesc.filterShader == nullptr)
- {
- sceneDesc.filterShader = mPhysxImpl->PhysXDefaultFilterShader;
- }
-
- // Create scene
- mPhysxImpl->Scene = CPhysX->createScene(sceneDesc);
- CHECK_INIT(mPhysxImpl->Scene, "createScene failed!");
-#if WITH_PVD
- auto pvdClient = PhysicsScene->getScenePvdClient();
- if (pvdClient)
- {
- pvdClient->setScenePvdFlags(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS | PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES | PxPvdSceneFlag::eTRANSMIT_CONTACTS);
- }
- else
- {
- LOG(Info, "Missing PVD client scene.");
- }
-#endif
-
- // Init characters controller
- mPhysxImpl->ControllerManager = PxCreateControllerManager(*mPhysxImpl->Scene);
-}
-
-PhysicsScene::~PhysicsScene()
-{
-#if WITH_VEHICLE
- RELEASE_PHYSX(mPhysxImpl->WheelRaycastBatchQuery);
- RELEASE_PHYSX(mPhysxImpl->WheelTireFrictions);
- mPhysxImpl->WheelQueryResults.Resize(0);
- mPhysxImpl->WheelHitResults.Resize(0);
- mPhysxImpl->WheelVehiclesResultsPerWheel.Resize(0);
- mPhysxImpl->WheelVehiclesResultsPerVehicle.Resize(0);
-#endif
-
- RELEASE_PHYSX(mPhysxImpl->ControllerManager);
- SAFE_DELETE(mPhysxImpl->CpuDispatcher);
- SAFE_DELETE(mStepper);
- Allocator::Free(mScratchMemory);
-
- mScratchMemory = nullptr;
- mPhysxImpl->Scene->release();
-
- SAFE_DELETE(mPhysxImpl);
-}
-
-String PhysicsScene::GetName() const
-{
- return mName;
-}
-
-PxScene* PhysicsScene::GetScene()
-{
- return mPhysxImpl->Scene;
-}
-
-bool PhysicsScene::GetAutoSimulation()
-{
- return mAutoSimulation;
-}
-
-void PhysicsScene::SetAutoSimulation(bool value)
-{
- mAutoSimulation = value;
-}
-
-void PhysicsScene::SetGravity(const Vector3& value)
-{
- if(mPhysxImpl->Scene)
- {
- mPhysxImpl->Scene->setGravity(C2P(value));
- }
-}
-
-Vector3 PhysicsScene::GetGravity()
-{
- return mPhysxImpl->Scene ? P2C(mPhysxImpl->Scene->getGravity()) : Vector3::Zero;
-}
-
-bool PhysicsScene::GetEnableCCD()
-{
- return mPhysxImpl->Scene ? (mPhysxImpl->Scene->getFlags() & PxSceneFlag::eENABLE_CCD) == PxSceneFlag::eENABLE_CCD : !PhysicsSettings::Get()->DisableCCD;
-}
-
-void PhysicsScene::SetEnableCCD(const bool value)
-{
- if (mPhysxImpl->Scene)
- mPhysxImpl->Scene->setFlag(PxSceneFlag::eENABLE_CCD, value);
-}
-
-float PhysicsScene::GetBounceThresholdVelocity()
-{
- return mPhysxImpl->Scene ? mPhysxImpl->Scene->getBounceThresholdVelocity() : PhysicsSettings::Get()->BounceThresholdVelocity;
-}
-
-void PhysicsScene::SetBounceThresholdVelocity(const float value)
-{
- if (mPhysxImpl->Scene)
- mPhysxImpl->Scene->setBounceThresholdVelocity(value);
-}
-
-void PhysicsScene::Simulate(float dt)
-{
- ASSERT(IsInMainThread() && !mIsDuringSimulation);
- ASSERT(CPhysX);
- const auto& settings = *PhysicsSettings::Get();
-
- // Flush the old/new objects and the other requests before the simulation
- FlushRequests();
-
- // Clamp delta
- dt = Math::Clamp(dt, 0.0f, settings.MaxDeltaTime);
-
- // Prepare util objects
- if (mScratchMemory == nullptr)
- {
- mScratchMemory = Allocator::Allocate(SCRATCH_BLOCK_SIZE, 16);
- }
- if (mStepper == nullptr)
- {
- mStepper = New();
- }
- if (settings.EnableSubstepping)
- {
- // Use substeps
- mStepper->Setup(settings.SubstepDeltaTime, settings.MaxSubsteps);
- }
- else
- {
- // Use single step
- mStepper->Setup(dt);
- }
-
- // Start simulation (may not be fired due to too small delta time)
- mIsDuringSimulation = true;
- if (mStepper->advance(mPhysxImpl->Scene, dt, mScratchMemory, SCRATCH_BLOCK_SIZE) == false)
- return;
- mPhysxImpl->EventsCallback.Clear();
- mLastDeltaTime = dt;
-
- // TODO: move this call after rendering done
- mStepper->renderDone();
-}
-
-bool PhysicsScene::IsDuringSimulation()
-{
- return mIsDuringSimulation;
-}
-
-void PhysicsScene::CollectResults()
-{
- if (!mIsDuringSimulation)
- return;
- ASSERT(IsInMainThread());
- ASSERT(CPhysX && mStepper);
-
- {
- PROFILE_CPU_NAMED("Physics.Fetch");
-
- // Gather results (with waiting for the end)
- mStepper->wait(mPhysxImpl->Scene);
- }
-
-#if WITH_VEHICLE
- if (mPhysxImpl->WheelVehicles.HasItems())
- {
- PROFILE_CPU_NAMED("Physics.Vehicles");
-
- // Update vehicles steering
- mPhysxImpl->WheelVehiclesCache.Clear();
- mPhysxImpl->WheelVehiclesCache.EnsureCapacity(mPhysxImpl->WheelVehicles.Count());
- int32 wheelsCount = 0;
- for (auto wheelVehicle : mPhysxImpl->WheelVehicles)
- {
- if (!wheelVehicle->IsActiveInHierarchy())
- continue;
- auto drive = (PxVehicleWheels*)wheelVehicle->_drive;
- ASSERT(drive);
- mPhysxImpl->WheelVehiclesCache.Add(drive);
- wheelsCount += drive->mWheelsSimData.getNbWheels();
-
- float throttle = wheelVehicle->_throttle;
- float brake = wheelVehicle->_brake;
- if (wheelVehicle->UseReverseAsBrake)
- {
- const float invalidDirectionThreshold = 80.0f;
- const float breakThreshold = 8.0f;
- const float forwardSpeed = wheelVehicle->GetForwardSpeed();
-
- // Automatic gear change when changing driving direction
- if (Math::Abs(forwardSpeed) < invalidDirectionThreshold)
- {
- if (throttle < -ZeroTolerance && wheelVehicle->GetCurrentGear() >= 0 && wheelVehicle->GetTargetGear() >= 0)
- {
- wheelVehicle->SetCurrentGear(-1);
- }
- else if (throttle > ZeroTolerance && wheelVehicle->GetCurrentGear() <= 0 && wheelVehicle->GetTargetGear() <= 0)
- {
- wheelVehicle->SetCurrentGear(1);
- }
- }
-
- // Automatic break when changing driving direction
- if (throttle > 0.0f)
- {
- if (forwardSpeed < -invalidDirectionThreshold)
- {
- brake = 1.0f;
- }
- }
- else if (throttle < 0.0f)
- {
- if (forwardSpeed > invalidDirectionThreshold)
- {
- brake = 1.0f;
- }
- }
- else
- {
- if (forwardSpeed < breakThreshold && forwardSpeed > -breakThreshold)
- {
- brake = 1.0f;
- }
- }
-
- // Block throttle if user is changing driving direction
- if ((throttle > 0.0f && wheelVehicle->GetTargetGear() < 0) || (throttle < 0.0f && wheelVehicle->GetTargetGear() > 0))
- {
- throttle = 0.0f;
- }
-
- throttle = Math::Abs(throttle);
- }
- else
- {
- throttle = Math::Max(throttle, 0.0f);
- }
- // @formatter:off
- // Reference: PhysX SDK docs
- // TODO: expose input control smoothing data
- static constexpr PxVehiclePadSmoothingData padSmoothing =
- {
- {
- 6.0f, // rise rate eANALOG_INPUT_ACCEL
- 6.0f, // rise rate eANALOG_INPUT_BRAKE
- 12.0f, // rise rate eANALOG_INPUT_HANDBRAKE
- 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT
- 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT
- },
- {
- 10.0f, // fall rate eANALOG_INPUT_ACCEL
- 10.0f, // fall rate eANALOG_INPUT_BRAKE
- 12.0f, // fall rate eANALOG_INPUT_HANDBRAKE
- 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT
- 5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT
- }
- };
- PxVehicleKeySmoothingData keySmoothing =
- {
- {
- 3.0f, // rise rate eANALOG_INPUT_ACCEL
- 3.0f, // rise rate eANALOG_INPUT_BRAKE
- 10.0f, // rise rate eANALOG_INPUT_HANDBRAKE
- 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT
- 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT
- },
- {
- 5.0f, // fall rate eANALOG_INPUT__ACCEL
- 5.0f, // fall rate eANALOG_INPUT__BRAKE
- 10.0f, // fall rate eANALOG_INPUT__HANDBRAKE
- 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT
- 5.0f // fall rate eANALOG_INPUT_STEER_RIGHT
- }
- };
- // Reference: PhysX SDK docs
- // TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range)
- static constexpr PxF32 steerVsForwardSpeedData[] =
- {
- 0.0f, 1.0f,
- 20.0f, 0.9f,
- 65.0f, 0.8f,
- 120.0f, 0.7f,
- PX_MAX_F32, PX_MAX_F32,
- PX_MAX_F32, PX_MAX_F32,
- PX_MAX_F32, PX_MAX_F32,
- PX_MAX_F32, PX_MAX_F32,
- };
- const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
- // @formatter:on
- if (wheelVehicle->UseAnalogSteering)
- {
- switch (wheelVehicle->_driveTypeCurrent)
- {
- case WheeledVehicle::DriveTypes::Drive4W:
- {
- PxVehicleDrive4WRawInputData rawInputData;
- rawInputData.setAnalogAccel(throttle);
- rawInputData.setAnalogBrake(brake);
- rawInputData.setAnalogSteer(wheelVehicle->_steering);
- rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
- PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDrive4W*)drive);
- break;
- }
- case WheeledVehicle::DriveTypes::DriveNW:
- {
- PxVehicleDriveNWRawInputData rawInputData;
- rawInputData.setAnalogAccel(throttle);
- rawInputData.setAnalogBrake(brake);
- rawInputData.setAnalogSteer(wheelVehicle->_steering);
- rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
- PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDriveNW*)drive);
- break;
- }
- }
- }
- else
- {
- const float deadZone = 0.1f;
- switch (wheelVehicle->_driveTypeCurrent)
- {
- case WheeledVehicle::DriveTypes::Drive4W:
- {
- PxVehicleDrive4WRawInputData rawInputData;
- rawInputData.setDigitalAccel(throttle > deadZone);
- rawInputData.setDigitalBrake(brake > deadZone);
- rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
- rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
- rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
- PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDrive4W*)drive);
- break;
- }
- case WheeledVehicle::DriveTypes::DriveNW:
- {
- PxVehicleDriveNWRawInputData rawInputData;
- rawInputData.setDigitalAccel(throttle > deadZone);
- rawInputData.setDigitalBrake(brake > deadZone);
- rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
- rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
- rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
- PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDriveNW*)drive);
- break;
- }
- }
- }
- }
-
- // Update batches queries cache
- if (wheelsCount > mPhysxImpl->WheelQueryResults.Count())
- {
- if (mPhysxImpl->WheelRaycastBatchQuery)
- mPhysxImpl->WheelRaycastBatchQuery->release();
- mPhysxImpl->WheelQueryResults.Resize(wheelsCount, false);
- mPhysxImpl->WheelHitResults.Resize(wheelsCount, false);
- PxBatchQueryDesc desc(wheelsCount, 0, 0);
- desc.queryMemory.userRaycastResultBuffer = mPhysxImpl->WheelQueryResults.Get();
- desc.queryMemory.userRaycastTouchBuffer = mPhysxImpl->WheelHitResults.Get();
- desc.queryMemory.raycastTouchBufferSize = wheelsCount;
- desc.preFilterShader = WheelRaycastPreFilter;
- mPhysxImpl->WheelRaycastBatchQuery = mPhysxImpl->Scene->createBatchQuery(desc);
- }
-
- // TODO: expose vehicle tires configuration
- if (!mPhysxImpl->WheelTireFrictions)
- {
- PxVehicleDrivableSurfaceType surfaceTypes[1];
- surfaceTypes[0].mType = 0;
- const PxMaterial* surfaceMaterials[1];
- surfaceMaterials[0] = Physics::GetDefaultMaterial();
- mPhysxImpl->WheelTireFrictions = PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(1, 1);
- mPhysxImpl->WheelTireFrictions->setup(1, 1, surfaceMaterials, surfaceTypes);
- mPhysxImpl->WheelTireFrictions->setTypePairFriction(0, 0, 5.0f);
- }
-
- // Setup cache for wheel states
- mPhysxImpl->WheelVehiclesResultsPerVehicle.Resize(mPhysxImpl->WheelVehiclesCache.Count(), false);
- mPhysxImpl->WheelVehiclesResultsPerWheel.Resize(wheelsCount, false);
- wheelsCount = 0;
- for (int32 i = 0, ii = 0; i < mPhysxImpl->WheelVehicles.Count(); i++)
- {
- auto wheelVehicle = mPhysxImpl->WheelVehicles[i];
- if (!wheelVehicle->IsActiveInHierarchy())
- continue;
- auto drive = (PxVehicleWheels*)mPhysxImpl->WheelVehicles[ii]->_drive;
- auto& perVehicle = mPhysxImpl->WheelVehiclesResultsPerVehicle[ii];
- ii++;
- perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels();
- perVehicle.wheelQueryResults = mPhysxImpl->WheelVehiclesResultsPerWheel.Get() + wheelsCount;
- wheelsCount += perVehicle.nbWheelQueryResults;
- }
-
- // Update vehicles
- if (mPhysxImpl->WheelVehiclesCache.Count() != 0)
- {
- PxVehicleSuspensionRaycasts(mPhysxImpl->WheelRaycastBatchQuery, mPhysxImpl->WheelVehiclesCache.Count(), mPhysxImpl->WheelVehiclesCache.Get(), mPhysxImpl->WheelQueryResults.Count(), mPhysxImpl->WheelQueryResults.Get());
- PxVehicleUpdates(mLastDeltaTime, mPhysxImpl->Scene->getGravity(), *mPhysxImpl->WheelTireFrictions, mPhysxImpl->WheelVehiclesCache.Count(), mPhysxImpl->WheelVehiclesCache.Get(), mPhysxImpl->WheelVehiclesResultsPerVehicle.Get());
- }
-
- // Synchronize state
- for (int32 i = 0, ii = 0; i < mPhysxImpl->WheelVehicles.Count(); i++)
- {
- auto wheelVehicle = mPhysxImpl->WheelVehicles[i];
- if (!wheelVehicle->IsActiveInHierarchy())
- continue;
- auto drive = mPhysxImpl->WheelVehiclesCache[ii];
- auto& perVehicle = mPhysxImpl->WheelVehiclesResultsPerVehicle[ii];
- ii++;
-#if PHYSX_VEHICLE_DEBUG_TELEMETRY
- LOG(Info, "Vehicle[{}] Gear={}, RPM={}", ii, wheelVehicle->GetCurrentGear(), (int32)wheelVehicle->GetEngineRotationSpeed());
-#endif
-
- // Update wheels
- for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++)
- {
- auto& wheelData = wheelVehicle->_wheelsData[j];
- auto& perWheel = perVehicle.wheelQueryResults[j];
-#if PHYSX_VEHICLE_DEBUG_TELEMETRY
- LOG(Info, "Vehicle[{}] Wheel[{}] longitudinalSlip={}, lateralSlip={}, suspSpringForce={}", ii, j, Utilities::RoundTo2DecimalPlaces(perWheel.longitudinalSlip), Utilities::RoundTo2DecimalPlaces(perWheel.lateralSlip), (int32)perWheel.suspSpringForce);
-#endif
-
- auto& state = wheelData.State;
- state.IsInAir = perWheel.isInAir;
- state.TireContactCollider = perWheel.tireContactShape ? static_cast(perWheel.tireContactShape->userData) : nullptr;
- state.TireContactPoint = P2C(perWheel.tireContactPoint);
- state.TireContactNormal = P2C(perWheel.tireContactNormal);
- state.TireFriction = perWheel.tireFriction;
- state.SteerAngle = RadiansToDegrees * perWheel.steerAngle;
- state.RotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j);
- state.SuspensionOffset = perWheel.suspJounce;
-#if USE_EDITOR
- state.SuspensionTraceStart = P2C(perWheel.suspLineStart);
- state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength);
-#endif
-
- if (!wheelData.Collider)
- continue;
- auto shape = wheelData.Collider->GetPxShape();
-
- // Update wheel collider transformation
- auto localPose = shape->getLocalPose();
- Transform t = wheelData.Collider->GetLocalTransform();
- t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation;
- t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter();
- wheelData.Collider->SetLocalTransform(t);
- }
- }
- }
-#endif
-
- {
- PROFILE_CPU_NAMED("Physics.FlushActiveTransforms");
-
- // Gather change info
- PxU32 activeActorsCount;
- PxActor** activeActors = mPhysxImpl->Scene->getActiveActors(activeActorsCount);
- if (activeActorsCount > 0)
- {
- // Update changed transformations
- // TODO: use jobs system if amount if huge
- for (uint32 i = 0; i < activeActorsCount; i++)
- {
- const auto pxActor = (PxRigidActor*)*activeActors++;
- auto actor = dynamic_cast((Actor*)pxActor->userData);
- ASSERT(actor);
- actor->OnActiveTransformChanged(pxActor->getGlobalPose());
- }
- }
- }
-
- {
- PROFILE_CPU_NAMED("Physics.SendEvents");
-
- mPhysxImpl->EventsCallback.CollectResults();
- mPhysxImpl->EventsCallback.SendTriggerEvents();
- mPhysxImpl->EventsCallback.SendCollisionEvents();
- mPhysxImpl->EventsCallback.SendJointEvents();
- }
-
- // End
- mIsDuringSimulation = false;
-}
-
-void PhysicsScene::FlushRequests()
-{
- ASSERT(!IsDuringSimulation());
- ASSERT(CPhysX);
-
- PROFILE_CPU();
-
- mPhysxImpl->FlushLocker.Lock();
-
- // Note: this does not handle case when actor is removed and added to the scene at the same time
-
- if (mPhysxImpl->NewActors.HasItems())
- {
- GetScene()->addActors(mPhysxImpl->NewActors.Get(), mPhysxImpl->NewActors.Count());
- mPhysxImpl->NewActors.Clear();
- }
-
- for (int32 i = 0; i < mPhysxImpl->Actions.Count(); i++)
- {
- const auto action = mPhysxImpl->Actions[i];
- switch (action.Type)
- {
- case ActionType::Sleep:
- static_cast(action.Actor)->putToSleep();
- break;
- }
- }
- mPhysxImpl->Actions.Clear();
-
- if (mPhysxImpl->DeadActors.HasItems())
- {
- GetScene()->removeActors(mPhysxImpl->DeadActors.Get(), mPhysxImpl->DeadActors.Count(), true);
- for (int32 i = 0; i < mPhysxImpl->DeadActors.Count(); i++)
- {
- mPhysxImpl->DeadActors[i]->release();
- }
- mPhysxImpl->DeadActors.Clear();
- }
-
- if (mPhysxImpl->DeadColliders.HasItems())
- {
- for (int32 i = 0; i < mPhysxImpl->DeadColliders.Count(); i++)
- {
- mPhysxImpl->EventsCallback.OnColliderRemoved(mPhysxImpl->DeadColliders[i]);
- }
- mPhysxImpl->DeadColliders.Clear();
- }
-
- if (mPhysxImpl->DeadJoints.HasItems())
- {
- for (int32 i = 0; i < mPhysxImpl->DeadJoints.Count(); i++)
- {
- mPhysxImpl->EventsCallback.OnJointRemoved(mPhysxImpl->DeadJoints[i]);
- }
- mPhysxImpl->DeadJoints.Clear();
- }
-
- for (int32 i = 0; i < mPhysxImpl->DeadMaterials.Count(); i++)
- {
- auto material = mPhysxImpl->DeadMaterials[i];
-
- // Unlink ref to flax object
- material->userData = nullptr;
-
- material->release();
- }
- mPhysxImpl->DeadMaterials.Clear();
-
- for (int32 i = 0; i < mPhysxImpl->DeadObjects.Count(); i++)
- {
- mPhysxImpl->DeadObjects[i]->release();
- }
- mPhysxImpl->DeadObjects.Clear();
-
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::RemoveMaterial(PxMaterial* material)
-{
- ASSERT(material);
-
- mPhysxImpl->FlushLocker.Lock();
- mPhysxImpl->DeadMaterials.Add(material);
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::RemoveObject(PxBase* obj)
-{
- ASSERT(obj);
-
- mPhysxImpl->FlushLocker.Lock();
- mPhysxImpl->DeadObjects.Add(obj);
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::AddActor(PxActor* actor)
-{
- ASSERT(actor);
-
- mPhysxImpl->FlushLocker.Lock();
- if (IsInMainThread())
- {
- GetScene()->addActor(*actor);
- }
- else
- {
- mPhysxImpl->NewActors.Add(actor);
- }
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::AddActor(PxRigidDynamic* actor, bool putToSleep)
-{
- ASSERT(actor);
-
- mPhysxImpl->FlushLocker.Lock();
- if (IsInMainThread())
- {
- GetScene()->addActor(*actor);
- if (putToSleep)
- actor->putToSleep();
- }
- else
- {
- mPhysxImpl->NewActors.Add(actor);
- if (putToSleep)
- mPhysxImpl->Actions.Add({ ActionType::Sleep, actor });
- }
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::UnlinkActor(PxActor* actor)
-{
- ASSERT(IsInMainThread())
- ASSERT(actor);
-
- GetScene()->removeActor(*actor);
-}
-
-void PhysicsScene::RemoveActor(PxActor* actor)
-{
- ASSERT(actor);
-
- // Unlink ref to flax object
- actor->userData = nullptr;
-
- mPhysxImpl->FlushLocker.Lock();
- mPhysxImpl->DeadActors.Add(actor);
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::RemoveCollider(PhysicsColliderActor* collider)
-{
- ASSERT(collider);
-
- mPhysxImpl->FlushLocker.Lock();
- mPhysxImpl->DeadColliders.Add(collider);
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-void PhysicsScene::RemoveJoint(Joint* joint)
-{
- ASSERT(joint);
-
- mPhysxImpl->FlushLocker.Lock();
- mPhysxImpl->DeadJoints.Add(joint);
- mPhysxImpl->FlushLocker.Unlock();
-}
-
-PxControllerManager* PhysicsScene::GetControllerManager()
-{
- return mPhysxImpl->ControllerManager;
-}
-
-#if WITH_VEHICLE
-void PhysicsScene::AddWheeledVehicle(WheeledVehicle* vehicle)
-{
- mPhysxImpl->WheelVehicles.Add(vehicle);
-}
-
-void PhysicsScene::RemoveWheeledVehicle(WheeledVehicle* vehicle)
-{
- mPhysxImpl->WheelVehicles.Remove(vehicle);
-}
-#endif
diff --git a/Source/Engine/Physics/PhysicsScene.h b/Source/Engine/Physics/PhysicsScene.h
index 1c95e7ece..db17c7ac1 100644
--- a/Source/Engine/Physics/PhysicsScene.h
+++ b/Source/Engine/Physics/PhysicsScene.h
@@ -1,33 +1,36 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
#pragma once
-#include "Engine/Scripting/ScriptingObject.h"
-#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Core/Math/Vector3.h"
#include "Engine/Core/Math/Quaternion.h"
+#include "Engine/Scripting/ScriptingObject.h"
#include "Types.h"
+struct ActionData;
+struct RayCastHit;
+class PhysicsSettings;
+class PhysicsColliderActor;
+class Joint;
+class Collider;
+class CollisionData;
#if WITH_VEHICLE
class WheeledVehicle;
#endif
-struct ActionData;
-struct RayCastHit;
-class FixedStepper;
-class PhysicsSettings;
-class PhysicsColliderActor;
-class PhysicsScenePhysX;
-class Joint;
-class Collider;
-class CollisionData;
-
///
-/// Isolated physics scene.
+/// Physical simulation scene.
///
-API_CLASS(NoSpawn) class FLAXENGINE_API PhysicsScene : public PersistentScriptingObject
+API_CLASS() class FLAXENGINE_API PhysicsScene : public ScriptingObject
{
- DECLARE_SCRIPTING_TYPE_NO_SPAWN(PhysicsScene);
+ DECLARE_SCRIPTING_TYPE(PhysicsScene);
+private:
+ String _name;
+ bool _autoSimulation = true;
+ bool _isDuringSimulation = false;
+ void* _scene = nullptr;
- explicit PhysicsScene(const String& name, const PhysicsSettings& settings);
+public:
~PhysicsScene();
///
@@ -35,30 +38,34 @@ API_CLASS(NoSpawn) class FLAXENGINE_API PhysicsScene : public PersistentScriptin
///
API_PROPERTY() String GetName() const;
-public:
- String ToString() const override
+ ///
+ /// Gets the native physics system scene object.
+ ///
+ FORCE_INLINE void* GetPhysicsScene() const
{
- return GetName();
+ return _scene;
}
- PxScene* GetScene();
+ ///
+ /// Gets the automatic simulation feature that perform physics simulation after on fixed update by auto, otherwise user should do it.
+ ///
+ API_PROPERTY() bool GetAutoSimulation() const;
///
- /// The automatic simulation feature. True if perform physics simulation after on fixed update by auto, otherwise user should do it.
+ /// Sets the automatic simulation feature that perform physics simulation after on fixed update by auto, otherwise user should do it.
///
- API_PROPERTY() bool GetAutoSimulation();
API_PROPERTY() void SetAutoSimulation(bool value);
- ///
- /// Sets the current gravity force.
- ///
- API_PROPERTY() void SetGravity(const Vector3& value);
-
///
/// Gets the current gravity force.
///
API_PROPERTY() Vector3 GetGravity();
+ ///
+ /// Sets the current gravity force.
+ ///
+ API_PROPERTY() void SetGravity(const Vector3& value);
+
///
/// Gets the CCD feature enable flag.
///
@@ -67,7 +74,7 @@ public:
///
/// Sets the CCD feature enable flag.
///
- API_PROPERTY() void SetEnableCCD(const bool value);
+ API_PROPERTY() void SetEnableCCD(bool value);
///
/// Gets the minimum relative velocity required for an object to bounce.
@@ -77,7 +84,16 @@ public:
///
/// Sets the minimum relative velocity required for an object to bounce.
///
- API_PROPERTY() void SetBounceThresholdVelocity(const float value);
+ API_PROPERTY() void SetBounceThresholdVelocity(float value);
+
+public:
+ ///
+ /// Initializes the scene.
+ ///
+ /// The name.
+ /// The physics settings.
+ /// True if failed, otherwise false.
+ bool Init(const StringView& name, const PhysicsSettings& settings);
///
/// Called during main engine loop to start physic simulation. Use CollectResults after.
@@ -86,90 +102,16 @@ public:
API_FUNCTION() void Simulate(float dt);
///
- /// Checks if physical simulation is running
+ /// Checks if physical simulation is running.
///
- /// True if simulation is active, otherwise false
- API_PROPERTY() bool IsDuringSimulation();
+ API_PROPERTY() bool IsDuringSimulation() const;
///
/// Called to collect physic simulation results and apply them as well as fire collision events.
///
API_FUNCTION() void CollectResults();
- ///
- /// Flushes the async requests to add/remove actors, remove materials, etc..
- ///
- void FlushRequests();
-
- ///
- /// Removes the material (using safe async request).
- ///
- /// The material.
- void RemoveMaterial(PxMaterial* material);
-
- ///
- /// Removes the physX object via calling release() on it (using safe async request).
- ///
- /// The obj.
- void RemoveObject(PxBase* obj);
-
- ///
- /// Adds the actor (using safe async request).
- ///
- /// The actor.
- void AddActor(PxActor* actor);
-
- ///
- /// Adds the actor (using safe async request).
- ///
- /// The actor.
- /// If set to true will put actor to sleep after spawning.
- void AddActor(PxRigidDynamic* actor, bool putToSleep = false);
-
- ///
- /// Removes the actor (using safe async request).
- ///
- /// The actor.
- void RemoveActor(PxActor* actor);
-
- ///
- /// Removes the actor from the underlying physics scene without destroying it.
- ///
- void UnlinkActor(PxActor* actor);
-
- ///
- /// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object).
- ///
- /// The collider.
- void RemoveCollider(PhysicsColliderActor* collider);
-
- ///
- /// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object).
- ///
- /// The joint.
- void RemoveJoint(Joint* joint);
-
- ///
- /// Gets PhysX characters controller manager object
- ///
- PxControllerManager* GetControllerManager();
-
public:
- ///
- /// Gets the default query filter callback used for the scene queries.
- ///
- PxQueryFilterCallback* GetQueryFilterCallback();
-
- ///
- /// Gets the default query filter callback used for the character controller collisions detection.
- ///
- PxQueryFilterCallback* GetCharacterQueryFilterCallback();
-
- ///
- /// Gets the default controller filter callback used for the character controller collisions detection.
- ///
- static PxControllerFilterCallback* GetCharacterControllerFilterCallback();
-
///
/// Performs a raycast against objects in the scene.
///
@@ -514,20 +456,4 @@ public:
/// If set to true triggers will be hit, otherwise will skip them.
/// True if convex mesh overlaps any matching object, otherwise false.
API_FUNCTION() bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array& results, const Quaternion& rotation = Quaternion::Identity, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
-
-public:
-#if WITH_VEHICLE
- void AddWheeledVehicle(WheeledVehicle* vehicle);
- void RemoveWheeledVehicle(WheeledVehicle* vehicle);
-#endif
-
-private:
- String mName;
- bool mAutoSimulation = true;
- void* mScratchMemory = nullptr;
- FixedStepper* mStepper = nullptr;
- float mLastDeltaTime = 0.0f;
- bool mIsDuringSimulation = false;
-
- PhysicsScenePhysX* mPhysxImpl;
};
diff --git a/Source/Engine/Physics/Types.h b/Source/Engine/Physics/Types.h
index 614322488..f7abc9062 100644
--- a/Source/Engine/Physics/Types.h
+++ b/Source/Engine/Physics/Types.h
@@ -4,54 +4,15 @@
#include "Engine/Core/Enums.h"
#include "Engine/Core/Config.h"
+#include "Engine/Core/Math/Vector2.h"
+#include "Engine/Core/Math/Vector3.h"
+#include "Engine/Scripting/ScriptingType.h"
-namespace physx
-{
- class PxScene;
- class PxConvexMesh;
- class PxTriangleMesh;
- class PxCooking;
- class PxPhysics;
- class PxVec3;
- class PxVec4;
- class PxTransform;
- class PxJoint;
- class PxMat44;
- class PxCpuDispatcher;
- class PxGpuDispatcher;
- class PxSimulationEventCallback;
- struct PxActiveTransform;
- class PxActor;
- class PxRigidActor;
- class PxRigidDynamic;
- class PxRigidStatic;
- class PxFoundation;
- class PxShape;
- class PxGeometry;
- class PxGeometryHolder;
- class PxProfileZoneManager;
- class PxMaterial;
- class PxPvd;
- class PxBase;
- class PxTolerancesScale;
- class PxBaseTask;
- class PxControllerManager;
- class PxController;
- class PxCapsuleController;
- class PxQueryFilterCallback;
- class PxControllerFilterCallback;
- class PxHeightField;
- struct PxFilterData;
- struct PxRaycastHit;
- struct PxSweepHit;
-}
-
-using namespace physx;
-
-#define RELEASE_PHYSX(x) if(x) { (x)->release(); x = nullptr; }
-
-// Global pointer to PhysX SDK object
-extern PxPhysics* CPhysX;
+class PhysicsColliderActor;
+class PhysicsScene;
+class Joint;
+class Collider;
+class CollisionData;
///
/// Enumeration that determines the way in which two material properties will be combined to yield a friction or restitution coefficient for a collision.
@@ -167,3 +128,147 @@ API_ENUM(Attributes="Flags") enum class RigidbodyConstraints
};
DECLARE_ENUM_OPERATORS(RigidbodyConstraints);
+
+///
+/// Raycast hit result data.
+///
+API_STRUCT() struct RayCastHit
+{
+ DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
+
+ ///
+ /// The collider that was hit.
+ ///
+ API_FIELD() PhysicsColliderActor* Collider = nullptr;
+
+ ///
+ /// The normal of the surface the ray hit.
+ ///
+ API_FIELD() Vector3 Normal;
+
+ ///
+ /// The distance from the ray's origin to the hit location.
+ ///
+ API_FIELD() float Distance;
+
+ ///
+ /// The point in the world space where ray hit the collider.
+ ///
+ API_FIELD() Vector3 Point;
+
+ ///
+ /// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
+ ///
+ ///
+ API_FIELD() uint32 FaceIndex;
+
+ ///
+ /// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
+ ///
+ API_FIELD() Vector2 UV;
+};
+
+///
+/// Physics collision shape variant for different shapes such as box, sphere, capsule.
+///
+struct FLAXENGINE_API CollisionShape
+{
+ enum class Types : uint8
+ {
+ Sphere,
+ Box,
+ Capsule,
+ ConvexMesh,
+ TriangleMesh,
+ HeightField,
+ };
+
+ Types Type;
+
+ union
+ {
+ struct
+ {
+ float Radius;
+ } Sphere;
+
+ struct
+ {
+ float HalfExtents[3];
+ } Box;
+
+ struct
+ {
+ float Radius;
+ float HalfHeight;
+ } Capsule;
+
+ struct
+ {
+ void* ConvexMesh;
+ float Scale[3];
+ } ConvexMesh;
+
+ struct
+ {
+ void* TriangleMesh;
+ float Scale[3];
+ } TriangleMesh;
+
+ struct
+ {
+ void* HeightField;
+ float HeightScale;
+ float RowScale;
+ float ColumnScale;
+ } HeightField;
+ };
+
+ void SetSphere(float radius)
+ {
+ Type = Types::Sphere;
+ Sphere.Radius = radius;
+ }
+
+ void SetBox(float halfExtents[3])
+ {
+ Type = Types::Box;
+ Box.HalfExtents[0] = halfExtents[0];
+ Box.HalfExtents[1] = halfExtents[1];
+ Box.HalfExtents[2] = halfExtents[2];
+ }
+
+ void SetCapsule(float radius, float halfHeight)
+ {
+ Type = Types::Capsule;
+ Capsule.Radius = radius;
+ Capsule.HalfHeight = halfHeight;
+ }
+
+ void SetConvexMesh(void* contextMesh, float scale[3])
+ {
+ Type = Types::ConvexMesh;
+ ConvexMesh.ConvexMesh = contextMesh;
+ ConvexMesh.Scale[0] = scale[0];
+ ConvexMesh.Scale[1] = scale[1];
+ ConvexMesh.Scale[2] = scale[2];
+ }
+
+ void SetTriangleMesh(void* triangleMesh, float scale[3])
+ {
+ Type = Types::TriangleMesh;
+ TriangleMesh.TriangleMesh = triangleMesh;
+ TriangleMesh.Scale[0] = scale[0];
+ TriangleMesh.Scale[1] = scale[1];
+ TriangleMesh.Scale[2] = scale[2];
+ }
+
+ void SetHeightField(void* heightField, float heightScale, float rowScale, float columnScale)
+ {
+ Type = Types::HeightField;
+ HeightField.HeightField = heightField;
+ HeightField.HeightScale = heightScale;
+ HeightField.RowScale = rowScale;
+ HeightField.ColumnScale = columnScale;
+ }
+};
diff --git a/Source/Engine/Physics/Utilities.h b/Source/Engine/Physics/Utilities.h
deleted file mode 100644
index fd38a55cd..000000000
--- a/Source/Engine/Physics/Utilities.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
-
-#pragma once
-
-#include "Engine/Core/Math/Vector2.h"
-#include "Engine/Core/Math/Vector3.h"
-#include "Engine/Core/Math/Vector4.h"
-#include "Engine/Core/Math/Quaternion.h"
-#include "Engine/Core/Math/BoundingBox.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-inline PxVec2& C2P(const Vector2& v)
-{
- return *(PxVec2*)&v;
-}
-
-inline PxVec3& C2P(const Vector3& v)
-{
- return *(PxVec3*)&v;
-}
-
-inline PxVec4& C2P(const Vector4& v)
-{
- return *(PxVec4*)&v;
-}
-
-inline PxQuat& C2P(const Quaternion& v)
-{
- return *(PxQuat*)&v;
-}
-
-inline PxBounds3& C2P(const BoundingBox& v)
-{
- return *(PxBounds3*)&v;
-}
-
-inline Vector2& P2C(const PxVec2& v)
-{
- return *(Vector2*)&v;
-}
-
-inline Vector3& P2C(const PxVec3& v)
-{
- return *(Vector3*)&v;
-}
-
-inline Vector4& P2C(const PxVec4& v)
-{
- return *(Vector4*)&v;
-}
-
-inline Quaternion& P2C(const PxQuat& v)
-{
- return *(Quaternion*)&v;
-}
-
-inline BoundingBox& P2C(const PxBounds3& v)
-{
- return *(BoundingBox*)&v;
-}
-
-inline Vector3 P2C(const PxExtendedVec3& v)
-{
-#ifdef PX_BIG_WORLDS
- return Vector3((float)v.x, (float)v.y, (float)v.z);
-#else
- return *(Vector3*)&v;
-#endif
-}
-
-inline float M2ToCm2(float v)
-{
- return v * (100.0f * 100.0f);
-}
-
-inline float Cm2ToM2(float v)
-{
- return v / (100.0f * 100.0f);
-}
-
-inline float KgPerM3ToKgPerCm3(float v)
-{
- return v / (100.0f * 100.0f * 100.0f);
-}
-
-inline float RpmToRadPerS(float v)
-{
- return v * (PI / 30.0f);
-}
-
-inline float RadPerSToRpm(float v)
-{
- return v * (30.0f / PI);
-}
-
-extern PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled);
diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp
index c09e20609..b7ec73a36 100644
--- a/Source/Engine/Terrain/Terrain.cpp
+++ b/Source/Engine/Terrain/Terrain.cpp
@@ -7,13 +7,12 @@
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Physics/Physics.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/PhysicalMaterial.h"
+#include "Engine/Physics/PhysicsBackend.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Profiler/ProfilerCPU.h"
-#include
Terrain::Terrain(const SpawnParams& params)
: PhysicsColliderActor(params)
@@ -69,13 +68,11 @@ void Terrain::UpdateLayerBits()
if (_patches.IsEmpty())
return;
- PxFilterData filterData;
-
// Own layer ID
- filterData.word0 = GetLayerMask();
+ const uint32 mask0 = GetLayerMask();
// Own layer mask
- filterData.word1 = Physics::LayerMasks[GetLayer()];
+ const uint32 mask1 = Physics::LayerMasks[GetLayer()];
// Update the shapes layer bits
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
@@ -83,8 +80,7 @@ void Terrain::UpdateLayerBits()
const auto patch = _patches[pathIndex];
if (patch->HasCollision())
{
- patch->_physicsShape->setSimulationFilterData(filterData);
- patch->_physicsShape->setQueryFilterData(filterData);
+ PhysicsBackend::SetShapeFilterMask(patch->_physicsShape, mask0, mask1);
}
}
}
@@ -170,7 +166,6 @@ bool Terrain::RayCast(const Vector3& origin, const Vector3& direction, RayCastHi
bool result = false;
RayCastHit tmpHit;
const Ray ray(origin, direction);
-
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
{
const auto patch = _patches[pathIndex];
@@ -184,7 +179,6 @@ bool Terrain::RayCast(const Vector3& origin, const Vector3& direction, RayCastHi
result = true;
}
}
-
return result;
}
@@ -192,13 +186,12 @@ void Terrain::ClosestPoint(const Vector3& position, Vector3& result) const
{
float minDistance = MAX_float;
Vector3 tmp;
-
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
{
const auto patch = _patches[pathIndex];
if (patch->HasCollision())
{
- patch->ClosestPoint(position, &tmp);
+ patch->ClosestPoint(position, tmp);
const auto distance = Vector3::DistanceSquared(position, tmp);
if (distance < minDistance)
{
@@ -237,22 +230,13 @@ void Terrain::OnPhysicalMaterialChanged()
if (_patches.IsEmpty())
return;
- PxMaterial* material = Physics::GetDefaultMaterial();
- if (PhysicalMaterial)
- {
- if (!PhysicalMaterial->WaitForLoaded())
- {
- material = ((::PhysicalMaterial*)PhysicalMaterial->Instance)->GetPhysXMaterial();
- }
- }
-
// Update the shapes material
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
{
const auto patch = _patches[pathIndex];
if (patch->HasCollision())
{
- patch->_physicsShape->setMaterials(&material, 1);
+ PhysicsBackend::SetShapeMaterial(patch->_physicsShape, PhysicalMaterial.Get());
}
}
}
@@ -819,13 +803,12 @@ void Terrain::OnActiveInTreeChanged()
Actor::OnActiveInTreeChanged();
// Update physics
- const PxShapeFlags shapeFlags = GetShapeFlags(false, IsActiveInHierarchy());
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
{
const auto patch = _patches[pathIndex];
if (patch->HasCollision())
{
- patch->_physicsShape->setFlags(shapeFlags);
+ PhysicsBackend::SetShapeState(patch->_physicsShape, IsActiveInHierarchy(), false);
}
}
}
diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp
index 82b379d39..aed8b7a60 100644
--- a/Source/Engine/Terrain/TerrainPatch.cpp
+++ b/Source/Engine/Terrain/TerrainPatch.cpp
@@ -5,11 +5,12 @@
#include "Engine/Serialization/Serialization.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Profiler/ProfilerCPU.h"
-#include "Engine/Physics/Utilities.h"
#include "Engine/Physics/Physics.h"
#include "Engine/Physics/PhysicsScene.h"
-#include "Engine/Physics/PhysicalMaterial.h"
+#include "Engine/Physics/PhysicsBackend.h"
+#include "Engine/Physics/CollisionCooking.h"
#include "Engine/Level/Scene/Scene.h"
+#include "Engine/Level/Level.h"
#include "Engine/Graphics/Async/GPUTask.h"
#include "Engine/Threading/Threading.h"
#if TERRAIN_EDITING
@@ -19,6 +20,7 @@
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Graphics/Textures/TextureData.h"
+#include "Engine/Serialization/MemoryWriteStream.h"
#if USE_EDITOR
#include "Editor/Editor.h"
#include "Engine/ContentImporters/AssetsImportingManager.h"
@@ -27,21 +29,10 @@
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
#endif
-#include "Engine/Physics/CollisionCooking.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/Assets/RawDataAsset.h"
-#include "Engine/Level/Level.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#define TERRAIN_PATCH_COLLISION_QUANTIZATION ((PxReal)0x7fff)
+#define TERRAIN_PATCH_COLLISION_QUANTIZATION ((float)0x7fff)
struct TerrainCollisionDataHeader
{
@@ -128,8 +119,7 @@ void TerrainPatch::UpdateTransform()
if (_physicsActor)
{
const Transform& terrainTransform = _terrain->_transform;
- const PxTransform trans(C2P(terrainTransform.LocalToWorld(_offset)), C2P(terrainTransform.Orientation));
- _physicsActor->setGlobalPose(trans);
+ PhysicsBackend::SetRigidActorPose(_physicsActor, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation);
}
// Update chunks cache
@@ -565,10 +555,10 @@ bool CookCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* ini
const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1;
const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
const int32 heightFieldLength = heightFieldSize * heightFieldSize;
- GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PxHeightFieldSample);
- PxHeightFieldSample sample;
- Platform::MemoryClear(&sample, sizeof(PxHeightFieldSample));
- Platform::MemoryClear(heightFieldData, sizeof(PxHeightFieldSample) * heightFieldLength);
+ GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PhysicsBackend::HeightFieldSample);
+ PhysicsBackend::HeightFieldSample sample;
+ Platform::MemoryClear(&sample, sizeof(PhysicsBackend::HeightFieldSample));
+ Platform::MemoryClear(heightFieldData, sizeof(PhysicsBackend::HeightFieldSample) * heightFieldLength);
// Setup terrain collision information
auto& mip = initData->Mips[collisionLOD];
@@ -598,47 +588,38 @@ bool CookCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* ini
const int32 heightmapZ = chunkStartZ + z;
const int32 dstIndex = (heightmapX * heightFieldSize) + heightmapZ;
- sample.height = PxI16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight);
- sample.materialIndex0 = sample.materialIndex1 = isHole ? PxHeightFieldMaterial::eHOLE : 0;
+ sample.Height = int16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight);
+ sample.MaterialIndex0 = sample.MaterialIndex1 = isHole ? (uint8)PhysicsBackend::HeightFieldMaterial::Hole : 0;
heightFieldData[dstIndex] = sample;
}
}
}
}
- PxHeightFieldDesc heightFieldDesc;
- heightFieldDesc.format = PxHeightFieldFormat::eS16_TM;
- heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES;
- heightFieldDesc.nbColumns = heightFieldSize;
- heightFieldDesc.nbRows = heightFieldSize;
- heightFieldDesc.samples.data = heightFieldData;
- heightFieldDesc.samples.stride = sizeof(PxHeightFieldSample);
// Cook height field
- PxDefaultMemoryOutputStream outputStream;
- if (CollisionCooking::CookHeightField(heightFieldDesc, outputStream))
+ MemoryWriteStream outputStream;
+ if (CollisionCooking::CookHeightField(heightFieldSize, heightFieldSize, heightFieldData, outputStream))
{
return true;
}
// Write results
- collisionData->Resize(sizeof(TerrainCollisionDataHeader) + outputStream.getSize(), false);
+ collisionData->Resize(sizeof(TerrainCollisionDataHeader) + outputStream.GetPosition(), false);
const auto header = (TerrainCollisionDataHeader*)collisionData->Get();
header->LOD = collisionLOD;
header->ScaleXZ = (float)info.HeightmapSize / heightFieldSize;
- Platform::MemoryCopy(collisionData->Get() + sizeof(TerrainCollisionDataHeader), outputStream.getData(), outputStream.getSize());
+ Platform::MemoryCopy(collisionData->Get() + sizeof(TerrainCollisionDataHeader), outputStream.GetHandle(), outputStream.GetPosition());
return false;
#else
-
- LOG(Warning, "Collision cooking is disabled.");
- return true;
-
+ LOG(Warning, "Collision cooking is disabled.");
+ return true;
#endif
}
-bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 collisionLod, const Int2& modifiedOffset, const Int2& modifiedSize, PxHeightField* heightField)
+bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 collisionLod, const Int2& modifiedOffset, const Int2& modifiedSize, void* heightField)
{
PROFILE_CPU_NAMED("Terrain.ModifyCollision");
@@ -658,10 +639,10 @@ bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* i
// Allocate data
const int32 heightFieldDataLength = samplesSize.X * samplesSize.Y;
- GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, info.HeightmapLength, PxHeightFieldSample);
- PxHeightFieldSample sample;
- Platform::MemoryClear(&sample, sizeof(PxHeightFieldSample));
- Platform::MemoryClear(heightFieldData, sizeof(PxHeightFieldSample) * heightFieldDataLength);
+ GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, info.HeightmapLength, PhysicsBackend::HeightFieldSample);
+ PhysicsBackend::HeightFieldSample sample;
+ Platform::MemoryClear(&sample, sizeof(PhysicsBackend::HeightFieldSample));
+ Platform::MemoryClear(heightFieldData, sizeof(PhysicsBackend::HeightFieldSample) * heightFieldDataLength);
// Setup terrain collision information
auto& mip = initData->Mips[collisionLOD];
@@ -711,24 +692,17 @@ bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* i
const int32 dstIndex = (heightmapLocalX * samplesSize.Y) + heightmapLocalZ;
- sample.height = PxI16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight);
- sample.materialIndex0 = sample.materialIndex1 = isHole ? PxHeightFieldMaterial::eHOLE : 0;
+ sample.Height = int16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight);
+ sample.MaterialIndex0 = sample.MaterialIndex1 = isHole ? (uint8)PhysicsBackend::HeightFieldMaterial::Hole : 0;
heightFieldData[dstIndex] = sample;
}
}
}
}
- PxHeightFieldDesc heightFieldDesc;
- heightFieldDesc.format = PxHeightFieldFormat::eS16_TM;
- heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES;
- heightFieldDesc.nbColumns = samplesSize.Y;
- heightFieldDesc.nbRows = samplesSize.X;
- heightFieldDesc.samples.data = heightFieldData;
- heightFieldDesc.samples.stride = sizeof(PxHeightFieldSample);
// Update height field range
- if (!heightField->modifySamples(samplesOffset.Y, samplesOffset.X, heightFieldDesc, true))
+ if (PhysicsBackend::ModifyHeightField(heightField, samplesOffset.Y, samplesOffset.X, samplesSize.Y, samplesSize.X, heightFieldData))
{
LOG(Warning, "Height Field collision modification failed.");
return true;
@@ -1958,7 +1932,7 @@ bool TerrainPatch::UpdateCollision()
_collisionVertices.Resize(0);
// Recreate height field
- _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField);
+ PhysicsBackend::DestroyObject(_physicsHeightField);
_physicsHeightField = nullptr;
if (CreateHeightField())
{
@@ -1981,42 +1955,26 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
{
if (_physicsShape == nullptr)
return false;
-
- // Prepare data
- PxTransform trans = _physicsActor->getGlobalPose();
- trans.p = trans.transform(_physicsShape->getLocalPose().p);
- const PxHitFlags hitFlags = (PxHitFlags)0;
-
- // Perform raycast test
- PxRaycastHit hit;
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0)
- {
- resultHitDistance = hit.distance;
- return true;
- }
-
- return false;
+ Vector3 shapePos;
+ Quaternion shapeRot;
+ PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot);
+ return PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, resultHitDistance, maxDistance);
}
bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance) const
{
if (_physicsShape == nullptr)
return false;
-
- // Prepare data
- PxTransform trans = _physicsActor->getGlobalPose();
- trans.p = trans.transform(_physicsShape->getLocalPose().p);
- const PxHitFlags hitFlags = PxHitFlag::eNORMAL;
-
- // Perform raycast test
- PxRaycastHit hit;
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0)
+ Vector3 shapePos;
+ Quaternion shapeRot;
+ PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot);
+ RayCastHit hit;
+ if (PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hit, maxDistance))
{
- resultHitDistance = hit.distance;
- resultHitNormal = P2C(hit.normal);
+ resultHitDistance = hit.Distance;
+ resultHitNormal = hit.Normal;
return true;
}
-
return false;
}
@@ -2024,19 +1982,17 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
{
if (_physicsShape == nullptr)
return false;
-
- // Prepare data
- PxTransform trans = _physicsActor->getGlobalPose();
- trans.p = trans.transform(_physicsShape->getLocalPose().p);
- const PxHitFlags hitFlags = (PxHitFlags)0;
+ Vector3 shapePos;
+ Quaternion shapeRot;
+ PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot);
// Perform raycast test
- PxRaycastHit hit;
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0)
+ float hitDistance;
+ if (PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hitDistance, maxDistance))
{
// Find hit chunk
resultChunk = nullptr;
- const auto hitPoint = origin + direction * hit.distance;
+ const auto hitPoint = origin + direction * hitDistance;
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
{
const auto box = Chunks[chunkIndex]._bounds;
@@ -2052,7 +2008,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
if (resultChunk == nullptr)
return false;
- resultHitDistance = hit.distance;
+ resultHitDistance = hitDistance;
return true;
}
@@ -2063,44 +2019,28 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, RayC
{
if (_physicsShape == nullptr)
return false;
-
- // Prepare data
- PxTransform trans = _physicsActor->getGlobalPose();
- trans.p = trans.transform(_physicsShape->getLocalPose().p);
- const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV;
- PxRaycastHit hit;
-
- // Perform raycast test
- if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0)
- return false;
-
- // Gather results
- hitInfo.Gather(hit);
- return true;
+ Vector3 shapePos;
+ Quaternion shapeRot;
+ PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot);
+ return PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hitInfo, maxDistance);
}
-void TerrainPatch::ClosestPoint(const Vector3& position, Vector3* result) const
+void TerrainPatch::ClosestPoint(const Vector3& position, Vector3& result) const
{
if (_physicsShape == nullptr)
+ {
+ result = Vector3::Maximum;
return;
-
- // Prepare data
- PxTransform trans = _physicsActor->getGlobalPose();
- trans.p = trans.transform(_physicsShape->getLocalPose().p);
- PxVec3 closestPoint;
-
- // Compute distance between a point and a geometry object
- const float distanceSqr = PxGeometryQuery::pointDistance(C2P(position), _physicsShape->getGeometry().any(), trans, &closestPoint);
+ }
+ Vector3 shapePos;
+ Quaternion shapeRot;
+ PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot);
+ Vector3 closestPoint;
+ const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_physicsShape, shapePos, shapeRot, position, &closestPoint);
if (distanceSqr > 0.0f)
- {
- // Use calculated point
- *result = P2C(closestPoint);
- }
+ result = closestPoint;
else
- {
- // Fallback to the input location
- *result = position;
- }
+ result = position;
}
#if USE_EDITOR
@@ -2130,7 +2070,7 @@ void TerrainPatch::UpdatePostManualDeserialization()
_collisionVertices.Resize(0);
// Recreate height field
- _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField);
+ PhysicsBackend::DestroyObject(_physicsHeightField);
_physicsHeightField = nullptr;
if (CreateHeightField())
{
@@ -2152,45 +2092,27 @@ void TerrainPatch::UpdatePostManualDeserialization()
void TerrainPatch::CreateCollision()
{
ASSERT(!HasCollision());
-
if (CreateHeightField())
return;
ASSERT(_physicsHeightField);
// Create geometry
const Transform terrainTransform = _terrain->_transform;
- PxHeightFieldGeometry geometry;
- geometry.heightField = _physicsHeightField;
- geometry.rowScale = Math::Max(Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE);
- geometry.heightScale = Math::Max(Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION, PX_MIN_HEIGHTFIELD_Y_SCALE);
- geometry.columnScale = Math::Max(Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE);
-
- // Prepare
- const PxShapeFlags shapeFlags = GetShapeFlags(false, _terrain->IsActiveInHierarchy());
- PxMaterial* material = Physics::GetDefaultMaterial();
- if (_terrain->PhysicalMaterial)
- {
- if (!_terrain->PhysicalMaterial->WaitForLoaded())
- {
- material = ((::PhysicalMaterial*)_terrain->PhysicalMaterial->Instance)->GetPhysXMaterial();
- }
- }
+ CollisionShape shape;
+ const float rowScale = Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ;
+ const float heightScale = Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION;
+ const float columnScale = Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ;
+ shape.SetHeightField(_physicsHeightField, heightScale, rowScale, columnScale);
// Create shape
- _physicsShape = CPhysX->createShape(geometry, *material, true, shapeFlags);
- ASSERT(_physicsShape);
- _physicsShape->userData = _terrain;
- _physicsShape->setLocalPose(PxTransform(0, _yOffset * terrainTransform.Scale.Y, 0));
+ _physicsShape = PhysicsBackend::CreateShape(_terrain, shape, _terrain->PhysicalMaterial.Get(), _terrain->IsActiveInHierarchy(), false);
+ PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity);
// Create static actor
- const PxTransform trans(C2P(terrainTransform.LocalToWorld(_offset)), C2P(terrainTransform.Orientation));
- _physicsActor = CPhysX->createRigidStatic(trans);
- ASSERT(_physicsActor);
- _physicsActor->userData = _terrain;
-#if WITH_PVD
- _physicsActor->setActorFlag(PxActorFlag::eVISUALIZATION, true);
-#endif
- _physicsActor->attachShape(*_physicsShape);
+ _physicsActor = PhysicsBackend::CreateRigidStaticActor(nullptr, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation);
+ PhysicsBackend::AttachShape(_physicsShape, _physicsActor);
+ void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _physicsActor);
}
bool TerrainPatch::CreateHeightField()
@@ -2208,9 +2130,7 @@ bool TerrainPatch::CreateHeightField()
const auto collisionHeader = (TerrainCollisionDataHeader*)_heightfield->Data.Get();
_collisionScaleXZ = collisionHeader->ScaleXZ * TERRAIN_UNITS_PER_VERTEX;
-
- PxDefaultMemoryInputData heightFieldData(_heightfield->Data.Get() + sizeof(TerrainCollisionDataHeader), _heightfield->Data.Count() - sizeof(TerrainCollisionDataHeader));
- _physicsHeightField = CPhysX->createHeightField(heightFieldData);
+ _physicsHeightField = PhysicsBackend::CreateHeightField(_heightfield->Data.Get() + sizeof(TerrainCollisionDataHeader), _heightfield->Data.Count() - sizeof(TerrainCollisionDataHeader));
if (_physicsHeightField == nullptr)
{
LOG(Error, "Failed to create terrain collision height field.");
@@ -2226,15 +2146,15 @@ void TerrainPatch::UpdateCollisionScale() const
// Create geometry
const Transform terrainTransform = _terrain->_transform;
- PxHeightFieldGeometry geometry;
- geometry.heightField = _physicsHeightField;
- geometry.rowScale = Math::Max(Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE);
- geometry.heightScale = Math::Max(Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION, PX_MIN_HEIGHTFIELD_Y_SCALE);
- geometry.columnScale = Math::Max(Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE);
+ CollisionShape geometry;
+ const float rowScale = Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ;
+ const float heightScale = Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION;
+ const float columnScale = Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ;
+ geometry.SetHeightField(_physicsHeightField, heightScale, rowScale, columnScale);
// Update shape
- _physicsShape->setGeometry(geometry);
- _physicsShape->setLocalPose(PxTransform(0, _yOffset * terrainTransform.Scale.Y, 0));
+ PhysicsBackend::SetShapeGeometry(_physicsShape, geometry);
+ PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity);
}
void TerrainPatch::DestroyCollision()
@@ -2242,10 +2162,12 @@ void TerrainPatch::DestroyCollision()
ScopeLock lock(_collisionLocker);
ASSERT(HasCollision());
- _terrain->GetPhysicsScene()->RemoveCollider(_terrain);
- _terrain->GetPhysicsScene()->RemoveActor(_physicsActor);
- _terrain->GetPhysicsScene()->RemoveObject(_physicsShape);
- _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField);
+ void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::RemoveCollider(_terrain);
+ PhysicsBackend::RemoveSceneActor(scene, _physicsActor);
+ PhysicsBackend::DestroyActor(_physicsActor);
+ PhysicsBackend::DestroyShape(_physicsShape);
+ PhysicsBackend::DestroyObject(_physicsHeightField);
_physicsActor = nullptr;
_physicsShape = nullptr;
@@ -2265,17 +2187,17 @@ void TerrainPatch::CacheDebugLines()
{
ASSERT(_debugLines.IsEmpty() && _physicsHeightField);
- const uint32 rows = _physicsHeightField->getNbRows();
- const uint32 cols = _physicsHeightField->getNbColumns();
+ int32 rows, cols;
+ PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
_debugLines.Resize((rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2);
Vector3* data = _debugLines.Get();
-#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), _physicsHeightField->getHeight((PxReal)(row + (x)), (PxReal)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y)))
+#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)(row + (x)), (float)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y)))
- for (uint32 row = 0; row < rows - 1; row++)
+ for (int32 row = 0; row < rows - 1; row++)
{
- for (uint32 col = 0; col < cols - 1; col++)
+ for (int32 col = 0; col < cols - 1; col++)
{
GET_VERTEX(0, 0);
GET_VERTEX(0, 1);
@@ -2293,9 +2215,9 @@ void TerrainPatch::CacheDebugLines()
}
}
- for (uint32 row = 0; row < rows - 1; row++)
+ for (int32 row = 0; row < rows - 1; row++)
{
- const uint32 col = cols - 1;
+ const int32 col = cols - 1;
GET_VERTEX(0, 0);
GET_VERTEX(1, 0);
@@ -2303,9 +2225,9 @@ void TerrainPatch::CacheDebugLines()
*data++ = v10;
}
- for (uint32 col = 0; col < cols - 1; col++)
+ for (int32 col = 0; col < cols - 1; col++)
{
- const uint32 row = rows - 1;
+ const int32 row = rows - 1;
GET_VERTEX(0, 0);
GET_VERTEX(0, 1);
@@ -2352,22 +2274,22 @@ const Array& TerrainPatch::GetCollisionTriangles()
if (!_physicsShape || _collisionTriangles.HasItems())
return _collisionTriangles;
- const uint32 rows = _physicsHeightField->getNbRows();
- const uint32 cols = _physicsHeightField->getNbColumns();
+ int32 rows, cols;
+ PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
_collisionTriangles.Resize((rows - 1) * (cols - 1) * 6);
Vector3* data = _collisionTriangles.Get();
-#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), _physicsHeightField->getHeight((PxReal)(row + (x)), (PxReal)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y)
+#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)(row + (x)), (float)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y)
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
const Transform terrainTransform = _terrain->_transform;
Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
- for (uint32 row = 0; row < rows - 1; row++)
+ for (int32 row = 0; row < rows - 1; row++)
{
- for (uint32 col = 0; col < cols - 1; col++)
+ for (int32 col = 0; col < cols - 1; col++)
{
GET_VERTEX(0, 0);
GET_VERTEX(0, 1);
@@ -2394,9 +2316,8 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, ArraygetNbRows();
- const int32 cols = _physicsHeightField->getNbColumns();
+ int32 rows, cols;
+ PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
int32 startRow = Math::FloorToInt(min.X / size * rows);
int32 startCol = Math::FloorToInt(min.Z / size * cols);
int32 endRow = Math::CeilToInt(max.X / size * rows);
@@ -2495,8 +2416,8 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array<
if (!_physicsShape)
return;
- const uint32 rows = _physicsHeightField->getNbRows();
- const uint32 cols = _physicsHeightField->getNbColumns();
+ int32 rows, cols;
+ PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
// Cache pre-transformed collision heightfield vertices locations
if (_collisionVertices.IsEmpty())
@@ -2513,11 +2434,11 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array<
const int32 vertexCount = rows * cols;
_collisionVertices.Resize(vertexCount);
Vector3* vb = _collisionVertices.Get();
- for (uint32 row = 0; row < rows; row++)
+ for (int32 row = 0; row < rows; row++)
{
- for (uint32 col = 0; col < cols; col++)
+ for (int32 col = 0; col < cols; col++)
{
- Vector3 v((float)row, _physicsHeightField->getHeight((PxReal)row, (PxReal)col) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)col);
+ Vector3 v((float)row, PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)row, (float)col) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)col);
Vector3::Transform(v, world, v);
*vb++ = v;
}
@@ -2532,9 +2453,9 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array<
const int32 indexCount = (rows - 1) * (cols - 1) * 6;
indexBuffer.Resize(indexCount);
int32* ib = indexBuffer.Get();
- for (uint32 row = 0; row < rows - 1; row++)
+ for (int32 row = 0; row < rows - 1; row++)
{
- for (uint32 col = 0; col < cols - 1; col++)
+ for (int32 col = 0; col < cols - 1; col++)
{
#define GET_INDEX(x, y) *ib++ = (col + (y)) + (row + (x)) * cols
@@ -2612,6 +2533,7 @@ void TerrainPatch::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
void TerrainPatch::OnPhysicsSceneChanged(PhysicsScene* previous)
{
- previous->UnlinkActor(_physicsActor);
- _terrain->GetPhysicsScene()->AddActor(_physicsActor);
+ PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _physicsActor);
+ void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene();
+ PhysicsBackend::AddSceneActor(scene, _physicsActor);
}
diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h
index 7e27220ca..b77cc191a 100644
--- a/Source/Engine/Terrain/TerrainPatch.h
+++ b/Source/Engine/Terrain/TerrainPatch.h
@@ -6,7 +6,6 @@
#include "TerrainChunk.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Core/Math/Int2.h"
-#include "Engine/Physics/Types.h"
#include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Content/Assets/RawDataAsset.h"
@@ -38,9 +37,9 @@ private:
BoundingBox _bounds;
Vector3 _offset;
AssetReference _heightfield;
- PxShape* _physicsShape;
- PxRigidStatic* _physicsActor;
- PxHeightField* _physicsHeightField;
+ void* _physicsShape;
+ void* _physicsActor;
+ void* _physicsHeightField;
CriticalSection _collisionLocker;
float _collisionScaleXZ;
#if TERRAIN_UPDATING
@@ -331,7 +330,7 @@ public:
///
/// The position to find the closest point to it.
/// The result point on the collider that is closest to the specified location.
- void ClosestPoint(const Vector3& position, Vector3* result) const;
+ void ClosestPoint(const Vector3& position, Vector3& result) const;
#if USE_EDITOR
@@ -373,7 +372,6 @@ private:
///
/// Determines whether this patch has created collision representation.
///
- /// true if this patch has collider; otherwise, false.
FORCE_INLINE bool HasCollision() const
{
return _physicsShape != nullptr;
diff --git a/Source/ThirdParty/PhysX/PhysX.Build.cs b/Source/ThirdParty/PhysX/PhysX.Build.cs
index 888893f59..34522dd81 100644
--- a/Source/ThirdParty/PhysX/PhysX.Build.cs
+++ b/Source/ThirdParty/PhysX/PhysX.Build.cs
@@ -48,6 +48,8 @@ public class PhysX : DepsModule
if (useVehicle)
options.PublicDefinitions.Add("WITH_VEHICLE");
+ options.PublicDefinitions.Add("COMPILE_WITH_PHYSX");
+
string archPostFix = string.Empty;
switch (options.Platform.Target)
{