summaryrefslogtreecommitdiff
path: root/Runtime/Dynamics/SphereCollider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Dynamics/SphereCollider.cpp')
-rw-r--r--Runtime/Dynamics/SphereCollider.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/Runtime/Dynamics/SphereCollider.cpp b/Runtime/Dynamics/SphereCollider.cpp
new file mode 100644
index 0000000..9bd05cb
--- /dev/null
+++ b/Runtime/Dynamics/SphereCollider.cpp
@@ -0,0 +1,272 @@
+#include "UnityPrefix.h"
+#if ENABLE_PHYSICS
+#include "SphereCollider.h"
+#include "Runtime/Graphics/Transform.h"
+#include "RigidBody.h"
+#include "PhysicsManager.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Filters/AABBUtility.h"
+#include "External/PhysX/builds/SDKs/Physics/include/NxPhysics.h"
+#include "Runtime/Misc/BuildSettings.h"
+
+#define GET_SHAPE() ((class NxSphereShape*)m_Shape)
+
+using namespace std;
+
+SphereCollider::SphereCollider (MemLabelId label, ObjectCreationMode mode)
+ : Super(label, mode)
+{
+ #if UNITY_EDITOR
+ fixupSphereColliderBackwardsCompatibility = false;
+ #endif
+}
+
+SphereCollider::~SphereCollider ()
+{
+}
+
+void SphereCollider::AwakeFromLoad(AwakeFromLoadMode awakeMode)
+{
+ if (m_Shape)
+ {
+ // Apply changed values
+ SetRadius (m_Radius);
+ SetCenter (m_Center);
+ }
+
+ Super::AwakeFromLoad (awakeMode);
+
+ #if UNITY_EDITOR
+ if (fixupSphereColliderBackwardsCompatibility)
+ {
+ float oldRadius = m_Radius;
+ m_Radius = 1.0F;
+ if (GetScaledRadius () > 0.001)
+ {
+ SetRadius (oldRadius / GetScaledRadius ());
+ }
+ fixupSphereColliderBackwardsCompatibility = false;
+ }
+ #endif
+}
+
+void SphereCollider::SmartReset ()
+{
+ Super::Reset ();
+ AABB aabb;
+ if (GetGameObjectPtr () && CalculateLocalAABB (GetGameObject (), &aabb))
+ {
+ Vector3f dist = aabb.GetExtent ();
+ float longestAxis = max (dist.x, dist.y);
+ longestAxis = max (longestAxis, dist.z);
+ SetRadius (longestAxis);
+ SetCenter (aabb.GetCenter ());
+ }
+ else
+ {
+ SetRadius (0.5F);
+ SetCenter (Vector3f::zero);
+ }
+}
+
+void SphereCollider::Reset ()
+{
+ Super::Reset ();
+ m_Radius = 0.5F;
+ m_Center = Vector3f::zero;
+}
+
+float SphereCollider::GetScaledRadius () const
+{
+ Vector3f scale = GetComponent (Transform).GetWorldScaleLossy ();
+ float absoluteRadius = max (max (Abs (scale.x), Abs (scale.y)), Abs (scale.z)) * m_Radius;
+ absoluteRadius = Abs (absoluteRadius);
+ absoluteRadius = max (absoluteRadius, 0.00001F);
+ return absoluteRadius;
+}
+
+void SphereCollider::SetRadius (float radius)
+{
+ if (m_Radius != radius)
+ {
+ SetDirty ();
+ m_Radius = radius;
+ }
+
+ PROFILE_MODIFY_STATIC_COLLIDER
+
+ if (GET_SHAPE ())
+ {
+ GET_SHAPE ()->setRadius (GetScaledRadius ());
+ RigidbodyMassDistributionChanged ();
+ RefreshPhysicsInEditMode();
+ UpdateCCDSkeleton ();
+ }
+}
+
+
+void SphereCollider::SetCenter (const Vector3f& center)
+{
+ if (m_Center != center)
+ {
+ m_Center = center;
+ SetDirty ();
+ }
+
+ if (GET_SHAPE ())
+ TransformChanged (Transform::kRotationChanged | Transform::kPositionChanged | kForceUpdateMass);
+}
+
+Vector3f SphereCollider::GetGlobalCenter () const
+{
+ return GetComponent (Transform).TransformPoint (m_Center);
+}
+
+void SphereCollider::Create (const Rigidbody* ignoreRigidbody)
+{
+ if (m_Shape)
+ Cleanup ();
+
+ NxSphereShapeDesc shapeDesc;
+ shapeDesc.radius = GetScaledRadius ();
+
+ FinalizeCreate (shapeDesc, true, ignoreRigidbody);
+}
+
+void SphereCollider::FetchPoseFromTransform ()
+{
+ FetchPoseFromTransformUtility (m_Center);
+}
+
+bool SphereCollider::GetRelativeToParentPositionAndRotation (Transform& transform, Transform& anyParent, Matrix4x4f& matrix)
+{
+ return GetRelativeToParentPositionAndRotationUtility (transform, anyParent, m_Center, matrix);
+}
+
+void SphereCollider::ScaleChanged ()
+{
+ GET_SHAPE ()->setRadius (GetScaledRadius ());
+ UpdateCCDSkeleton ();
+}
+
+void SphereCollider::TransformChanged (int changeMask)
+{
+ Super::TransformChanged (changeMask);
+ if (m_Shape)
+ {
+ if (!m_Shape->getActor ().userData)
+ {
+ PROFILER_AUTO(gStaticColliderMove, this)
+ FetchPoseFromTransformUtility (m_Center);
+ }
+ else
+ {
+ Rigidbody* body = (Rigidbody*)m_Shape->getActor ().userData;
+ Matrix4x4f matrix;
+ if (GetRelativeToParentPositionAndRotationUtility (GetComponent (Transform), body->GetComponent (Transform), m_Center, matrix))
+ {
+ NxMat34 shapeMatrix;
+ shapeMatrix.setColumnMajor44 (matrix.GetPtr ());
+ m_Shape->setLocalPose (shapeMatrix);
+ }
+
+ if (body->GetGameObjectPtr() != GetGameObjectPtr() || changeMask & (Transform::kScaleChanged | kForceUpdateMass))
+ RigidbodyMassDistributionChanged ();
+ }
+
+ if (changeMask & Transform::kScaleChanged)
+ ScaleChanged ();
+
+ RefreshPhysicsInEditMode();
+ }
+}
+
+AABB SphereCollider::GetBounds ()
+{
+ if (m_Shape)
+ {
+ // AABB reported by PhysX is inaccurate, as PhysX will just transform the local AABB.
+ // For Spheres it's very easy to do better.
+ float globalRadius = GetScaledRadius();
+ return AABB(GetGlobalCenter(), Vector3f(globalRadius, globalRadius, globalRadius));
+ }
+ else
+ return Super::GetBounds ();
+}
+
+NxCCDSkeleton* SphereCollider::CreateCCDSkeleton(float scale)
+{
+ // This is a very simple "approximation" of a sphere, of only 6 vertices.
+ // Since CCD only kicks in when normal collisions fail, any is probably mostly
+ // interesting for small objects (as those tend to move faster), I believe that this
+ // is a reasonable choice for common expected use. NVidia even recommends using
+ // single vertex meshes for very small objects.
+ float radius = scale;
+ if (IS_CONTENT_NEWER_OR_SAME(kUnityVersion4_0_a1))
+ radius *= GetScaledRadius();
+ else
+ // Prior to 4.0 we incorrectly ignored object scale here. Keep this behaviour for backwards compatibility.
+ radius *= m_Radius;
+
+ NxU32 triangles[3 * 8] = {
+ 0,1,2,
+ 0,2,3,
+ 0,3,4,
+ 0,4,1,
+ 5,2,1,
+ 5,3,2,
+ 5,4,3,
+ 5,1,4,
+ };
+
+ NxVec3 points[6];
+
+ // Static mesh
+ points[0].set( 0, -radius, 0);
+ points[1].set( -radius, 0, 0);
+ points[2].set( 0, 0, -radius);
+ points[3].set( radius, 0, 0);
+ points[4].set( 0, 0, radius);
+ points[5].set( 0, radius, 0);
+
+ if (!IS_CONTENT_NEWER_OR_SAME(kUnityVersion4_0_a1))
+ {
+ // This is wrong, as the m_Center transformation is already applied at the shape matrix.
+ // Keep for backward compatibility.
+ NxVec3 center(m_Center.x, m_Center.y, m_Center.z);
+ for (int i=0;i<6;i++)
+ points[i] += center;
+ }
+
+ NxSimpleTriangleMesh stm;
+ stm.numVertices = 6;
+ stm.numTriangles = 8;
+ stm.pointStrideBytes = sizeof(NxVec3);
+ stm.triangleStrideBytes = sizeof(NxU32)*3;
+
+ stm.points = points;
+ stm.triangles = triangles;
+ return GetDynamicsSDK().createCCDSkeleton(stm);
+}
+
+template<class TransferFunction>
+void SphereCollider::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.SetVersion (2);
+
+ transfer.Align();
+
+ #if UNITY_EDITOR
+ fixupSphereColliderBackwardsCompatibility = transfer.IsOldVersion (1);
+ #endif
+
+ TRANSFER_SIMPLE (m_Radius);
+ TRANSFER (m_Center);
+}
+
+IMPLEMENT_CLASS (SphereCollider)
+IMPLEMENT_OBJECT_SERIALIZE (SphereCollider)
+
+#undef GET_SHAPE
+#endif //ENABLE_PHYSICS \ No newline at end of file