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. ///