diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp index 4bf135060..3e3ca0aff 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp @@ -6,7 +6,9 @@ CapsuleCollider::CapsuleCollider(const SpawnParams& params) : Collider(params) , _radius(20.0f) , _height(100.0f) + , _direction(ColliderOrientationDirection::YAxis) { + SetColliderDirection(_direction); } void CapsuleCollider::SetRadius(const float value) @@ -31,6 +33,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" @@ -41,8 +61,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 rotation; - Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rotation); + Quaternion::Multiply(_transform.Orientation, collRot, rotation); const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize); @@ -55,8 +77,10 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view) void CapsuleCollider::OnDebugDrawSelected() { + Quaternion collRot; + Quaternion::Multiply( _colliderOrientation, Quaternion::Euler(0, 90, 0), collRot); Quaternion rotation; - Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rotation); + Quaternion::Multiply(_transform.Orientation, collRot, rotation); const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize); @@ -85,7 +109,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 60526750c..ed96cc168 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.h +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h @@ -5,6 +5,27 @@ #include "Collider.h" #include "Engine/Core/Math/OrientedBoundingBox.h" +/// +/// The collider orientation direction. +/// +API_ENUM() enum class ColliderOrientationDirection +{ + /// + /// Orient to the X-Axis. + /// + XAxis, + + /// + /// Orient to the Y-Axis. + /// + YAxis, + + /// + /// Orient to the Z-Axis. + /// + ZAxis +}; + /// /// A capsule-shaped primitive collider. /// @@ -19,6 +40,7 @@ private: float _radius; float _height; OrientedBoundingBox _orientedBox; + ColliderOrientationDirection _direction; public: /// @@ -53,6 +75,20 @@ 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. + /// + API_PROPERTY(Attributes="EditorOrder(111), DefaultValue(typeof(ColliderOrientationDirection), \"YAxis\"), EditorDisplay(\"Collider\")") + FORCE_INLINE ColliderOrientationDirection GetColliderDirection() const + { + return _direction; + } + + /// + /// Sets the orientation direction of the capsule collider. + /// + API_PROPERTY() void SetColliderDirection(ColliderOrientationDirection value); + public: // [Collider] #if USE_EDITOR diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index 1ad6b4946..844030e32 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -14,6 +14,7 @@ Collider::Collider(const SpawnParams& params) : PhysicsColliderActor(params) , _center(Float3::Zero) + , _colliderOrientation(Quaternion::Identity) , _isTrigger(false) , _shape(nullptr) , _staticActor(nullptr) @@ -44,11 +45,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(); } @@ -168,8 +194,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()) { @@ -261,7 +289,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); @@ -404,15 +434,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 a2e115dcc..29a6752ad 100644 --- a/Source/Engine/Physics/Colliders/Collider.h +++ b/Source/Engine/Physics/Colliders/Collider.h @@ -21,6 +21,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; @@ -77,6 +78,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. ///