From 2607e0e187d51a9da4ae56fce58b2a7ee83c435e Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 31 May 2023 10:38:33 -0500 Subject: [PATCH 1/2] Add ability to rotate colliders and add collider direction for capsule collider. --- .../Physics/Colliders/CapsuleCollider.cpp | 37 +++++++++++-- .../Physics/Colliders/CapsuleCollider.h | 27 ++++++++++ Source/Engine/Physics/Colliders/Collider.cpp | 54 +++++++++++++++---- Source/Engine/Physics/Colliders/Collider.h | 14 +++++ 4 files changed, 120 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp index ba133e8b6..7728e6a3e 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp @@ -7,7 +7,9 @@ CapsuleCollider::CapsuleCollider(const SpawnParams& params) : Collider(params) , _radius(20.0f) , _height(100.0f) + , _direction(ColliderOrientationDirection::YAxis) { + SetDirection(_direction); } void CapsuleCollider::SetRadius(const float value) @@ -42,8 +44,10 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view) const BoundingSphere sphere(_sphere.Center - view.Origin, _sphere.Radius); if (!view.CullingFrustum.Intersects(sphere)) return; + Quaternion collRot; + Quaternion::Multiply( _colliderOrientation, Quaternion::Euler(0, 90, 0), collRot); Quaternion rot; - Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rot); + Quaternion::Multiply(_transform.Orientation, collRot, rot); const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize); @@ -54,10 +58,30 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view) DEBUG_DRAW_WIRE_TUBE(_transform.LocalToWorld(_center), rot, radius, height, Color::GreenYellow * 0.8f, 0, true); } +void CapsuleCollider::SetDirection(ColliderOrientationDirection value) +{ + _direction = value; + switch (value) + { + case ColliderOrientationDirection::XAxis: + SetColliderOrientation(Quaternion::Identity); + break; + case ColliderOrientationDirection::YAxis: + SetColliderOrientation(Quaternion::Euler(0, 0, 90)); + break; + case ColliderOrientationDirection::ZAxis: + SetColliderOrientation(Quaternion::Euler(0, 90, 0)); + break; + default: ; + } +} + void CapsuleCollider::OnDebugDrawSelected() { + Quaternion collRot; + Quaternion::Multiply( _colliderOrientation, Quaternion::Euler(0, 90, 0), collRot); Quaternion rot; - Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rot); + Quaternion::Multiply(_transform.Orientation, collRot, rot); const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize); @@ -84,6 +108,7 @@ void CapsuleCollider::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE_MEMBER(Radius, _radius); SERIALIZE_MEMBER(Height, _height); + SERIALIZE(_direction); } void CapsuleCollider::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) @@ -93,6 +118,8 @@ void CapsuleCollider::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE_MEMBER(Radius, _radius); DESERIALIZE_MEMBER(Height, _height); + DESERIALIZE(_direction); + SetDirection(_direction); } void CapsuleCollider::UpdateBounds() @@ -100,7 +127,11 @@ void CapsuleCollider::UpdateBounds() // Cache bounds const float radiusTwice = _radius * 2.0f; OrientedBoundingBox::CreateCentered(_center, Vector3(_height + radiusTwice, radiusTwice, radiusTwice), _orientedBox); - _orientedBox.Transform(_transform); + Transform transform = _transform; + Quaternion rot; + Quaternion::Multiply(transform.Orientation, _colliderOrientation, rot); + transform.Orientation = rot; + _orientedBox.Transform(transform); _orientedBox.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); } diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.h b/Source/Engine/Physics/Colliders/CapsuleCollider.h index 5ae53cf53..210a49450 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.h +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h @@ -5,6 +5,16 @@ #include "Collider.h" #include "Engine/Core/Math/OrientedBoundingBox.h" +/// +/// The collider orientation direction. +/// +API_ENUM() enum class ColliderOrientationDirection +{ + XAxis, + YAxis, + ZAxis +}; + /// /// A capsule-shaped primitive collider. /// @@ -18,6 +28,7 @@ private: float _radius; float _height; OrientedBoundingBox _orientedBox; + ColliderOrientationDirection _direction; public: /// @@ -52,6 +63,22 @@ public: /// The capsule height will be scaled by the actor's world scale. API_PROPERTY() void SetHeight(float value); + /// + /// Gets the orientation direction of the capsule collider. + /// + /// The capsule height will be scaled by the actor's world scale. + API_PROPERTY(Attributes="EditorOrder(111), DefaultValue(typeof(ColliderOrientationDirection), \"YAxis\"), EditorDisplay(\"Collider\")") + FORCE_INLINE ColliderOrientationDirection GetDirection() const + { + return _direction; + } + + /// + /// Sets the orientation direction of the capsule collider. + /// + /// The capsule height will be scaled by the actor's world scale. + API_PROPERTY() void SetDirection(ColliderOrientationDirection value); + public: // [Collider] #if USE_EDITOR diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index 49de1f799..af8f85e9b 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -15,6 +15,7 @@ Collider::Collider(const SpawnParams& params) : PhysicsColliderActor(params) , _center(Float3::Zero) + , _colliderOrientation(Quaternion::Identity) , _isTrigger(false) , _shape(nullptr) , _staticActor(nullptr) @@ -45,11 +46,36 @@ void Collider::SetCenter(const Vector3& value) _center = value; if (_staticActor) { - PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); + Quaternion result; + Quaternion::Multiply(Quaternion::Identity, _colliderOrientation, result); + PhysicsBackend::SetShapeLocalPose(_shape, _center, result); } else if (const RigidBody* rigidBody = GetAttachedRigidBody()) { - PhysicsBackend::SetShapeLocalPose(_shape, (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(), _localTransform.Orientation); + Quaternion result; + Quaternion::Multiply(_localTransform.Orientation, _colliderOrientation, result); + PhysicsBackend::SetShapeLocalPose(_shape, (_localTransform.Translation + result * _center) * rigidBody->GetScale(), result); + } + UpdateBounds(); +} + +void Collider::SetColliderOrientation(const Quaternion& value) +{ + + if (Quaternion::NearEqual(value, _colliderOrientation)) + return; + _colliderOrientation = value; + if (_staticActor) + { + Quaternion result; + Quaternion::Multiply(Quaternion::Identity, _colliderOrientation, result); + PhysicsBackend::SetShapeLocalPose(_shape, _center, result); + } + else if (const RigidBody* rigidBody = GetAttachedRigidBody()) + { + Quaternion result; + Quaternion::Multiply(_localTransform.Orientation, _colliderOrientation, result); + PhysicsBackend::SetShapeLocalPose(_shape, (_localTransform.Translation + result * _center) * rigidBody->GetScale(), result); } UpdateBounds(); } @@ -169,8 +195,10 @@ void Collider::Attach(RigidBody* rigidBody) // Attach PhysicsBackend::AttachShape(_shape, rigidBody->GetPhysicsActor()); - _cachedLocalPosePos = (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(); - _cachedLocalPoseRot = _localTransform.Orientation; + Quaternion result; + Quaternion::Multiply(_localTransform.Orientation, _colliderOrientation, result); + _cachedLocalPosePos = (_localTransform.Translation + result * _center) * rigidBody->GetScale(); + _cachedLocalPoseRot = result; PhysicsBackend::SetShapeLocalPose(_shape, _cachedLocalPosePos, _cachedLocalPoseRot); if (rigidBody->IsDuringPlay()) { @@ -262,7 +290,9 @@ void Collider::CreateStaticActor() _staticActor = PhysicsBackend::CreateRigidStaticActor(nullptr, _transform.Translation, _transform.Orientation, scene); // Reset local pos of the shape and link it to the actor - PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); + Quaternion result; + Quaternion::Multiply(Quaternion::Identity, _colliderOrientation, result); + PhysicsBackend::SetShapeLocalPose(_shape, _center, result); PhysicsBackend::AttachShape(_shape, _staticActor); PhysicsBackend::AddSceneActor(scene, _staticActor); @@ -301,6 +331,7 @@ void Collider::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE_MEMBER(IsTrigger, _isTrigger); SERIALIZE_MEMBER(Center, _center); + SERIALIZE_MEMBER(ColliderOrientation, _colliderOrientation); SERIALIZE_MEMBER(ContactOffset, _contactOffset); SERIALIZE(Material); } @@ -312,6 +343,7 @@ void Collider::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi DESERIALIZE_MEMBER(IsTrigger, _isTrigger); DESERIALIZE_MEMBER(Center, _center); + DESERIALIZE_MEMBER(ColliderOrientation, _colliderOrientation); DESERIALIZE_MEMBER(ContactOffset, _contactOffset); DESERIALIZE(Material); } @@ -429,15 +461,19 @@ void Collider::OnTransformChanged() if (_staticActor) { - PhysicsBackend::SetRigidActorPose(_staticActor, _transform.Translation, _transform.Orientation); + Quaternion result; + Quaternion::Multiply(_localTransform.Orientation, _colliderOrientation, result); + PhysicsBackend::SetRigidActorPose(_staticActor, _transform.Translation, result); } else if (const RigidBody* rigidBody = GetAttachedRigidBody()) { - const Vector3 localPosePos = (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(); - if (_cachedLocalPosePos != localPosePos || _cachedLocalPoseRot != _localTransform.Orientation) + Quaternion result; + Quaternion::Multiply(_localTransform.Orientation, _colliderOrientation, result); + const Vector3 localPosePos = (_localTransform.Translation + result * _center) * rigidBody->GetScale(); + if (_cachedLocalPosePos != localPosePos || _cachedLocalPoseRot != result) { _cachedLocalPosePos = localPosePos; - _cachedLocalPoseRot = _localTransform.Orientation; + _cachedLocalPoseRot = result; PhysicsBackend::SetShapeLocalPose(_shape, localPosePos, _cachedLocalPoseRot); } } diff --git a/Source/Engine/Physics/Colliders/Collider.h b/Source/Engine/Physics/Colliders/Collider.h index 6b9dfcb9d..5afc5ab27 100644 --- a/Source/Engine/Physics/Colliders/Collider.h +++ b/Source/Engine/Physics/Colliders/Collider.h @@ -20,6 +20,7 @@ API_CLASS(Abstract) class FLAXENGINE_API Collider : public PhysicsColliderActor DECLARE_SCENE_OBJECT_ABSTRACT(Collider); protected: Vector3 _center; + Quaternion _colliderOrientation; bool _isTrigger; void* _shape; void* _staticActor; @@ -88,6 +89,19 @@ public: /// API_PROPERTY() void SetContactOffset(float value); + /// + /// Gets the collider's orientation, measured in the object's local space. + /// + FORCE_INLINE Quaternion GetColliderOrientation() const + { + return _colliderOrientation; + } + + /// + /// Sets the orientation of the collider, measured in the object's local space. + /// + void SetColliderOrientation(const Quaternion& value); + /// /// The physical material used to define the collider physical properties. /// From c4c55bfb612e5c7f92ade575d290f8e89c618c14 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 31 May 2023 11:28:26 -0500 Subject: [PATCH 2/2] Fix compilation errors --- .../Physics/Colliders/CapsuleCollider.cpp | 40 +++++++++---------- .../Physics/Colliders/CapsuleCollider.h | 17 ++++++-- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp index 7728e6a3e..19a44cc52 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp @@ -9,7 +9,7 @@ CapsuleCollider::CapsuleCollider(const SpawnParams& params) , _height(100.0f) , _direction(ColliderOrientationDirection::YAxis) { - SetDirection(_direction); + SetColliderDirection(_direction); } void CapsuleCollider::SetRadius(const float value) @@ -34,6 +34,24 @@ void CapsuleCollider::SetHeight(const float value) UpdateBounds(); } +void CapsuleCollider::SetColliderDirection(ColliderOrientationDirection value) +{ + _direction = value; + switch (value) + { + case ColliderOrientationDirection::XAxis: + SetColliderOrientation(Quaternion::Identity); + break; + case ColliderOrientationDirection::YAxis: + SetColliderOrientation(Quaternion::Euler(0, 0, 90)); + break; + case ColliderOrientationDirection::ZAxis: + SetColliderOrientation(Quaternion::Euler(0, 90, 0)); + break; + default: ; + } +} + #if USE_EDITOR #include "Engine/Debug/DebugDraw.h" @@ -58,24 +76,6 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view) DEBUG_DRAW_WIRE_TUBE(_transform.LocalToWorld(_center), rot, radius, height, Color::GreenYellow * 0.8f, 0, true); } -void CapsuleCollider::SetDirection(ColliderOrientationDirection value) -{ - _direction = value; - switch (value) - { - case ColliderOrientationDirection::XAxis: - SetColliderOrientation(Quaternion::Identity); - break; - case ColliderOrientationDirection::YAxis: - SetColliderOrientation(Quaternion::Euler(0, 0, 90)); - break; - case ColliderOrientationDirection::ZAxis: - SetColliderOrientation(Quaternion::Euler(0, 90, 0)); - break; - default: ; - } -} - void CapsuleCollider::OnDebugDrawSelected() { Quaternion collRot; @@ -119,7 +119,7 @@ void CapsuleCollider::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE_MEMBER(Radius, _radius); DESERIALIZE_MEMBER(Height, _height); DESERIALIZE(_direction); - SetDirection(_direction); + SetColliderDirection(_direction); } void CapsuleCollider::UpdateBounds() diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.h b/Source/Engine/Physics/Colliders/CapsuleCollider.h index 210a49450..ef910df32 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.h +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h @@ -10,8 +10,19 @@ /// API_ENUM() enum class ColliderOrientationDirection { + /// + /// Orient to the X-Axis. + /// XAxis, + + /// + /// Orient to the Y-Axis. + /// YAxis, + + /// + /// Orient to the Z-Axis. + /// ZAxis }; @@ -66,9 +77,8 @@ public: /// /// Gets the orientation direction of the capsule collider. /// - /// The capsule height will be scaled by the actor's world scale. API_PROPERTY(Attributes="EditorOrder(111), DefaultValue(typeof(ColliderOrientationDirection), \"YAxis\"), EditorDisplay(\"Collider\")") - FORCE_INLINE ColliderOrientationDirection GetDirection() const + FORCE_INLINE ColliderOrientationDirection GetColliderDirection() const { return _direction; } @@ -76,8 +86,7 @@ public: /// /// Sets the orientation direction of the capsule collider. /// - /// The capsule height will be scaled by the actor's world scale. - API_PROPERTY() void SetDirection(ColliderOrientationDirection value); + API_PROPERTY() void SetColliderDirection(ColliderOrientationDirection value); public: // [Collider]