Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
8 changed files with 82 additions and 177 deletions
Showing only changes of commit 6a20e93704 - Show all commits

View File

@ -25,9 +25,10 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType) SHCollisionShape::SHCollisionShape(SHCollisionShapeID id, Type colliderType)
: id { id } : id { id }
, flags { 0 } , flags { 0 }
, collisionTag { SHCollisionTagMatrix::GetTag(0) } , parentTransform { nullptr }
, collisionTag { SHCollisionTagMatrix::GetTag(0) }
{ {
flags |= 1U << SHUtilities::ConvertEnum(colliderType); flags |= 1U << SHUtilities::ConvertEnum(colliderType);
} }
@ -58,7 +59,7 @@ namespace SHADE
const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept
{ {
return positionOffset; return transform.position;
} }
const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept
@ -95,15 +96,6 @@ namespace SHADE
return flags & FLAG_VALUE; return flags & FLAG_VALUE;
} }
bool SHCollisionShape::IsDirty() const noexcept
{
static constexpr int FLAG_POS = 6;
static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS;
return flags & FLAG_VALUE;
}
const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept
{ {
return *collisionTag; return *collisionTag;
@ -125,26 +117,32 @@ namespace SHADE
void SHCollisionShape::SetDensity(float density) noexcept void SHCollisionShape::SetDensity(float density) noexcept
{ {
setDirty(true);
material.SetDensity(density); material.SetDensity(density);
} }
void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{ {
setDirty(true);
material = newMaterial; material = newMaterial;
} }
void SHCollisionShape::SetParentTransform(SHTransform& parentTF) noexcept
{
parentTransform = &parentTF;
}
void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept
{ {
setDirty(true); transform.position = posOffset;
positionOffset = posOffset;
ComputeTransforms();
} }
void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept
{ {
setDirty(true);
rotationOffset = rotOffset; rotationOffset = rotOffset;
transform.orientation = SHQuaternion::FromEuler(rotationOffset);
ComputeTransforms();
} }
void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept
@ -160,28 +158,6 @@ namespace SHADE
collisionTag = newCollisionTag; collisionTag = newCollisionTag;
} }
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::ClearDirty() noexcept
{
setDirty(false);
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::setDirty(bool isDirty) noexcept
{
static constexpr int FLAG_POS = 6;
static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS;
isDirty ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
}
} // namespace SHADE } // namespace SHADE
RTTR_REGISTRATION RTTR_REGISTRATION

View File

@ -14,11 +14,10 @@
// Project Headers // Project Headers
#include "ECS_Base/Entity/SHEntity.h" #include "ECS_Base/Entity/SHEntity.h"
#include "Math/Geometry/SHShape.h"
#include "Math/SHQuaternion.h"
#include "Physics/Collision/CollisionTags/SHCollisionTags.h" #include "Physics/Collision/CollisionTags/SHCollisionTags.h"
#include "Physics/Collision/SHPhysicsMaterial.h" #include "Physics/Collision/SHPhysicsMaterial.h"
#include "SHCollisionShapeID.h" #include "SHCollisionShapeID.h"
#include "Math/Transform/SHTransform.h"
namespace SHADE namespace SHADE
{ {
@ -91,7 +90,6 @@ namespace SHADE
[[nodiscard]] Type GetType () const noexcept; [[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] bool IsTrigger () const noexcept; [[nodiscard]] bool IsTrigger () const noexcept;
[[nodiscard]] bool IsColliding () const noexcept; [[nodiscard]] bool IsColliding () const noexcept;
[[nodiscard]] bool IsDirty () const noexcept;
[[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept; [[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept;
@ -104,6 +102,8 @@ namespace SHADE
void SetDensity (float density) noexcept; void SetDensity (float density) noexcept;
void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept;
void SetParentTransform (SHTransform& parentTF) noexcept;
void SetPositionOffset (const SHVec3& posOffset) noexcept; void SetPositionOffset (const SHVec3& posOffset) noexcept;
void SetRotationOffset (const SHVec3& rotOffset) noexcept; void SetRotationOffset (const SHVec3& rotOffset) noexcept;
@ -117,13 +117,9 @@ namespace SHADE
/* Member Functions */ /* Member Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/** virtual void ComputeTransforms () noexcept = 0;
* @brief [[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0;
* Clears the dirty flag of the collider. [[nodiscard]] virtual SHMatrix ComputeWorldTransform () const noexcept = 0;
*/
void ClearDirty () noexcept;
[[nodiscard]] virtual SHMatrix GetInertiaTensor (float mass) const noexcept = 0;
protected: protected:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -134,20 +130,16 @@ namespace SHADE
SHPhysicsMaterial material; SHPhysicsMaterial material;
SHVec3 positionOffset; SHTransform* parentTransform;
SHTransform transform;
// Needed for conversion to euler angles
SHVec3 rotationOffset; SHVec3 rotationOffset;
uint8_t flags; // 0 dirty wasColliding isColliding trigger capsule sphere box uint8_t flags; // 0 0 wasColliding isColliding trigger capsule sphere box
SHCollisionTag* collisionTag; SHCollisionTag* collisionTag;
RTTR_ENABLE() RTTR_ENABLE()
private:
/*---------------------------------------------------------------------------------*/
/* Member Functions */
/*---------------------------------------------------------------------------------*/
void setDirty (bool isDirty) noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -14,6 +14,7 @@
#include "SHSphereCollisionShape.h" #include "SHSphereCollisionShape.h"
// Project Headers // Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
namespace SHADE namespace SHADE
@ -37,7 +38,8 @@ namespace SHADE
{ {
material = rhs.material; material = rhs.material;
positionOffset = rhs.positionOffset; parentTransform = rhs.parentTransform;
transform = rhs.transform;
rotationOffset = rhs.rotationOffset; rotationOffset = rhs.rotationOffset;
flags = rhs.flags; flags = rhs.flags;
// Since all collision tags are taken from the matrix, we do not need to do a deep copy here. // Since all collision tags are taken from the matrix, we do not need to do a deep copy here.
@ -52,7 +54,8 @@ namespace SHADE
{ {
material = rhs.material; material = rhs.material;
positionOffset = rhs.positionOffset; parentTransform = rhs.parentTransform;
transform = rhs.transform;
rotationOffset = rhs.rotationOffset; rotationOffset = rhs.rotationOffset;
flags = rhs.flags; flags = rhs.flags;
// Since all collision tags are taken from the matrix, we do not need to do a deep copy here. // Since all collision tags are taken from the matrix, we do not need to do a deep copy here.
@ -72,7 +75,8 @@ namespace SHADE
id = rhs.id; id = rhs.id;
material = rhs.material; material = rhs.material;
positionOffset = rhs.positionOffset; parentTransform = rhs.parentTransform;
transform = rhs.transform;
rotationOffset = rhs.rotationOffset; rotationOffset = rhs.rotationOffset;
flags = rhs.flags; flags = rhs.flags;
// Since all collision tags are taken from the matrix, we do not need to do a deep copy here. // Since all collision tags are taken from the matrix, we do not need to do a deep copy here.
@ -97,7 +101,8 @@ namespace SHADE
id = rhs.id; id = rhs.id;
material = rhs.material; material = rhs.material;
positionOffset = rhs.positionOffset; parentTransform = rhs.parentTransform;
transform = rhs.transform;
rotationOffset = rhs.rotationOffset; rotationOffset = rhs.rotationOffset;
flags = rhs.flags; flags = rhs.flags;
// Since all collision tags are taken from the matrix, we do not need to do a deep copy here. // Since all collision tags are taken from the matrix, we do not need to do a deep copy here.
@ -172,6 +177,18 @@ namespace SHADE
/* Public Member Function Definitions */ /* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHSphereCollisionShape::ComputeTransforms() noexcept
{
const float SPHERE_SCALE = std::fabs(SHMath::Max({ parentTransform->scale.x, parentTransform->scale.y, parentTransform->scale.z }));
SetScale(SPHERE_SCALE);
// Recompute center
const SHQuaternion FINAL_ROT = parentTransform->orientation * transform.orientation;
const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(parentTransform->position);
Center = SHVec3::Transform(transform.position, TRS);
}
bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept bool SHSphereCollisionShape::TestPoint(const SHVec3& point) const noexcept
{ {
return SHSphere::TestPoint(point); return SHSphere::TestPoint(point);
@ -193,6 +210,18 @@ namespace SHADE
return result; return result;
} }
SHMatrix SHSphereCollisionShape::ComputeWorldTransform() const noexcept
{
const SHQuaternion ROTATION = parentTransform->orientation * transform.orientation;
const SHVec3 SCALE{ Radius };
return SHMatrix::Transform
(
Center
, ROTATION
, SCALE
);
}
} // namespace SHADE } // namespace SHADE

View File

@ -88,6 +88,12 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/**
* @brief
* Recomputes the transform of this sphere.
*/
void ComputeTransforms () noexcept override;
/** /**
* @brief * @brief
* Tests if a point is inside the sphere. * Tests if a point is inside the sphere.
@ -96,7 +102,7 @@ namespace SHADE
* @return * @return
* True if the point is inside the sphere. * True if the point is inside the sphere.
*/ */
[[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; [[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override;
/** /**
* @brief * @brief
@ -107,7 +113,7 @@ namespace SHADE
* An object holding the results of the raycast. <br/> * An object holding the results of the raycast. <br/>
* See the corresponding header for the contents of the object. * See the corresponding header for the contents of the object.
*/ */
[[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override; [[nodiscard]] SHRaycastResult Raycast (const SHRay& ray) const noexcept override;
/** /**
* @brief * @brief
@ -117,9 +123,9 @@ namespace SHADE
* @return * @return
* The inertia tensor of the sphere. * The inertia tensor of the sphere.
*/ */
[[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override; [[nodiscard]] SHMatrix GetInertiaTensor (float mass) const noexcept override;
[[nodiscard]] SHMatrix ComputeWorldTransform () const noexcept override;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -30,19 +30,15 @@ namespace SHADE
: entityID { eid } : entityID { eid }
, shapeIDCounter { 0 } , shapeIDCounter { 0 }
, debugDraw { false } , debugDraw { false }
, dirty { true }
, rigidBody { nullptr } , rigidBody { nullptr }
, shapeFactory { nullptr } , shapeFactory { nullptr }
, transform { worldTransform } , transform { worldTransform }
{ {}
}
SHCollider::SHCollider(const SHCollider& rhs) noexcept SHCollider::SHCollider(const SHCollider& rhs) noexcept
: entityID { rhs.entityID } : entityID { rhs.entityID }
, shapeIDCounter { rhs.shapeIDCounter } , shapeIDCounter { rhs.shapeIDCounter }
, debugDraw { rhs.debugDraw } , debugDraw { rhs.debugDraw }
, dirty { rhs.dirty }
, rigidBody { rhs.rigidBody } , rigidBody { rhs.rigidBody }
, shapeFactory { rhs.shapeFactory } , shapeFactory { rhs.shapeFactory }
, transform { rhs.transform } , transform { rhs.transform }
@ -60,7 +56,6 @@ namespace SHADE
: entityID { rhs.entityID } : entityID { rhs.entityID }
, shapeIDCounter { rhs.shapeIDCounter } , shapeIDCounter { rhs.shapeIDCounter }
, debugDraw { rhs.debugDraw } , debugDraw { rhs.debugDraw }
, dirty { rhs.dirty }
, rigidBody { rhs.rigidBody } , rigidBody { rhs.rigidBody }
, shapeFactory { rhs.shapeFactory } , shapeFactory { rhs.shapeFactory }
, transform { rhs.transform } , transform { rhs.transform }
@ -103,7 +98,6 @@ namespace SHADE
entityID = rhs.entityID; entityID = rhs.entityID;
debugDraw = rhs.debugDraw; debugDraw = rhs.debugDraw;
dirty = rhs.dirty;
rigidBody = rhs.rigidBody; rigidBody = rhs.rigidBody;
shapeFactory = rhs.shapeFactory; shapeFactory = rhs.shapeFactory;
transform = rhs.transform; transform = rhs.transform;
@ -123,7 +117,6 @@ namespace SHADE
entityID = rhs.entityID; entityID = rhs.entityID;
debugDraw = rhs.debugDraw; debugDraw = rhs.debugDraw;
dirty = rhs.dirty;
rigidBody = rhs.rigidBody; rigidBody = rhs.rigidBody;
shapeFactory = rhs.shapeFactory; shapeFactory = rhs.shapeFactory;
transform = rhs.transform; transform = rhs.transform;
@ -206,25 +199,21 @@ namespace SHADE
void SHCollider::SetTransform(const SHTransform& newTransform) noexcept void SHCollider::SetTransform(const SHTransform& newTransform) noexcept
{ {
dirty = true;
transform = newTransform; transform = newTransform;
} }
void SHCollider::SetPosition(const SHVec3& newPosition) noexcept void SHCollider::SetPosition(const SHVec3& newPosition) noexcept
{ {
dirty = true;
transform.position = newPosition; transform.position = newPosition;
} }
void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept void SHCollider::SetOrientation(const SHQuaternion& newOrientation) noexcept
{ {
dirty = true;
transform.orientation = newOrientation; transform.orientation = newOrientation;
} }
void SHCollider::SetScale(const SHVec3& newScale) noexcept void SHCollider::SetScale(const SHVec3& newScale) noexcept
{ {
dirty = true;
transform.scale = newScale; transform.scale = newScale;
} }
@ -272,8 +261,9 @@ namespace SHADE
++shapeIDCounter; ++shapeIDCounter;
// Set offsets // Set offsets
sphere->positionOffset = posOffset; sphere->SetParentTransform(transform);
sphere->rotationOffset = rotOffset; sphere->SetPositionOffset(posOffset);
sphere->SetRotationOffset(rotOffset);
shapes.emplace_back(sphere); shapes.emplace_back(sphere);
@ -293,28 +283,6 @@ namespace SHADE
return static_cast<int>(shapes.size()); return static_cast<int>(shapes.size());
} }
void SHCollider::Update()
{
// Forcefully recompute everything since the transform was changed
if (dirty)
{
RecomputeShapes();
dirty = false;
return;
}
// Recompute any shapes set to dirty
for (auto* shape : shapes)
{
if (shape->IsDirty())
{
recomputeShape(shape);
shape->ClearDirty();
}
}
}
void SHCollider::RemoveCollisionShape(int index) void SHCollider::RemoveCollisionShape(int index)
{ {
if (!shapeFactory) if (!shapeFactory)
@ -360,7 +328,7 @@ namespace SHADE
void SHCollider::RecomputeShapes() noexcept void SHCollider::RecomputeShapes() noexcept
{ {
for (auto* shape : shapes) for (auto* shape : shapes)
recomputeShape(shape); shape->ComputeTransforms();
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -416,47 +384,4 @@ namespace SHADE
++shapeIDCounter; ++shapeIDCounter;
} }
void SHCollider::recomputeShape(SHCollisionShape* shape) noexcept
{
if (!shape)
{
SHLOGV_ERROR_D("Shape missing from Collider {}", entityID)
return;
}
switch (shape->GetType())
{
case SHCollisionShape::Type::SPHERE:
{
recomputeSphere(dynamic_cast<SHSphereCollisionShape*>(shape));
break;
}
case SHCollisionShape::Type::BOX:
{
break;
}
case SHCollisionShape::Type::CAPSULE:
{
break;
}
default: break;
}
}
void SHCollider::recomputeSphere(SHSphereCollisionShape* sphere) noexcept
{
// Recompute world radius
const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z }));
sphere->SetScale(SPHERE_SCALE);
// Recompute center
const SHQuaternion FINAL_ROT = transform.orientation * SHQuaternion::FromEuler(sphere->rotationOffset);
const SHMatrix TRS = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(transform.position);
const SHVec3 NEW_CENTER = SHVec3::Transform(sphere->positionOffset, TRS);
sphere->SetCenter(NEW_CENTER);
}
} // namespace SHADE } // namespace SHADE

View File

@ -132,12 +132,6 @@ namespace SHADE
// TODO: Add Box & Capsule // TODO: Add Box & Capsule
/**
* @brief
* Recomputes any shapes that were set to dirty.
*/
void Update ();
/** /**
* @brief * @brief
* Removes a shape from the container. Removal reduces the size of the container. * Removes a shape from the container. Removal reduces the size of the container.
@ -164,7 +158,6 @@ namespace SHADE
uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes. uint32_t shapeIDCounter; // This increments everytime a shape is added to differentiate shapes.
bool debugDraw; bool debugDraw;
bool dirty;
SHRigidBody* rigidBody; SHRigidBody* rigidBody;
SHCollisionShapeFactory* shapeFactory; SHCollisionShapeFactory* shapeFactory;
@ -179,9 +172,6 @@ namespace SHADE
void copyShapes (const SHCollider& rhsCollider); void copyShapes (const SHCollider& rhsCollider);
void copyShape (const SHCollisionShape* rhsShape); void copyShape (const SHCollisionShape* rhsShape);
void recomputeShape (SHCollisionShape* shape) noexcept;
void recomputeSphere (SHSphereCollisionShape* sphere) noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -41,7 +41,7 @@ namespace SHADE
{ {
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID); const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (!TRANSFORM_COMPONENT) if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged())
continue; continue;
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
@ -50,7 +50,7 @@ namespace SHADE
// We assume that all engine components and physics object components have been successfully linked // We assume that all engine components and physics object components have been successfully linked
if (physicsObject.rigidBody && TRANSFORM_COMPONENT->HasChanged()) if (physicsObject.rigidBody)
{ {
SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); SHMotionState& motionState = physicsObject.rigidBody->GetMotionState();
@ -60,14 +60,11 @@ namespace SHADE
if (physicsObject.collider) if (physicsObject.collider)
{ {
if (TRANSFORM_COMPONENT->HasChanged()) physicsObject.collider->SetPosition(WORLD_POS);
{ physicsObject.collider->SetOrientation(WORLD_ROT);
physicsObject.collider->SetPosition(WORLD_POS); physicsObject.collider->SetScale(WORLD_SCL);
physicsObject.collider->SetOrientation(WORLD_ROT);
physicsObject.collider->SetScale(WORLD_SCL);
}
physicsObject.collider->Update(); physicsObject.collider->RecomputeShapes();
} }
} }
} }

View File

@ -122,17 +122,7 @@ namespace SHADE
{ {
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
const SHSphereCollisionShape* SPHERE = dynamic_cast<const SHSphereCollisionShape*>(SHAPE); debugDrawSystem->DrawWireSphere(SHAPE->ComputeWorldTransform(), DRAW_COLOUR, true);
// Compute transforms of sphere
const SHVec3 POSITION = SPHERE->GetCenter(); // Position offset is already computed here
const SHVec3 ROTATION = collider.GetOrientation().ToEuler() + SPHERE->GetRotationOffset();
const SHVec3 SCALE { SPHERE->GetWorldRadius() };
// Compute TRS for the sphere
const SHMatrix TRS = SHMatrix::Transform(POSITION, ROTATION, SCALE);
debugDrawSystem->DrawWireSphere(TRS, DRAW_COLOUR, true);
break; break;
} }