summaryrefslogtreecommitdiff
path: root/Runtime/Dynamics/TerrainCollider.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Dynamics/TerrainCollider.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Dynamics/TerrainCollider.cpp')
-rw-r--r--Runtime/Dynamics/TerrainCollider.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/Runtime/Dynamics/TerrainCollider.cpp b/Runtime/Dynamics/TerrainCollider.cpp
new file mode 100644
index 0000000..67a82a0
--- /dev/null
+++ b/Runtime/Dynamics/TerrainCollider.cpp
@@ -0,0 +1,238 @@
+#include "UnityPrefix.h"
+
+#if ENABLE_TERRAIN && ENABLE_PHYSICS
+#include "TerrainCollider.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Dynamics/PhysicsManager.h"
+
+///@TODO: THis should really only be ITerrain
+#include "Runtime/Terrain/TerrainData.h"
+#include "Runtime/Terrain/Heightmap.h"
+#include "Runtime/Interfaces/ITerrainManager.h"
+
+#include "Runtime/Dynamics/CapsuleCollider.h"
+#include "Runtime/BaseClasses/IsPlaying.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/BaseClasses/SupportedMessageOptimization.h"
+#include "Runtime/Dynamics/NxWrapperUtility.h"
+
+inline UInt32 GetLowMaterialIndex (UInt32 index)
+{
+ return index & 0x7F;
+}
+
+inline UInt32 GetHighMaterialIndex (UInt32 index)
+{
+ return index >> 7;
+}
+
+
+IMPLEMENT_CLASS_HAS_INIT(TerrainCollider)
+IMPLEMENT_OBJECT_SERIALIZE(TerrainCollider)
+
+TerrainCollider::TerrainCollider (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+, m_Node (this)
+{
+ m_CreateTreeColliders = true;
+ m_CachedInvSize = Vector3f(1.0F, 1.0F, 1.0F);
+}
+
+TerrainCollider::~TerrainCollider ()
+{
+}
+
+void TerrainCollider::SetTerrainData (PPtr<TerrainData> map)
+{
+ if (m_TerrainData != map)
+ {
+ m_TerrainData = map;
+ Create(NULL);
+ SetDirty();
+ }
+}
+
+TerrainData* TerrainCollider::GetTerrainData ()
+{
+ return m_TerrainData;
+}
+
+void TerrainCollider::Cleanup ()
+{
+ Super::Cleanup();
+
+ for (int i=0;i<m_TreeColliders.size();i++)
+ GetDynamicsScene ().releaseActor (m_TreeColliders[i]->getActor());
+ m_TreeColliders.clear();
+
+ m_Node.RemoveFromList();
+}
+
+void TerrainCollider::Create (const Rigidbody* ignoreAttachRigidbody)
+{
+ Cleanup ();
+
+ if (!GetTerrainData())
+ return;
+
+ ITerrainManager* terrainManager = GetITerrainManager();
+
+ //////@TODO: Make this more directly just return the physx representation...
+
+ Heightmap* map = &GetTerrainData()->GetHeightmap();
+ if (map == NULL || terrainManager->Heightmap_GetNxHeightField(*map) == NULL)
+ return;
+
+ NxHeightFieldShapeDesc desc;
+ desc.heightField = terrainManager->Heightmap_GetNxHeightField(*map);
+
+ if (desc.heightField == NULL)
+ return;
+
+ m_CachedInvSize = Inverse(terrainManager->Heightmap_GetSize(*map));
+ Vector3f mapScale = map->GetScale ();
+ desc.heightScale = mapScale.y / (float)(Heightmap::kMaxHeight);
+ desc.columnScale = mapScale.z;
+ desc.rowScale = mapScale.x;
+ desc.holeMaterial = 1;
+
+ // Smooth sphere collisions on terrains are much better!
+ if (IS_CONTENT_NEWER_OR_SAME(kUnityVersion3_2_a1))
+ desc.meshFlags = NX_MESH_SMOOTH_SPHERE_COLLISIONS;
+
+ desc.materialIndexHighBits = GetHighMaterialIndex(terrainManager->Heightmap_GetMaterialIndex(*map));
+ FinalizeCreate(desc, true, ignoreAttachRigidbody);
+
+ if (m_Shape)
+ {
+ // Insert into front of terrain colliders. Create() may be called from inside
+ // of RecreateColliders, and inserting to back will result in eternal loop.
+ Heightmap::TerrainColliderList& colliders = map->GetTerrainColliders();
+ colliders.insert(colliders.begin(), m_Node);
+ }
+
+ // Dont create trees in edit mode,its too slow to recreate all those trees when adding new trees
+ if (m_CreateTreeColliders && IsWorldPlaying())
+ CreateTrees();
+}
+
+void TerrainCollider::CreateTrees ()
+{
+ const float kMinSize = 0.00001F;
+ int prototypeCount = m_TerrainData->GetTreeDatabase().GetTreePrototypes().size();
+ const TreePrototype* prototypes = prototypeCount > 0 ? &m_TerrainData->GetTreeDatabase().GetTreePrototypes()[0] : NULL;
+
+ int instanceCount = m_TerrainData->GetTreeDatabase().GetInstances().size();
+ const TreeInstance* instances = instanceCount > 0 ? &m_TerrainData->GetTreeDatabase().GetInstances()[0] : NULL;
+
+
+ int supportedMessages = GetGameObject ().GetSupportedMessages ();
+
+ NxActorDesc actorDesc;
+ NxCapsuleShapeDesc shapeDesc;
+ actorDesc.userData = NULL;
+ actorDesc.shapes.push_back (&shapeDesc);
+ shapeDesc.materialIndex = GetMaterialIndex ();
+
+ if (supportedMessages & kHasCollisionStay)
+ actorDesc.group = kContactTouchGroup;
+ else if (supportedMessages & (kHasCollisionStay | kHasCollisionEnterExit))
+ actorDesc.group = kContactEnterExitGroup;
+ else
+ actorDesc.group = kContactNothingGroup;
+ shapeDesc.userData = this;
+ shapeDesc.group = GetGameObject ().GetLayer ();
+
+ Vector3f terrainPositionOffset = GetComponent(Transform).GetPosition();
+
+ Vector3f scale = GetITerrainManager()->Heightmap_GetSize(m_TerrainData->GetHeightmap());
+ NxMat33 id33;
+ id33.id();
+ for (int i=0;i<instanceCount;i++)
+ {
+ const TreeInstance& instance = instances[i];
+
+ if (instance.index >= prototypeCount)
+ {
+ ErrorString("Prototype for tree missing.");
+ continue;
+ }
+
+ const TreePrototype& proto = prototypes[instance.index];
+ Vector3f pos = Scale(scale, instance.position) + terrainPositionOffset;;
+ GameObject* prefab = proto.prefab;
+ if (prefab == NULL)
+ continue;
+ CapsuleCollider* capsule = prefab->QueryComponent(CapsuleCollider);
+ if (capsule == NULL)
+ continue;
+
+ float absoluteHeight = max (Abs (capsule->GetHeight() * instance.heightScale), kMinSize);
+ float absoluteRadius = Abs (instance.widthScale) * capsule->GetRadius();
+
+ float height = absoluteHeight - absoluteRadius * 2.0F;
+
+ height = max (height, kMinSize);
+ absoluteRadius = max (absoluteRadius, kMinSize);
+
+ shapeDesc.height = height;
+ shapeDesc.radius = absoluteRadius;
+ shapeDesc.group = prefab->GetLayer();
+
+ pos += Scale(capsule->GetCenter(), Vector3f(instance.widthScale, instance.heightScale, instance.widthScale));
+
+ actorDesc.globalPose = NxMat34(id33, Vec3ToNx(pos ));
+
+ NxActor* actor = GetDynamicsScene ().createActor (actorDesc);
+ if (actor == NULL)
+ {
+ ErrorString ("Could not create tree colliders. Maybe there are more Trees then PhysX can handle?");
+ for (int i=0;i<m_TreeColliders.size();i++)
+ GetDynamicsScene ().releaseActor (m_TreeColliders[i]->getActor());
+ m_TreeColliders.clear();
+ return;
+ }
+ NxShape* shape = actor->getShapes ()[0];
+
+ m_TreeColliders.push_back(shape);
+ }
+}
+
+template<class TransferFunc>
+void TerrainCollider::Transfer (TransferFunc& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.Align();
+ TRANSFER(m_TerrainData);
+ TRANSFER(m_CreateTreeColliders);
+}
+
+void TerrainCollider::FetchPoseFromTransform ()
+{
+ NxQuat quat; quat.id();
+ Vector3f pos = GetComponent(Transform).GetPosition();
+ NxMat34 shapeMatrix (quat, (const NxVec3&)pos);
+
+ m_Shape->setGlobalPose(shapeMatrix);
+}
+
+void TerrainCollider::InitializeClass ()
+{
+ REGISTER_MESSAGE (TerrainCollider, kTerrainChanged, TerrainChanged, int);
+}
+
+void TerrainCollider::TransformChanged (int changeMask)
+{
+ Super::TransformChanged(changeMask);
+
+ if (m_Shape)
+ FetchPoseFromTransform ();
+}
+
+void TerrainCollider::TerrainChanged (int changeMask)
+{
+ if (changeMask == TerrainData::kWillBeDestroyed)
+ Cleanup();
+}
+#endif