// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "CapsuleCollider.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Physics/Utilities.h" #include #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(this); // Base Collider::OnEnable(); } void CapsuleCollider::OnDisable() { GetSceneRendering()->RemovePhysicsDebug(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); }