Browse Source

Add mesh collider support

Daniele Bartolini 9 years ago
parent
commit
efdff7a154
2 changed files with 69 additions and 9 deletions
  1. 32 3
      src/resource/physics_resource.cpp
  2. 37 6
      src/world/physics_world_bullet.cpp

+ 32 - 3
src/resource/physics_resource.cpp

@@ -169,6 +169,14 @@ namespace physics_resource
 		JsonArray positions(ta);
 		sjson::parse_array(geometry["position"], positions);
 
+		JsonObject indices(ta);
+		JsonArray indices_data(ta);
+		JsonArray position_indices(ta);
+		sjson::parse_object(geometry["indices"], indices);
+		sjson::parse_array(indices["data"], indices_data);
+		sjson::parse_array(indices_data[0], position_indices);
+
+
 		Array<Vector3> points(default_allocator());
 		for (u32 i = 0; i < array::size(positions); i += 3)
 		{
@@ -179,13 +187,19 @@ namespace physics_resource
 			array::push_back(points, p*matrix_local);
 		}
 
+		Array<u16> point_indices(default_allocator());
+		for (u32 i = 0; i < array::size(position_indices); ++i)
+		{
+			array::push_back(point_indices, (u16)sjson::parse_int(position_indices[i]));
+		}
+
 		switch (cd.type)
 		{
 			case ColliderType::SPHERE:      compile_sphere(points, cd); break;
 			case ColliderType::CAPSULE:     compile_capsule(points, cd); break;
 			case ColliderType::BOX:         compile_box(points, cd); break;
 			case ColliderType::CONVEX_HULL: break;
-			case ColliderType::MESH:
+			case ColliderType::MESH:        break;
 			case ColliderType::HEIGHTFIELD:
 			{
 				RESOURCE_COMPILER_ASSERT(false, opts, "Not implemented yet");
@@ -193,13 +207,28 @@ namespace physics_resource
 			}
 		}
 
-		cd.size = cd.type == ColliderType::CONVEX_HULL ? sizeof(Vector3)*array::size(points) : 0;
+		const u32 num_points  = array::size(points);
+		const u32 num_indices = array::size(point_indices);
+
+		const bool needs_points = cd.type == ColliderType::CONVEX_HULL
+			|| cd.type == ColliderType::MESH;
+
+		cd.size += (needs_points ? sizeof(u32) + sizeof(Vector3)*array::size(points) : 0);
+		cd.size += (cd.type == ColliderType::MESH ? sizeof(u32) + sizeof(u16)*array::size(point_indices) : 0);
 
 		Buffer buf(default_allocator());
 		array::push(buf, (char*)&cd, sizeof(cd));
 
-		if (cd.type == ColliderType::CONVEX_HULL)
+		if (needs_points)
+		{
+			array::push(buf, (char*)&num_points, sizeof(num_points));
 			array::push(buf, (char*)array::begin(points), sizeof(Vector3)*array::size(points));
+		}
+		if (cd.type == ColliderType::MESH)
+		{
+			array::push(buf, (char*)&num_indices, sizeof(num_indices));
+			array::push(buf, (char*)array::begin(point_indices), sizeof(u16)*array::size(point_indices));
+		}
 
 		return buf;
 	}

+ 37 - 6
src/world/physics_world_bullet.cpp

@@ -22,6 +22,7 @@
 #include "unit_manager.h"
 #include "vector3.h"
 #include <btBoxShape.h>
+#include <btBvhTriangleMeshShape.h>
 #include <btCapsuleShape.h>
 #include <btCollisionObject.h>
 #include <btCompoundShape.h>
@@ -211,6 +212,7 @@ public:
 
 		for (u32 i = 0; i < array::size(_collider); ++i)
 		{
+			CE_DELETE(*_allocator, _collider[i].vertex_array);
 			CE_DELETE(*_allocator, _collider[i].shape);
 		}
 
@@ -219,6 +221,7 @@ public:
 
 	ColliderInstance create_collider(UnitId id, const ColliderDesc* sd)
 	{
+		btTriangleIndexVertexArray* vertex_array = NULL;
 		btCollisionShape* child_shape = NULL;
 
 		switch(sd->type)
@@ -234,12 +237,38 @@ public:
 				break;
 			case ColliderType::CONVEX_HULL:
 			{
-				const u32 num = sd->size / sizeof(Vector3);
-				const btScalar* points = (const btScalar*)&sd[1];
+				const char* data       = (char*)&sd[1];
+				const u32 num          = *(u32*)data;
+				const btScalar* points = (btScalar*)(data + sizeof(u32));
+
 				child_shape = CE_NEW(*_allocator, btConvexHullShape)(points, (int)num, sizeof(Vector3));
 				break;
 			}
 			case ColliderType::MESH:
+			{
+				const char* data      = (char*)&sd[1];
+				const u32 num_points  = *(u32*)data;
+				const char* points    = data + sizeof(u32);
+				const u32 num_indices = *(u32*)(points + num_points*sizeof(Vector3));
+				const char* indices   = points + sizeof(u32) + num_points*sizeof(Vector3);
+
+				btIndexedMesh part;
+				part.m_vertexBase          = (const unsigned char*)points;
+				part.m_vertexStride        = sizeof(Vector3);
+				part.m_numVertices         = num_points;
+				part.m_triangleIndexBase   = (const unsigned char*)indices;
+				part.m_triangleIndexStride = sizeof(u16)*3;
+				part.m_numTriangles        = num_indices/3;
+				part.m_indexType           = PHY_SHORT;
+
+				vertex_array = CE_NEW(*_allocator, btTriangleIndexVertexArray)();
+				vertex_array->addIndexedMesh(part, PHY_SHORT);
+
+				const btVector3 aabb_min(-1000.0f,-1000.0f,-1000.0f);
+				const btVector3 aabb_max(1000.0f,1000.0f,1000.0f);
+				child_shape = CE_NEW(*_allocator, btBvhTriangleMeshShape)(vertex_array, false, aabb_min, aabb_max);
+				break;
+			}
 			case ColliderType::HEIGHTFIELD:
 			{
 				CE_FATAL("Not implemented yet");
@@ -255,10 +284,11 @@ public:
 		const u32 last = array::size(_collider);
 
 		ColliderInstanceData cid;
-		cid.unit     = id;
-		cid.local_tm = sd->local_tm;
-		cid.shape    = child_shape;
-		cid.next.i   = UINT32_MAX;
+		cid.unit         = id;
+		cid.local_tm     = sd->local_tm;
+		cid.vertex_array = vertex_array;
+		cid.shape        = child_shape;
+		cid.next.i       = UINT32_MAX;
 
 		ColliderInstance ci = first_collider(id);
 		while (is_valid(ci) && is_valid(next_collider(ci)))
@@ -950,6 +980,7 @@ private:
 	{
 		UnitId unit;
 		Matrix4x4 local_tm;
+		btTriangleIndexVertexArray* vertex_array;
 		btCollisionShape* shape;
 		ColliderInstance next;
 	};