Files
FlaxEngine/Source/Engine/Physics/Colliders/CapsuleCollider.cpp
2021-01-02 14:28:49 +01:00

157 lines
4.2 KiB
C++

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "CapsuleCollider.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Physics/Utilities.h"
#include <ThirdParty/PhysX/PxShape.h>
#if USE_EDITOR
#include "Engine/Level/Scene/SceneRendering.h"
#endif
CapsuleCollider::CapsuleCollider(const SpawnParams& params)
: Collider(params)
, _radius(20.0f)
, _height(100.0f)
{
}
void CapsuleCollider::SetRadius(const float value)
{
if (Math::NearEqual(value, _radius))
return;
_radius = value;
UpdateGeometry();
UpdateBounds();
}
void CapsuleCollider::SetHeight(const float value)
{
if (Math::NearEqual(value, _height))
return;
_height = value;
UpdateGeometry();
UpdateBounds();
}
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
void CapsuleCollider::DrawPhysicsDebug(RenderView& view)
{
Quaternion rot;
Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rot);
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
DEBUG_DRAW_WIRE_TUBE(_transform.LocalToWorld(_center), rot, radius, height, Color::GreenYellow * 0.8f, 0, true);
}
void CapsuleCollider::OnDebugDrawSelected()
{
Quaternion rot;
Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rot);
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
DEBUG_DRAW_WIRE_TUBE(_transform.LocalToWorld(_center), rot, radius, height, Color::GreenYellow, 0, false);
// Base
Collider::OnDebugDrawSelected();
}
#endif
bool CapsuleCollider::IntersectsItself(const Ray& ray, float& distance, Vector3& normal)
{
return _orientedBox.Intersects(ray, distance, normal);
}
void CapsuleCollider::Serialize(SerializeStream& stream, const void* otherObj)
{
// Base
Collider::Serialize(stream, otherObj);
SERIALIZE_GET_OTHER_OBJ(CapsuleCollider);
SERIALIZE_MEMBER(Radius, _radius);
SERIALIZE_MEMBER(Height, _height);
}
void CapsuleCollider::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
// Base
Collider::Deserialize(stream, modifier);
DESERIALIZE_MEMBER(Radius, _radius);
DESERIALIZE_MEMBER(Height, _height);
}
#if USE_EDITOR
void CapsuleCollider::OnEnable()
{
GetSceneRendering()->AddPhysicsDebug<CapsuleCollider, &CapsuleCollider::DrawPhysicsDebug>(this);
// Base
Collider::OnEnable();
}
void CapsuleCollider::OnDisable()
{
GetSceneRendering()->RemovePhysicsDebug<CapsuleCollider, &CapsuleCollider::DrawPhysicsDebug>(this);
// Base
Collider::OnDisable();
}
#endif
void CapsuleCollider::UpdateBounds()
{
// Cache bounds
const float radiusTwice = _radius * 2.0f;
OrientedBoundingBox::CreateCentered(_center, Vector3(_height + radiusTwice, radiusTwice, radiusTwice), _orientedBox);
_orientedBox.Transform(_transform.GetWorld());
_orientedBox.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
}
void CapsuleCollider::CreateShape()
{
// Setup shape geometry
_cachedScale = GetScale();
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
const PxCapsuleGeometry geometry(radius, height * 0.5f);
// Setup shape
CreateShapeBase(geometry);
}
void CapsuleCollider::UpdateGeometry()
{
// Check if has no shape created
if (_shape == nullptr)
return;
// Setup shape geometry
_cachedScale = GetScale();
const float scaling = _cachedScale.GetAbsolute().MaxValue();
const float minSize = 0.001f;
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
const PxCapsuleGeometry geometry(radius, height * 0.5f);
// Setup shape
_shape->setGeometry(geometry);
}