@@ -5,6 +5,7 @@
|
||||
#if COMPILE_WITH_ASSETS_IMPORTER
|
||||
|
||||
#include "AssetsImportingManager.h"
|
||||
#include "Engine/Physics/CollisionData.h"
|
||||
|
||||
CreateAssetResult CreateCollisionData::Create(CreateAssetContext& context)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -970,10 +970,10 @@ public:
|
||||
/// <summary>
|
||||
/// Get the physics world the controller is part of.
|
||||
/// </summary>
|
||||
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:
|
||||
|
||||
|
||||
@@ -2,36 +2,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxRigidActor;
|
||||
class PxTransform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A base interface for all physical actors types/owners that can responds on transformation changed event.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API IPhysicsActor
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="IPhysicsActor"/> class.
|
||||
/// </summary>
|
||||
virtual ~IPhysicsActor() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rigid actor (PhysX object) may be null.
|
||||
/// Gets the native physics backend object.
|
||||
/// </summary>
|
||||
/// <returns>PhysX rigid actor or null if not using</returns>
|
||||
virtual physx::PxRigidActor* GetRigidActor() = 0;
|
||||
virtual void* GetPhysicsActor() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event is called internally by the Physics service and should not be used by the others.
|
||||
/// </remarks>
|
||||
/// <param name="transform">The current transformation.</param>
|
||||
virtual void OnActiveTransformChanged(const physx::PxTransform& transform) = 0;
|
||||
virtual void OnActiveTransformChanged() = 0;
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/PxActor.h>
|
||||
#include <ThirdParty/PhysX/PxRigidActor.h>
|
||||
#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<PxRigidActor>())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include "Engine/Physics/Types.h"
|
||||
#include "IPhysicsActor.h"
|
||||
|
||||
class PhysicsScene;
|
||||
|
||||
/// <summary>
|
||||
/// A base class for all physical actors.
|
||||
/// </summary>
|
||||
@@ -22,12 +20,6 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the native PhysX actor object.
|
||||
/// </summary>
|
||||
/// <returns>The PhysX actor.</returns>
|
||||
virtual PxActor* GetPhysXActor() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box.
|
||||
/// </summary>
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxRigidBodyExt.h>
|
||||
#include <ThirdParty/PhysX/PxRigidActor.h>
|
||||
#include <ThirdParty/PhysX/PxRigidDynamic.h>
|
||||
#include <ThirdParty/PhysX/PxPhysics.h>
|
||||
|
||||
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<PxRigidDynamicLockFlag::Enum>(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<float, InlinedAllocation<32>> 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<PxForceMode::Enum>(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<PxForceMode::Enum>(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<PxForceMode::Enum>(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<PxActorFlags>(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<PxRigidDynamicLockFlag::Enum>(_constraints));
|
||||
|
||||
// Find colliders to attach
|
||||
for (int32 i = 0; i < Children.Count(); i++)
|
||||
{
|
||||
auto collider = dynamic_cast<Collider*>(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<Collider*>(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);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Engine/Physics/Collisions.h"
|
||||
|
||||
class PhysicsColliderActor;
|
||||
class Collider;
|
||||
|
||||
/// <summary>
|
||||
/// 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:
|
||||
/// </summary>
|
||||
API_FUNCTION() void UpdateMass();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the native PhysX rigid actor object.
|
||||
/// </summary>
|
||||
/// <returns>The PhysX dynamic rigid actor.</returns>
|
||||
FORCE_INLINE PxRigidDynamic* GetPhysXRigidActor() const
|
||||
{
|
||||
return _actor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a force (or impulse) defined in the world space to the rigidbody at its center of mass.
|
||||
/// </summary>
|
||||
@@ -547,11 +539,6 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
/// Creates the physics actor.
|
||||
/// </summary>
|
||||
void CreateActor();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the rigidbody scale dependent properties like mass (may be modified when actor transformation changes).
|
||||
/// </summary>
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/vehicle/PxVehicleSDK.h>
|
||||
#include <ThirdParty/PhysX/vehicle/PxVehicleNoDrive.h>
|
||||
#include <ThirdParty/PhysX/vehicle/PxVehicleDrive4W.h>
|
||||
#include <ThirdParty/PhysX/vehicle/PxVehicleDriveNW.h>
|
||||
#include <ThirdParty/PhysX/vehicle/PxVehicleUtilSetup.h>
|
||||
#include <ThirdParty/PhysX/PxFiltering.h>
|
||||
#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<Wheel*, FixedAllocation<PX_MAX_NB_WHEELS>> 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<PxShape*, InlinedAllocation<8>> 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<Collider>(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
|
||||
|
||||
|
||||
@@ -6,17 +6,14 @@
|
||||
#include "Engine/Physics/Colliders/Collider.h"
|
||||
#include "Engine/Scripting/ScriptingObjectReference.h"
|
||||
|
||||
class PhysicsScene;
|
||||
|
||||
/// <summary>
|
||||
/// Representation of the car vehicle that uses wheels. Built on top of the RigidBody with collider representing its chassis shape and wheels.
|
||||
/// </summary>
|
||||
/// <seealso cref="RigidBody" />
|
||||
API_CLASS() class FLAXENGINE_API WheeledVehicle : public RigidBody
|
||||
{
|
||||
friend PhysicsScene;
|
||||
friend class PhysicsBackend;
|
||||
DECLARE_SCENE_OBJECT(WheeledVehicle);
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle driving mode types.
|
||||
@@ -319,7 +316,7 @@ private:
|
||||
WheelState State;
|
||||
};
|
||||
|
||||
void* _drive = nullptr;
|
||||
void* _vehicle = nullptr;
|
||||
DriveTypes _driveType = DriveTypes::Drive4W, _driveTypeCurrent;
|
||||
Array<WheelData, FixedAllocation<20>> _wheelsData;
|
||||
float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f;
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "BoxCollider.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "CapsuleCollider.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/PxRigidActor.h>
|
||||
#include <ThirdParty/PhysX/PxRigidDynamic.h>
|
||||
#include <ThirdParty/PhysX/characterkinematic/PxController.h>
|
||||
#include <ThirdParty/PhysX/characterkinematic/PxControllerManager.h>
|
||||
#include <ThirdParty/PhysX/characterkinematic//PxCapsuleController.h>
|
||||
|
||||
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<PxControllerNonWalkableMode::Enum>(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<PxControllerNonWalkableMode::Enum>(_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();
|
||||
|
||||
@@ -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:
|
||||
/// <summary>
|
||||
@@ -181,11 +180,6 @@ public:
|
||||
/// <returns>The collision flags. It can be used to trigger various character animations.</returns>
|
||||
API_FUNCTION() CollisionFlags Move(const Vector3& displacement);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the native PhysX rigid actor object.
|
||||
/// </summary>
|
||||
PxRigidDynamic* GetPhysXRigidActor() const;
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/geometry/PxGeometryQuery.h>
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
#include <ThirdParty/PhysX/PxPhysics.h>
|
||||
#include <ThirdParty/PhysX/PxFiltering.h>
|
||||
#include <ThirdParty/PhysX/PxRigidDynamic.h>
|
||||
#include <ThirdParty/PhysX/PxRigidStatic.h>
|
||||
|
||||
Collider::Collider(const SpawnParams& params)
|
||||
: PhysicsColliderActor(params)
|
||||
@@ -31,7 +24,7 @@ Collider::Collider(const SpawnParams& params)
|
||||
Material.Changed.Bind<Collider, &Collider::OnMaterialChanged>(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<PxRigidDynamic>())
|
||||
return static_cast<RigidBody*>(actor->userData);
|
||||
return dynamic_cast<RigidBody*>(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<RigidBody*>(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<PxRigidDynamic>())
|
||||
static_cast<RigidBody*>(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<PxRigidDynamic>())
|
||||
static_cast<RigidBody*>(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<RigidBody*>(GetParent());
|
||||
rigidBody = dynamic_cast<RigidBody*>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collider shape PhysX object.
|
||||
/// Gets the native physics backend object.
|
||||
/// </summary>
|
||||
PxShape* GetPxShape() const;
|
||||
void* GetPhysicsShape() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the 'IsTrigger' flag.
|
||||
@@ -121,9 +121,9 @@ public:
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="position">The position to find the closest point to it.</param>
|
||||
/// <param name="point">The position to find the closest point to it.</param>
|
||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a point is inside the collider.
|
||||
@@ -171,7 +171,7 @@ protected:
|
||||
/// <summary>
|
||||
/// Updates the shape actor collisions/queries layer mask bits.
|
||||
/// </summary>
|
||||
virtual void UpdateLayerBits();
|
||||
void UpdateLayerBits();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bounding box of the shape.
|
||||
@@ -181,8 +181,8 @@ protected:
|
||||
/// <summary>
|
||||
/// Gets the collider shape geometry.
|
||||
/// </summary>
|
||||
/// <param name="geometry">The output geometry.</param>
|
||||
virtual void GetGeometry(PxGeometryHolder& geometry) = 0;
|
||||
/// <param name="collision">The output collision shape.</param>
|
||||
virtual void GetGeometry(CollisionShape& collision) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the collider shape.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -45,5 +45,5 @@ protected:
|
||||
void DrawPhysicsDebug(RenderView& view) override;
|
||||
#endif
|
||||
void UpdateBounds() override;
|
||||
void GetGeometry(PxGeometryHolder& geometry) override;
|
||||
void GetGeometry(CollisionShape& collision) override;
|
||||
};
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "SphereCollider.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <PxShape.h>
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -54,5 +54,5 @@ protected:
|
||||
void DrawPhysicsDebug(RenderView& view) override;
|
||||
#endif
|
||||
void UpdateBounds() override;
|
||||
void GetGeometry(PxGeometryHolder& geometry) override;
|
||||
void GetGeometry(CollisionShape& collision) override;
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/PxPhysics.h>
|
||||
#include <ThirdParty/PhysX/extensions/PxDefaultStreams.h>
|
||||
#endif
|
||||
#include <ThirdParty/PhysX/geometry/PxTriangleMesh.h>
|
||||
|
||||
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<int32> 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));
|
||||
}
|
||||
|
||||
@@ -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<Vector3> _vertexBuffer;
|
||||
Array<int32> _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;
|
||||
};
|
||||
|
||||
@@ -8,96 +8,6 @@
|
||||
#include "Engine/Graphics/Models/MeshBase.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Physics.h"
|
||||
#include <ThirdParty/PhysX/cooking/PxCooking.h>
|
||||
#include <ThirdParty/PhysX/extensions/PxDefaultStreams.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
/// 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:
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
static bool CookTriangleMesh(CookingInput& input, BytesContainer& output);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="cols">The heightfield columns count.</param>
|
||||
/// <param name="rows">The heightfield rows count.</param>
|
||||
/// <param name="data">The heightfield data.</param>
|
||||
/// <param name="stream">The user stream to output the cooked data.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
static bool CookHeightField(int32 cols, int32 rows, const PhysicsBackend::HeightFieldSample* data, WriteStream& stream);
|
||||
|
||||
/// <summary>
|
||||
/// Cooks the collision from the model and prepares the data for the <see cref="CollisionData"/> format.
|
||||
/// </summary>
|
||||
@@ -73,14 +80,6 @@ public:
|
||||
/// <param name="outputData">The output data container.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
static bool CookCollision(const Argument& arg, CollisionData::SerializedOptions& outputOptions, BytesContainer& outputData);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="desc">The heightfield descriptor to read the HF from.</param>
|
||||
/// <param name="stream">The user stream to output the cooked data.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
static bool CookHeightField(const physx::PxHeightFieldDesc& desc, physx::PxOutputStream& stream);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxDefaultStreams.h>
|
||||
#include <ThirdParty/PhysX/geometry/PxTriangleMesh.h>
|
||||
#include <ThirdParty/PhysX/geometry/PxConvexMesh.h>
|
||||
#include <ThirdParty/PhysX/PxPhysics.h>
|
||||
|
||||
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<Vector3>& vertexBuffer, Array<int32>&
|
||||
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();
|
||||
|
||||
@@ -10,12 +10,6 @@ class ModelBase;
|
||||
class ModelData;
|
||||
class MeshBase;
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxConvexMesh;
|
||||
class PxTriangleMesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="CollisionData"/> storage data type.
|
||||
/// </summary>
|
||||
@@ -165,8 +159,8 @@ public:
|
||||
private:
|
||||
|
||||
CollisionDataOptions _options;
|
||||
physx::PxConvexMesh* _convexMesh;
|
||||
physx::PxTriangleMesh* _triangleMesh;
|
||||
void* _convexMesh;
|
||||
void* _triangleMesh;
|
||||
|
||||
public:
|
||||
|
||||
@@ -181,7 +175,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the convex mesh object (valid only if asset is loaded and has cooked convex data).
|
||||
/// </summary>
|
||||
FORCE_INLINE physx::PxConvexMesh* GetConvex() const
|
||||
FORCE_INLINE void* GetConvex() const
|
||||
{
|
||||
return _convexMesh;
|
||||
}
|
||||
@@ -189,7 +183,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the triangle mesh object (valid only if asset is loaded and has cooked triangle data).
|
||||
/// </summary>
|
||||
FORCE_INLINE physx::PxTriangleMesh* GetTriangle() const
|
||||
FORCE_INLINE void* GetTriangle() const
|
||||
{
|
||||
return _triangleMesh;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a contact point data for the collision location.
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxD6Joint.h>
|
||||
#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<int32>(axis)] = value;
|
||||
|
||||
if (_joint)
|
||||
{
|
||||
auto joint = static_cast<PxD6Joint*>(_joint);
|
||||
joint->setMotion(static_cast<PxD6Axis::Enum>(axis), static_cast<PxD6Motion::Enum>(value));
|
||||
}
|
||||
PhysicsBackend::SetD6JointMotion(_joint, axis, value);
|
||||
}
|
||||
|
||||
void D6Joint::SetDrive(const D6JointDriveType index, const D6JointDrive& value)
|
||||
{
|
||||
if (value == GetDrive(index))
|
||||
return;
|
||||
|
||||
_drive[static_cast<int32>(index)] = value;
|
||||
|
||||
if (_joint)
|
||||
{
|
||||
auto joint = static_cast<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());
|
||||
joint->setDrive(static_cast<PxD6Drive::Enum>(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<PxD6Joint*>(_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<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());
|
||||
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<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());
|
||||
joint->setSwingLimit(limit);
|
||||
}
|
||||
PhysicsBackend::SetD6JointLimitSwing(_joint, value);
|
||||
}
|
||||
|
||||
Vector3 D6Joint::GetDrivePosition() const
|
||||
{
|
||||
return _joint ? P2C(static_cast<PxD6Joint*>(_joint)->getDrivePosition().p) : Vector3::Zero;
|
||||
return _joint ? PhysicsBackend::GetD6JointDrivePosition(_joint) : Vector3::Zero;
|
||||
}
|
||||
|
||||
void D6Joint::SetDrivePosition(const Vector3& value)
|
||||
{
|
||||
if (_joint)
|
||||
{
|
||||
auto joint = static_cast<PxD6Joint*>(_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<PxD6Joint*>(_joint)->getDrivePosition().q) : Quaternion::Identity;
|
||||
return _joint ? PhysicsBackend::GetD6JointDriveRotation(_joint) : Quaternion::Identity;
|
||||
}
|
||||
|
||||
void D6Joint::SetDriveRotation(const Quaternion& value)
|
||||
{
|
||||
if (_joint)
|
||||
{
|
||||
auto joint = static_cast<PxD6Joint*>(_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<PxD6Joint*>(_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<PxD6Joint*>(_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<PxD6Joint*>(_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<PxD6Joint*>(_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<PxD6Joint*>(_joint)->getTwistAngle() : 0.0f;
|
||||
return _joint ? PhysicsBackend::GetD6JointTwist(_joint) : 0.0f;
|
||||
}
|
||||
|
||||
float D6Joint::GetCurrentSwingYAngle() const
|
||||
float D6Joint::GetCurrentSwingY() const
|
||||
{
|
||||
return _joint ? static_cast<PxD6Joint*>(_joint)->getSwingYAngle() : 0.0f;
|
||||
return _joint ? PhysicsBackend::GetD6JointSwingY(_joint) : 0.0f;
|
||||
}
|
||||
|
||||
float D6Joint::GetCurrentSwingZAngle() const
|
||||
float D6Joint::GetCurrentSwingZ() const
|
||||
{
|
||||
return _joint ? static_cast<PxD6Joint*>(_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<int32>(D6JointAxis::MAX); i++)
|
||||
{
|
||||
joint->setMotion(static_cast<PxD6Axis::Enum>(i), static_cast<PxD6Motion::Enum>(_motion[i]));
|
||||
}
|
||||
|
||||
PhysicsBackend::SetD6JointMotion(joint, (D6JointAxis)i, _motion[i]);
|
||||
for (int32 i = 0; i < static_cast<int32>(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<PxD6Drive::Enum>(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;
|
||||
}
|
||||
|
||||
@@ -303,19 +303,19 @@ public:
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the twist angle of the joint.
|
||||
/// Gets the twist angle of the joint (in the range (-2*Pi, 2*Pi]).
|
||||
/// </summary>
|
||||
API_PROPERTY() float GetCurrentTwist() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current swing angle of the joint from the Y axis.
|
||||
/// </summary>
|
||||
API_PROPERTY() float GetCurrentSwingYAngle() const;
|
||||
API_PROPERTY() float GetCurrentSwingY() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current swing angle of the joint from the Z axis.
|
||||
/// </summary>
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxDistanceJoint.h>
|
||||
|
||||
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<PxDistanceJoint*>(_joint)->setDistanceJointFlags(static_cast<PxDistanceJointFlag::Enum>(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<PxDistanceJoint*>(_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<PxDistanceJoint*>(_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<PxDistanceJoint*>(_joint)->setTolerance(value);
|
||||
}
|
||||
PhysicsBackend::SetDistanceJointTolerance(_joint, value);
|
||||
}
|
||||
|
||||
void DistanceJoint::SetSpringParameters(const SpringParameters& value)
|
||||
{
|
||||
if (value == _spring)
|
||||
return;
|
||||
|
||||
_spring = value;
|
||||
|
||||
if (_joint)
|
||||
{
|
||||
static_cast<PxDistanceJoint*>(_joint)->setStiffness(value.Stiffness);
|
||||
static_cast<PxDistanceJoint*>(_joint)->setDamping(value.Damping);
|
||||
}
|
||||
PhysicsBackend::SetDistanceJointSpring(_joint, value);
|
||||
}
|
||||
|
||||
float DistanceJoint::GetCurrentDistance() const
|
||||
{
|
||||
return _joint ? static_cast<PxDistanceJoint*>(_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<PxDistanceJointFlag::Enum>(_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;
|
||||
}
|
||||
|
||||
@@ -157,5 +157,5 @@ public:
|
||||
protected:
|
||||
|
||||
// [Joint]
|
||||
PxJoint* CreateJoint(JointData& data) override;
|
||||
void* CreateJoint(const PhysicsJointDesc& desc) override;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "FixedJoint.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <ThirdParty/PhysX/extensions/PxFixedJoint.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ public:
|
||||
protected:
|
||||
|
||||
// [Joint]
|
||||
PxJoint* CreateJoint(JointData& data) override;
|
||||
void* CreateJoint(const PhysicsJointDesc& desc) override;
|
||||
};
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "HingeJoint.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <ThirdParty/PhysX/extensions/PxRevoluteJoint.h>
|
||||
#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<PxRevoluteJoint*>(_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<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());
|
||||
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<PxRevoluteJoint*>(_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<PxRevoluteJoint*>(_joint)->getAngle() : 0.0f;
|
||||
return _joint ? PhysicsBackend::GetHingeJointAngle(_joint) : 0.0f;
|
||||
}
|
||||
|
||||
float HingeJoint::GetCurrentVelocity() const
|
||||
{
|
||||
return _joint ? static_cast<PxRevoluteJoint*>(_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<PxRevoluteJointFlag::Enum>(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;
|
||||
}
|
||||
|
||||
@@ -165,5 +165,5 @@ public:
|
||||
protected:
|
||||
|
||||
// [Joint]
|
||||
PxJoint* CreateJoint(JointData& data) override;
|
||||
void* CreateJoint(const PhysicsJointDesc& desc) override;
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxJoint.h>
|
||||
|
||||
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<IPhysicsActor*>(GetParent());
|
||||
auto target = dynamic_cast<IPhysicsActor*>(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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the native PhysX joint object.
|
||||
/// Gets the native physics backend object.
|
||||
/// </summary>
|
||||
FORCE_INLINE PxJoint* GetPhysXJoint() const
|
||||
{
|
||||
return _joint;
|
||||
}
|
||||
void* GetPhysicsImpl() const;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
#include "SliderJoint.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include "Engine/Physics/Physics.h"
|
||||
#include <ThirdParty/PhysX/extensions/PxPrismaticJoint.h>
|
||||
#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<PxPrismaticJoint*>(_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<PxPrismaticJoint*>(_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<PxPrismaticJoint*>(_joint)->getPosition() : 0.0f;
|
||||
return _joint ? PhysicsBackend::GetSliderJointPosition(_joint) : 0.0f;
|
||||
}
|
||||
|
||||
float SliderJoint::GetCurrentVelocity() const
|
||||
{
|
||||
return _joint ? static_cast<PxPrismaticJoint*>(_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<PxPrismaticJointFlag::Enum>(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;
|
||||
}
|
||||
|
||||
@@ -95,5 +95,5 @@ public:
|
||||
protected:
|
||||
|
||||
// [Joint]
|
||||
PxJoint* CreateJoint(JointData& data) override;
|
||||
void* CreateJoint(const PhysicsJointDesc& desc) override;
|
||||
};
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "SphericalJoint.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include <ThirdParty/PhysX/extensions/PxSphericalJoint.h>
|
||||
#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<PxSphericalJoint*>(_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<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());
|
||||
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<PxSphericalJointFlag::Enum>(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;
|
||||
}
|
||||
|
||||
@@ -85,5 +85,5 @@ public:
|
||||
protected:
|
||||
|
||||
// [Joint]
|
||||
PxJoint* CreateJoint(JointData& data) override;
|
||||
void* CreateJoint(const PhysicsJointDesc& desc) override;
|
||||
};
|
||||
|
||||
3061
Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
Normal file
3061
Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
Normal file
File diff suppressed because it is too large
Load Diff
23
Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h
Normal file
23
Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h
Normal file
@@ -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"
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the physical simulation using PhysX.
|
||||
/// </summary>
|
||||
class PhysicsBackendPhysX
|
||||
{
|
||||
public:
|
||||
static PxPhysics* GetPhysics();
|
||||
#if COMPILE_WITH_PHYSICS_COOKING
|
||||
static PxCooking* GetCooking();
|
||||
#endif
|
||||
static PxMaterial* GetDefaultMaterial();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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 <ThirdParty/PhysX/foundation/PxMath.h>
|
||||
#include <ThirdParty/PhysX/PxSceneLock.h>
|
||||
@@ -138,3 +140,5 @@ void FixedStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, P
|
||||
|
||||
mAccumulator -= PxReal(substepCount) * substepSize;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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 <ThirdParty/PhysX/task/PxTask.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxSimpleTypes.h>
|
||||
@@ -215,3 +217,5 @@ public:
|
||||
mMaxSubSteps = maxSteps;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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 <ThirdParty/PhysX/extensions/PxJoint.h>
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
|
||||
@@ -136,7 +137,6 @@ void SimulationEventCallback::onConstraintBreak(PxConstraintInfo* constraints, P
|
||||
for (uint32 i = 0; i < count; i++)
|
||||
{
|
||||
PxJoint* joint = reinterpret_cast<PxJoint*>(constraints[i].externalReference);
|
||||
|
||||
if (joint->userData)
|
||||
BrokenJoints.Add(static_cast<Joint*>(joint->userData));
|
||||
}
|
||||
@@ -177,6 +177,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
|
||||
|
||||
c.ThisActor = static_cast<PhysicsColliderActor*>(pair.shapes[0]->userData);
|
||||
c.OtherActor = static_cast<PhysicsColliderActor*>(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<PhysicsColliderActor*>(pair.shapes[0]->userData);
|
||||
c.OtherActor = static_cast<PhysicsColliderActor*>(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<PhysicsColliderActor*>(pair.triggerShape->userData);
|
||||
auto otherCollider = static_cast<PhysicsColliderActor*>(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
|
||||
@@ -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 <ThirdParty/PhysX/PxSimulationEventCallback.h>
|
||||
@@ -12,7 +14,6 @@
|
||||
/// <summary>
|
||||
/// Default implementation of the PxSimulationEventCallback to send physics events to the other engine services.
|
||||
/// </summary>
|
||||
/// <seealso cref="PxSimulationEventCallback" />
|
||||
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
|
||||
174
Source/Engine/Physics/PhysX/Types.h
Normal file
174
Source/Engine/Physics/PhysX/Types.h
Normal file
@@ -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 <ThirdParty/PhysX/foundation/PxVec2.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxVec3.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxVec4.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxQuat.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxBounds3.h>
|
||||
#include <ThirdParty/PhysX/characterkinematic/PxExtended.h>
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
#include <ThirdParty/PhysX/PxQueryReport.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; }
|
||||
|
||||
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<PhysicsColliderActor*>(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<PhysicsColliderActor*>(hit.shape->userData) : nullptr;
|
||||
result.FaceIndex = hit.faceIndex;
|
||||
result.UV = Vector2::Zero;
|
||||
}
|
||||
|
||||
extern PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled);
|
||||
|
||||
#endif
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
/// <returns>The native material object.</returns>
|
||||
PxMaterial* GetPhysXMaterial();
|
||||
void* GetPhysicsMaterial();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the PhysX material (after any property change).
|
||||
/// Updates the physics material (after any property change).
|
||||
/// </summary>
|
||||
void UpdatePhysXMaterial();
|
||||
void UpdatePhysicsMaterial();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public static bool WithCooking = true;
|
||||
|
||||
/// <summary>
|
||||
/// Physics system extension event to override for custom physics backend plugin.
|
||||
/// </summary>
|
||||
public static Action<Physics, BuildOptions> SetupPhysicsBackend = SetupPhysicsBackendPhysX;
|
||||
|
||||
/// <inheritdoc />
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
|
||||
}
|
||||
@@ -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 <ThirdParty/PhysX/PxPhysicsAPI.h>
|
||||
#if WITH_PVD
|
||||
#include <ThirdParty/PhysX/pvd/PxPvd.h>
|
||||
#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<int32>(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<PhysicsScene*> 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<PxShapeFlags>(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<PxCombineMode::Enum>(useFrictionCombineMode));
|
||||
|
||||
const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
|
||||
_material->setRestitutionCombineMode(static_cast<PxCombineMode::Enum>(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<PxCombineMode::Enum>(useFrictionCombineMode));
|
||||
|
||||
_material->setRestitution(Restitution);
|
||||
const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode;
|
||||
_material->setRestitutionCombineMode(static_cast<PxCombineMode::Enum>(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<PxScene*> 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<PhysicsScene>();
|
||||
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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsScene>(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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
return PhysicsBackend::OverlapConvex(_scene, center, convexMesh, scale, results, rotation, layerMask, hitTriggers);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Raycast hit result data.
|
||||
/// </summary>
|
||||
API_STRUCT() struct RayCastHit
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
|
||||
|
||||
/// <summary>
|
||||
/// The collider that was hit.
|
||||
/// </summary>
|
||||
API_FIELD() PhysicsColliderActor* Collider = nullptr;
|
||||
|
||||
/// <summary>
|
||||
/// The normal of the surface the ray hit.
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 Normal;
|
||||
|
||||
/// <summary>
|
||||
/// The distance from the ray's origin to the hit location.
|
||||
/// </summary>
|
||||
API_FIELD() float Distance;
|
||||
|
||||
/// <summary>
|
||||
/// The point in the world space where ray hit the collider.
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 Point;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
|
||||
/// </summary>
|
||||
/// <seealso cref="CollisionData.GetModelTriangle" />
|
||||
API_FIELD() uint32 FaceIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
|
||||
/// </summary>
|
||||
API_FIELD() Vector2 UV;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gathers the data from the specified hit (PhysX).
|
||||
/// </summary>
|
||||
/// <param name="hit">The hit.</param>
|
||||
void Gather(const PxRaycastHit& hit);
|
||||
|
||||
/// <summary>
|
||||
/// Gathers the data from the specified hit (PhysX).
|
||||
/// </summary>
|
||||
/// <param name="hit">The hit.</param>
|
||||
void Gather(const PxSweepHit& hit);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Physics simulation system.
|
||||
/// </summary>
|
||||
API_CLASS(Static) class FLAXENGINE_API Physics
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics);
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the master physics object.
|
||||
/// </summary>
|
||||
static PxPhysics* GetPhysics();
|
||||
|
||||
#if COMPILE_WITH_PHYSICS_COOKING
|
||||
|
||||
/// <summary>
|
||||
/// Gets physics cooking object
|
||||
/// </summary>
|
||||
static PxCooking* GetCooking();
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the physics tolerances scale.
|
||||
/// </summary>
|
||||
static PxTolerancesScale* GetTolerancesScale();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default physical material.
|
||||
/// </summary>
|
||||
static PxMaterial* GetDefaultMaterial();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The default physics scene.
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly)
|
||||
static PhysicsScene* DefaultScene;
|
||||
API_FIELD(ReadOnly) static PhysicsScene* DefaultScene;
|
||||
|
||||
/// <summary>
|
||||
/// List with all physics scenes (readonly).
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly)
|
||||
static Array<PhysicsScene*, HeapAllocation> Scenes;
|
||||
API_FIELD(ReadOnly) static Array<PhysicsScene*, HeapAllocation> Scenes;
|
||||
|
||||
/// <summary>
|
||||
/// Finds an existing <see cref="PhysicsScene"/> or creates it if it does not exist.
|
||||
/// </summary>
|
||||
API_FUNCTION() static PhysicsScene* FindOrCreateScene(const String& name);
|
||||
API_FUNCTION() static PhysicsScene* FindOrCreateScene(const StringView& name);
|
||||
|
||||
/// <summary>
|
||||
///Finds an existing scene.
|
||||
/// Finds an existing scene.
|
||||
/// </summary>
|
||||
API_FUNCTION() static PhysicsScene* FindScene(const String& name);
|
||||
API_FUNCTION() static PhysicsScene* FindScene(const StringView& name);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -162,9 +72,29 @@ public:
|
||||
/// The collision layers masks. Used to define layer-based collision detection.
|
||||
/// </summary>
|
||||
static uint32 LayerMasks[32];
|
||||
public:
|
||||
/// <summary>
|
||||
/// Called during main engine loop to start physic simulation. Use CollectResults after.
|
||||
/// </summary>
|
||||
/// <param name="dt">The delta time (in seconds).</param>
|
||||
API_FUNCTION() static void Simulate(float dt);
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events.
|
||||
/// </summary>
|
||||
API_FUNCTION() static void CollectResults();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if physical simulation is running.
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool IsDuringSimulation();
|
||||
|
||||
/// <summary>
|
||||
/// Flushes any latent physics actions (eg. object destroy, actor add/remove to the scene, etc.).
|
||||
/// </summary>
|
||||
API_FUNCTION() static void FlushRequests();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against objects in the scene.
|
||||
/// </summary>
|
||||
@@ -509,84 +439,4 @@ public:
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if convex mesh overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array<PhysicsColliderActor*, HeapAllocation>& results, const Quaternion& rotation = Quaternion::Identity, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to start physic simulation. Use CollectResults after.
|
||||
/// </summary>
|
||||
/// <param name="dt">The delta time (in seconds).</param>
|
||||
API_FUNCTION() static void Simulate(float dt);
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to start physic simulation on all registered scenes.
|
||||
/// </summary>
|
||||
/// <param name="dt">The delta time (in seconds).</param>
|
||||
static void SimulateAll(float dt);
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events.
|
||||
/// </summary>
|
||||
API_FUNCTION() static void CollectResults();
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to collect physic simulation results on all registered scenes and apply them as well as fire collision events.
|
||||
/// </summary>
|
||||
static void CollectResultsAll();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if physical simulation is running
|
||||
/// </summary>
|
||||
/// <returns>True if simulation is active, otherwise false</returns>
|
||||
API_PROPERTY() static bool IsDuringSimulation();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the async requests to add/remove actors, remove materials, etc..
|
||||
/// </summary>
|
||||
static void FlushRequestsAll();
|
||||
|
||||
/// <summary>
|
||||
/// Removes the material (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="material">The material.</param>
|
||||
static void RemoveMaterial(PxMaterial* material);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the physX object via calling release() on it (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="obj">The obj.</param>
|
||||
static void RemoveObject(PxBase* obj);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
static void AddActor(PxActor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
/// <param name="putToSleep">If set to <c>true</c> will put actor to sleep after spawning.</param>
|
||||
static void AddActor(PxRigidDynamic* actor, bool putToSleep = false);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
static void RemoveActor(PxActor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object).
|
||||
/// </summary>
|
||||
/// <param name="collider">The collider.</param>
|
||||
static void RemoveCollider(PhysicsColliderActor* collider);
|
||||
|
||||
/// <summary>
|
||||
/// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object).
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint.</param>
|
||||
static void RemoveJoint(Joint* joint);
|
||||
};
|
||||
|
||||
294
Source/Engine/Physics/PhysicsBackend.h
Normal file
294
Source/Engine/Physics/PhysicsBackend.h
Normal file
@@ -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;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface for the physical simulation backend implementation.
|
||||
/// </summary>
|
||||
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<RayCastHit, HeapAllocation>& 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<RayCastHit, HeapAllocation>& 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<RayCastHit, HeapAllocation>& 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<RayCastHit, HeapAllocation>& 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<RayCastHit, HeapAllocation>& 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<Collider*, HeapAllocation>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array<Collider*, HeapAllocation>& results, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array<Collider*, HeapAllocation>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array<Collider*, HeapAllocation>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array<PhysicsColliderActor*, HeapAllocation>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array<PhysicsColliderActor*, HeapAllocation>& results, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array<PhysicsColliderActor*, HeapAllocation>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers);
|
||||
static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array<PhysicsColliderActor*, HeapAllocation>& 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<Vector3, HeapAllocation>& vertexBuffer, Array<int32, HeapAllocation>& indexBuffer);
|
||||
static void GetTriangleMeshTriangles(void* triangleMesh, Array<Vector3, HeapAllocation>& vertexBuffer, Array<int32, HeapAllocation>& 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);
|
||||
@@ -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 <ThirdParty/PhysX/PxPhysicsAPI.h>
|
||||
#include <ThirdParty/PhysX/PxQueryFiltering.h>
|
||||
|
||||
// Temporary result buffer size
|
||||
#define HIT_BUFFER_SIZE 128
|
||||
|
||||
template<typename HitType>
|
||||
class DynamicHitBuffer : public PxHitCallback<HitType>
|
||||
{
|
||||
private:
|
||||
|
||||
uint32 _count;
|
||||
HitType _buffer[HIT_BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
DynamicHitBuffer()
|
||||
: PxHitCallback<HitType>(_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<PxSweepHit> buffer
|
||||
|
||||
#define SCENE_QUERY_SETUP_OVERLAP_1() SCENE_QUERY_SETUP(false); \
|
||||
PxOverlapBufferN<1> buffer
|
||||
|
||||
#define SCENE_QUERY_SETUP_OVERLAP() SCENE_QUERY_SETUP(false); \
|
||||
DynamicHitBuffer<PxOverlapHit> 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<PhysicsColliderActor*>(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<PhysicsColliderActor*>(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<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP(false);
|
||||
DynamicHitBuffer<PxRaycastHit> 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<RayCastHit>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<Collider*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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<PhysicsColliderActor*>& 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;
|
||||
}
|
||||
@@ -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 <ThirdParty/PhysX/PxPhysicsAPI.h>
|
||||
|
||||
#if WITH_VEHICLE
|
||||
#include "Actors/WheeledVehicle.h"
|
||||
#include <ThirdParty/PhysX/vehicle/PxVehicleUpdate.h>
|
||||
#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<PxActor*> NewActors;
|
||||
Array<PxActor*> DeadActors;
|
||||
Array<PxMaterial*> DeadMaterials;
|
||||
Array<PhysicsColliderActor*> DeadColliders;
|
||||
Array<Joint*> DeadJoints;
|
||||
Array<ActionData> Actions;
|
||||
Array<PxBase*> DeadObjects;
|
||||
|
||||
#if WITH_VEHICLE
|
||||
Array<PxVehicleWheels*> WheelVehiclesCache;
|
||||
Array<PxRaycastQueryResult> WheelQueryResults;
|
||||
Array<PxRaycastHit> WheelHitResults;
|
||||
Array<PxWheelQueryResult> WheelVehiclesResultsPerWheel;
|
||||
Array<PxVehicleWheelQueryResult> WheelVehiclesResultsPerVehicle;
|
||||
PxBatchQuery* WheelRaycastBatchQuery = nullptr;
|
||||
PxVehicleDrivableSurfaceToTireFrictionPairs* WheelTireFrictions = nullptr;
|
||||
Array<WheeledVehicle*> 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<PhysicsScenePhysX>();
|
||||
|
||||
// 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<uint32>(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<FixedStepper>();
|
||||
}
|
||||
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<PhysicsColliderActor*>(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<IPhysicsActor*>((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<PxRigidDynamic*>(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
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Isolated physics scene.
|
||||
/// Physical simulation scene.
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
@@ -35,30 +38,34 @@ API_CLASS(NoSpawn) class FLAXENGINE_API PhysicsScene : public PersistentScriptin
|
||||
/// </summary>
|
||||
API_PROPERTY() String GetName() const;
|
||||
|
||||
public:
|
||||
String ToString() const override
|
||||
/// <summary>
|
||||
/// Gets the native physics system scene object.
|
||||
/// </summary>
|
||||
FORCE_INLINE void* GetPhysicsScene() const
|
||||
{
|
||||
return GetName();
|
||||
return _scene;
|
||||
}
|
||||
|
||||
PxScene* GetScene();
|
||||
/// <summary>
|
||||
/// Gets the automatic simulation feature that perform physics simulation after on fixed update by auto, otherwise user should do it.
|
||||
/// </summary>
|
||||
API_PROPERTY() bool GetAutoSimulation() const;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_PROPERTY() bool GetAutoSimulation();
|
||||
API_PROPERTY() void SetAutoSimulation(bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current gravity force.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetGravity(const Vector3& value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current gravity force.
|
||||
/// </summary>
|
||||
API_PROPERTY() Vector3 GetGravity();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current gravity force.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetGravity(const Vector3& value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CCD feature enable flag.
|
||||
/// </summary>
|
||||
@@ -67,7 +74,7 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the CCD feature enable flag.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetEnableCCD(const bool value);
|
||||
API_PROPERTY() void SetEnableCCD(bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum relative velocity required for an object to bounce.
|
||||
@@ -77,7 +84,16 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the minimum relative velocity required for an object to bounce.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetBounceThresholdVelocity(const float value);
|
||||
API_PROPERTY() void SetBounceThresholdVelocity(float value);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes the scene.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="settings">The physics settings.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool Init(const StringView& name, const PhysicsSettings& settings);
|
||||
|
||||
/// <summary>
|
||||
/// Called during main engine loop to start physic simulation. Use CollectResults after.
|
||||
@@ -86,90 +102,16 @@ public:
|
||||
API_FUNCTION() void Simulate(float dt);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if physical simulation is running
|
||||
/// Checks if physical simulation is running.
|
||||
/// </summary>
|
||||
/// <returns>True if simulation is active, otherwise false</returns>
|
||||
API_PROPERTY() bool IsDuringSimulation();
|
||||
API_PROPERTY() bool IsDuringSimulation() const;
|
||||
|
||||
/// <summary>
|
||||
/// Called to collect physic simulation results and apply them as well as fire collision events.
|
||||
/// </summary>
|
||||
API_FUNCTION() void CollectResults();
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the async requests to add/remove actors, remove materials, etc..
|
||||
/// </summary>
|
||||
void FlushRequests();
|
||||
|
||||
/// <summary>
|
||||
/// Removes the material (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="material">The material.</param>
|
||||
void RemoveMaterial(PxMaterial* material);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the physX object via calling release() on it (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="obj">The obj.</param>
|
||||
void RemoveObject(PxBase* obj);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
void AddActor(PxActor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
/// <param name="putToSleep">If set to <c>true</c> will put actor to sleep after spawning.</param>
|
||||
void AddActor(PxRigidDynamic* actor, bool putToSleep = false);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the actor (using safe async request).
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor.</param>
|
||||
void RemoveActor(PxActor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the actor from the underlying physics scene without destroying it.
|
||||
/// </summary>
|
||||
void UnlinkActor(PxActor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object).
|
||||
/// </summary>
|
||||
/// <param name="collider">The collider.</param>
|
||||
void RemoveCollider(PhysicsColliderActor* collider);
|
||||
|
||||
/// <summary>
|
||||
/// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object).
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint.</param>
|
||||
void RemoveJoint(Joint* joint);
|
||||
|
||||
/// <summary>
|
||||
/// Gets PhysX characters controller manager object
|
||||
/// </summary>
|
||||
PxControllerManager* GetControllerManager();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the default query filter callback used for the scene queries.
|
||||
/// </summary>
|
||||
PxQueryFilterCallback* GetQueryFilterCallback();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default query filter callback used for the character controller collisions detection.
|
||||
/// </summary>
|
||||
PxQueryFilterCallback* GetCharacterQueryFilterCallback();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default controller filter callback used for the character controller collisions detection.
|
||||
/// </summary>
|
||||
static PxControllerFilterCallback* GetCharacterControllerFilterCallback();
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against objects in the scene.
|
||||
/// </summary>
|
||||
@@ -514,20 +456,4 @@ public:
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if convex mesh overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array<PhysicsColliderActor*, HeapAllocation>& 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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
|
||||
/// <summary>
|
||||
/// Raycast hit result data.
|
||||
/// </summary>
|
||||
API_STRUCT() struct RayCastHit
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
|
||||
|
||||
/// <summary>
|
||||
/// The collider that was hit.
|
||||
/// </summary>
|
||||
API_FIELD() PhysicsColliderActor* Collider = nullptr;
|
||||
|
||||
/// <summary>
|
||||
/// The normal of the surface the ray hit.
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 Normal;
|
||||
|
||||
/// <summary>
|
||||
/// The distance from the ray's origin to the hit location.
|
||||
/// </summary>
|
||||
API_FIELD() float Distance;
|
||||
|
||||
/// <summary>
|
||||
/// The point in the world space where ray hit the collider.
|
||||
/// </summary>
|
||||
API_FIELD() Vector3 Point;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
|
||||
/// </summary>
|
||||
/// <seealso cref="CollisionData.GetModelTriangle" />
|
||||
API_FIELD() uint32 FaceIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
|
||||
/// </summary>
|
||||
API_FIELD() Vector2 UV;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Physics collision shape variant for different shapes such as box, sphere, capsule.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/PhysX/foundation/PxVec2.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxVec3.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxVec4.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxQuat.h>
|
||||
#include <ThirdParty/PhysX/foundation/PxBounds3.h>
|
||||
#include <ThirdParty/PhysX/characterkinematic/PxExtended.h>
|
||||
#include <ThirdParty/PhysX/PxShape.h>
|
||||
|
||||
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);
|
||||
@@ -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 <ThirdParty/PhysX/PxFiltering.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <extensions/PxDefaultStreams.h>
|
||||
#include <extensions/PxShapeExt.h>
|
||||
#include <foundation/PxTransform.h>
|
||||
#include <geometry/PxHeightField.h>
|
||||
#include <geometry/PxHeightFieldDesc.h>
|
||||
#include <geometry/PxHeightFieldSample.h>
|
||||
#include <cooking/PxCooking.h>
|
||||
#include <PxRigidStatic.h>
|
||||
#include <PxPhysics.h>
|
||||
|
||||
#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<Vector3>& 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, Array<Vec
|
||||
result.Clear();
|
||||
|
||||
// Skip if no intersection with patch
|
||||
if (!CollisionsHelper::BoxIntersectsSphere(GetBounds(), bounds))
|
||||
if (!CollisionsHelper::BoxIntersectsSphere(GetBounds(), bounds) || !_physicsHeightField)
|
||||
return;
|
||||
CHECK(_physicsHeightField);
|
||||
|
||||
// Prepare
|
||||
const auto& triangles = GetCollisionTriangles();
|
||||
@@ -2424,8 +2345,8 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array<Vec
|
||||
}
|
||||
|
||||
// Normalize bounds and map to actual triangles buffer
|
||||
const int32 rows = _physicsHeightField->getNbRows();
|
||||
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<Vector3>& 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<Vector3>& 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<Vector3>& 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);
|
||||
}
|
||||
|
||||
@@ -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<RawDataAsset> _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:
|
||||
/// </summary>
|
||||
/// <param name="position">The position to find the closest point to it.</param>
|
||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
||||
void ClosestPoint(const Vector3& position, Vector3* result) const;
|
||||
void ClosestPoint(const Vector3& position, Vector3& result) const;
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
@@ -373,7 +372,6 @@ private:
|
||||
/// <summary>
|
||||
/// Determines whether this patch has created collision representation.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this patch has collider; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool HasCollision() const
|
||||
{
|
||||
return _physicsShape != nullptr;
|
||||
|
||||
2
Source/ThirdParty/PhysX/PhysX.Build.cs
vendored
2
Source/ThirdParty/PhysX/PhysX.Build.cs
vendored
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user