Refactor Rigidbody automatic mass calculation to include physical material Density
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "RigidBody.h"
|
||||
#include "PxMaterial.h"
|
||||
#include "Engine/Physics/Utilities.h"
|
||||
#include "Engine/Physics/Colliders/Collider.h"
|
||||
#include "Engine/Physics/Physics.h"
|
||||
#include "Engine/Physics/PhysicalMaterial.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include <ThirdParty/PhysX/extensions/PxRigidBodyExt.h>
|
||||
#include <ThirdParty/PhysX/PxRigidActor.h>
|
||||
@@ -133,6 +135,11 @@ void RigidBody::SetMaxAngularVelocity(float value)
|
||||
_actor->setMaxAngularVelocity(value);
|
||||
}
|
||||
|
||||
bool RigidBody::GetOverrideMass() const
|
||||
{
|
||||
return _overrideMass != 0;
|
||||
}
|
||||
|
||||
void RigidBody::SetOverrideMass(bool value)
|
||||
{
|
||||
if (value == GetOverrideMass())
|
||||
@@ -143,6 +150,11 @@ void RigidBody::SetOverrideMass(bool value)
|
||||
UpdateMass();
|
||||
}
|
||||
|
||||
float RigidBody::GetMass() const
|
||||
{
|
||||
return _mass;
|
||||
}
|
||||
|
||||
void RigidBody::SetMass(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _mass))
|
||||
@@ -156,15 +168,18 @@ void RigidBody::SetMass(float value)
|
||||
UpdateMass();
|
||||
}
|
||||
|
||||
float RigidBody::GetMassScale() const
|
||||
{
|
||||
return _massScale;
|
||||
}
|
||||
|
||||
void RigidBody::SetMassScale(float value)
|
||||
{
|
||||
if (Math::NearEqual(value, _massScale))
|
||||
return;
|
||||
|
||||
_massScale = value;
|
||||
|
||||
if (!_overrideMass)
|
||||
UpdateMass();
|
||||
UpdateMass();
|
||||
}
|
||||
|
||||
void RigidBody::SetCenterOfMassOffset(const Vector3& value)
|
||||
@@ -267,44 +282,51 @@ void RigidBody::WakeUp() const
|
||||
|
||||
void RigidBody::UpdateMass()
|
||||
{
|
||||
// Skip if no actor created
|
||||
if (_actor == nullptr)
|
||||
return;
|
||||
|
||||
// Physical material
|
||||
float densityKGPerCubicUU = 1.0f;
|
||||
float raiseMassToPower = 0.75f;
|
||||
// TODO: link physical material or expose density parameter
|
||||
|
||||
PxRigidBodyExt::updateMassAndInertia(*_actor, densityKGPerCubicUU);
|
||||
|
||||
// Grab old mass so we can apply new mass while maintaining inertia tensor
|
||||
const float oldMass = _actor->getMass();
|
||||
float newMass;
|
||||
|
||||
if (_overrideMass == false)
|
||||
if (_overrideMass)
|
||||
{
|
||||
const float usePow = Math::Clamp<float>(raiseMassToPower, ZeroTolerance, 1.0f);
|
||||
newMass = Math::Pow(oldMass, usePow);
|
||||
|
||||
// Apply user-defined mass scaling
|
||||
newMass *= Math::Clamp<float>(_massScale, 0.01f, 100.0f);
|
||||
|
||||
_mass = newMass;
|
||||
// Use fixed mass
|
||||
PxRigidBodyExt::setMassAndUpdateInertia(*_actor, Math::Max(_mass * _massScale, 0.001f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Min weight of 1g
|
||||
newMass = Math::Max(_mass, 0.001f);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(newMass > 0.0f);
|
||||
|
||||
const float massRatio = newMass / oldMass;
|
||||
const PxVec3 inertiaTensor = _actor->getMassSpaceInertiaTensor();
|
||||
|
||||
_actor->setMassSpaceInertiaTensor(inertiaTensor * massRatio);
|
||||
_actor->setMass(newMass);
|
||||
}
|
||||
|
||||
void RigidBody::AddForce(const Vector3& force, ForceMode mode) const
|
||||
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
/// Kinematic rigidbodies are incompatible with CCD.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(false), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE bool GetIsKinematic() const
|
||||
{
|
||||
@@ -81,7 +80,6 @@ public:
|
||||
/// <remarks>
|
||||
/// Linear damping can be used to slow down an object. The higher the drag the more the object slows down.
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(0.01f), Limit(0), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE float GetLinearDamping() const
|
||||
{
|
||||
@@ -103,7 +101,6 @@ public:
|
||||
/// <remarks>
|
||||
/// Angular damping can be used to slow down the rotation of an object. The higher the drag the more the rotation slows down.
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(70), DefaultValue(0.05f), Limit(0), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE float GetAngularDamping() const
|
||||
{
|
||||
@@ -122,7 +119,6 @@ public:
|
||||
/// <summary>
|
||||
/// If true simulation and collisions detection will be enabled for the rigidbody.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(true), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE bool GetEnableSimulation() const
|
||||
{
|
||||
@@ -138,7 +134,6 @@ public:
|
||||
/// <summary>
|
||||
/// If true Continuous Collision Detection (CCD) will be used for this component.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(30), DefaultValue(false), EditorDisplay(\"Rigid Body\", \"Use CCD\")")
|
||||
FORCE_INLINE bool GetUseCCD() const
|
||||
{
|
||||
@@ -154,7 +149,6 @@ public:
|
||||
/// <summary>
|
||||
/// If object should have the force of gravity applied.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(true), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE bool GetEnableGravity() const
|
||||
{
|
||||
@@ -170,7 +164,6 @@ public:
|
||||
/// <summary>
|
||||
/// If object should start awake, or if it should initially be sleeping.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(true), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE bool GetStartAwake() const
|
||||
{
|
||||
@@ -186,7 +179,6 @@ public:
|
||||
/// <summary>
|
||||
/// If true, it will update mass when actor scale changes.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(130), DefaultValue(false), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE bool GetUpdateMassWhenScaleChanges() const
|
||||
{
|
||||
@@ -196,7 +188,7 @@ public:
|
||||
/// <summary>
|
||||
/// If true, it will update mass when actor scale changes.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetUpdateMassWhenScaleChanges(bool value);
|
||||
|
||||
/// <summary>
|
||||
@@ -206,7 +198,6 @@ public:
|
||||
/// The angular velocity of rigidbodies is clamped to MaxAngularVelocity to avoid numerical instability with fast rotating bodies.
|
||||
/// Because this may prevent intentional fast rotations on objects such as wheels, you can override this value per rigidbody.
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(90), DefaultValue(7.0f), Limit(0), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE float GetMaxAngularVelocity() const
|
||||
{
|
||||
@@ -226,12 +217,8 @@ public:
|
||||
/// <summary>
|
||||
/// Override the auto computed mass.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="HideInEditor")
|
||||
FORCE_INLINE bool GetOverrideMass() const
|
||||
{
|
||||
return _overrideMass != 0;
|
||||
}
|
||||
bool GetOverrideMass() const;
|
||||
|
||||
/// <summary>
|
||||
/// Override the auto computed mass.
|
||||
@@ -240,33 +227,23 @@ public:
|
||||
API_PROPERTY() void SetOverrideMass(bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mass value measured in kilograms (use override value only if EnableOverrideMass is enabled).
|
||||
/// Gets the mass value measured in kilograms (use override value only if OverrideMass is checked).
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(110), Limit(0), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE float GetMass() const
|
||||
{
|
||||
return _mass;
|
||||
}
|
||||
float GetMass() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mass value measured in kilograms (use override value only if EnableOverrideMass is enabled).
|
||||
/// Sets the mass value measured in kilograms (use override value only if OverrideMass is checked).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If set auto enables mass override.
|
||||
/// </remarks>
|
||||
/// <remarks>If set auto enables mass override.</remarks>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetMass(float value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the per-instance scaling of the mass.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(120), DefaultValue(1.0f), Limit(0.001f, 100.0f), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE float GetMassScale() const
|
||||
{
|
||||
return _massScale;
|
||||
}
|
||||
float GetMassScale() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the per-instance scaling of the mass.
|
||||
@@ -277,7 +254,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the user specified offset for the center of mass of this object, from the calculated location.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(140), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorDisplay(\"Rigid Body\", \"Center Of Mass Offset\")")
|
||||
FORCE_INLINE Vector3 GetCenterOfMassOffset() const
|
||||
{
|
||||
@@ -293,7 +269,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the object movement constraint flags that define degrees of freedom are allowed for the simulation of object.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="EditorOrder(150), DefaultValue(RigidbodyConstraints.None), EditorDisplay(\"Rigid Body\")")
|
||||
FORCE_INLINE RigidbodyConstraints GetConstraints() const
|
||||
{
|
||||
@@ -314,7 +289,6 @@ public:
|
||||
/// <remarks>
|
||||
/// It's used mostly to get the current velocity. Manual modifications may result in unrealistic behaviour.
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="HideInEditor")
|
||||
Vector3 GetLinearVelocity() const;
|
||||
|
||||
@@ -333,7 +307,6 @@ public:
|
||||
/// <remarks>
|
||||
/// It's used mostly to get the current angular velocity. Manual modifications may result in unrealistic behaviour.
|
||||
/// </remarks>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY(Attributes="HideInEditor")
|
||||
Vector3 GetAngularVelocity() const;
|
||||
|
||||
@@ -389,13 +362,11 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the center of the mass in the local space.
|
||||
/// </summary>
|
||||
/// <returns>The value.</returns>
|
||||
API_PROPERTY() Vector3 GetCenterOfMass() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this rigidbody is sleeping.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this rigidbody is sleeping; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() bool IsSleeping() const;
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user