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