My V-HACD Integration

Post Reply
User avatar
KKlouzal
Posts: 44
Joined: Thu Mar 06, 2014 5:56 am
Location: USA - Arizona

My V-HACD Integration

Post by KKlouzal » Fri Nov 29, 2019 6:46 pm

Hello, I spent the morning creating this function that takes an object containing vectors of vertices and indices, runs it through V-HACD, and spits out a btCompoundShape.

I have tested it and everything appears to be functioning properly but I would like the community experts to take a look and see if everything checks out.

When two objects collide they are a bit 'springy'. The colliding object will move slightly inside the object it collides with before being pushed out.

I'm also afraid I may have missed something or that there may be a more efficient way. Possibly the use of btConvexTriangleMeshShape is inefficient and there may be a better approach?

Code: Select all

#pragma once
#include <VHACD.h>

//
//	FBXObject contains vectors of Vertices and Indices
btCollisionShape* Decomp(FBXObject* FBX) {
	//
	//	Setup Indices
	const uint32_t nTriangles = FBX->Indices.size();
	std::vector<uint32_t> Triangles;
	for (uint32_t i = 0; i < nTriangles; i++) {
		Triangles.push_back(FBX->Indices[i]);
	}
	//
	//	Setup Points (3 Points is 1 Vertex)
	const uint32_t nPoints = FBX->Vertices.size();
	std::vector<float> Points;
	for (uint32_t i = 0; i < nPoints; i++) {
		Points.push_back(FBX->Vertices[i].pos.x);
		Points.push_back(FBX->Vertices[i].pos.y);
		Points.push_back(FBX->Vertices[i].pos.z);
	}
	//
	//	Setup VHACD Parameters and create its interface
	VHACD::IVHACD::Parameters params;
	VHACD::IVHACD* interfaceVHACD = VHACD::CreateVHACD();
	//
	//	Compute approximate convex decomposition
	bool res = interfaceVHACD->Compute(Points.data(), (uint32_t)(Points.size() / 3),
		Triangles.data(), (uint32_t)(Triangles.size() / 3), params);
	//
	//	Get the number of convex hulls
	unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
	//
	//	Iterate through each convex hull
	btAlignedObjectArray<btConvexShape*> m_convexShapes;
	btAlignedObjectArray<btTriangleMesh*> m_trimeshes;
	btAlignedObjectArray<btVector3> m_convexCentroids;
	VHACD::IVHACD::ConvexHull Hull;
	for (unsigned int h = 0; h < nConvexHulls; ++h)
	{
		//	Fill Hull for each individual convex hull
		interfaceVHACD->GetConvexHull(h, Hull);

		btAlignedObjectArray<btVector3> vertices;

		btTriangleMesh* trimesh = new btTriangleMesh();
		m_trimeshes.push_back(trimesh);
		btVector3 centroid = btVector3(0, 0, 0);
		//
		//	Calculate centroid and fill vertices
		for (unsigned int i = 0; i < Hull.m_nTriangles; i++) {
			const unsigned int index0 = Hull.m_triangles[i * 3];
			const unsigned int index1 = Hull.m_triangles[i * 3 + 1];
			const unsigned int index2 = Hull.m_triangles[i * 3 + 2];

			btVector3 vertex0(Hull.m_points[index0 * 3], Hull.m_points[index0 * 3 + 1], Hull.m_points[index0 * 3 + 2]);
			btVector3 vertex1(Hull.m_points[index1 * 3], Hull.m_points[index1 * 3 + 1], Hull.m_points[index1 * 3 + 2]);
			btVector3 vertex2(Hull.m_points[index2 * 3], Hull.m_points[index2 * 3 + 1], Hull.m_points[index2 * 3 + 2]);

			centroid += vertex0;
			centroid += vertex1;
			centroid += vertex2;

			vertices.push_back(vertex0);
			vertices.push_back(vertex1);
			vertices.push_back(vertex2);
		}
		//
		//	Offset vertices by centroid and add them to the trimesh
		for (unsigned int i = 0; i < vertices.size()/3; i++) {

			trimesh->addTriangle(vertices[i*3] - centroid, vertices[i*3 + 1] - centroid, vertices[i*3 + 2] - centroid);
		}
		//
		//	Create a new ConvexShape from our Hull
		btConvexShape* convexShape = new btConvexTriangleMeshShape(trimesh);
		m_convexShapes.push_back(convexShape);
		m_convexCentroids.push_back(centroid);
	}
	//
	//	Create a new Compound Shape
	btCompoundShape* compound = new btCompoundShape();
	//
	btTransform trans;
	trans.setIdentity();
	//
	//	Add each individual Convex Shape into our Compound Shape offset by its centroid
	for (unsigned int i = 0; i < nConvexHulls; i++)
	{
		btVector3 centroid = m_convexCentroids[i];
		trans.setOrigin(centroid);
		btConvexShape* convexShape = m_convexShapes[i];
		compound->addChildShape(trans, convexShape);
	}
	//
	// release memory
	interfaceVHACD->Clean();
	interfaceVHACD->Release();

	//	Return our Compound Shape full of Convexically Decomposed Convex Shapes
	return compound;
}
EDIT: Please see This Post for the current version of this function.
Last edited by KKlouzal on Sun Dec 01, 2019 7:50 pm, edited 1 time in total.

User avatar
KKlouzal
Posts: 44
Joined: Thu Mar 06, 2014 5:56 am
Location: USA - Arizona

Re: My V-HACD Integration

Post by KKlouzal » Fri Nov 29, 2019 6:59 pm

Well after just a few of these are created into the world, collisions make FPS drop below 15. I am reusing the collision shapes of duplicate objects to help improve bullets performance. It doesn't seem to matter with these collision shapes being used..
Image
https://i.imgur.com/VvEWwqY.mp4

User avatar
KKlouzal
Posts: 44
Joined: Thu Mar 06, 2014 5:56 am
Location: USA - Arizona

Re: My V-HACD Integration

Post by KKlouzal » Fri Nov 29, 2019 7:08 pm

Okay I mistakenly ran in debug mode. In release we have a constant 60+fps with hundreds of objects. It just goes to show though that these shapes do take a considerable more amount of computing power. I never had slowdowns like that in debug mode using basic collision shapes. I'm sure the complexity of the underlying trimesh will also play a major factor in determining performance with these objects.
Image
It leaves me wondering even more now if there is anything I can do to improve performance of these objects.

User avatar
KKlouzal
Posts: 44
Joined: Thu Mar 06, 2014 5:56 am
Location: USA - Arizona

Re: My V-HACD Integration

Post by KKlouzal » Sun Dec 01, 2019 3:36 pm

So there was an issue computing the center of mass. V-HACD computes the center position for each convex hull during decomposition. I have greatly reduced the complexity of reading decomp results and here is the resulting code:

Code: Select all

#pragma once
#include <VHACD.h>

//
//	Structure containing objects created during composition
struct DecompResults {
	btCompoundShape* CompoundShape = nullptr;
	btAlignedObjectArray<btConvexShape*> m_convexShapes = {};
	btAlignedObjectArray<btTriangleMesh*> m_trimeshes = {};
};

//
//	FBXObject contains vectors of Vertices and Indices
DecompResults* Decomp(FBXObject* FBX) {
	//
	//	Setup Indices
	const uint32_t nTriangles = FBX->Indices.size();
	std::vector<uint32_t> Triangles;
	for (uint32_t i = 0; i < nTriangles; i++) {
		Triangles.push_back(FBX->Indices[i]);
	}
	//
	//	Setup Points (3 Points is 1 Vertex)
	const uint32_t nPoints = FBX->Vertices.size();
	std::vector<float> Points;
	for (uint32_t i = 0; i < nPoints; i++) {
		Points.push_back(FBX->Vertices[i].pos.x);
		Points.push_back(FBX->Vertices[i].pos.y);
		Points.push_back(FBX->Vertices[i].pos.z);
	}
	//
	//	Setup VHACD Parameters and create its interface
	VHACD::IVHACD::Parameters params;
	VHACD::IVHACD* interfaceVHACD = VHACD::CreateVHACD();
	VHACD::IVHACD::ConvexHull Hull;
	//
	//	Compute approximate convex decomposition
	//printf("Compute V-HACD: Points %i Triangles %i\n", Points.size(), Triangles.size());
	bool res = interfaceVHACD->Compute(Points.data(), (uint32_t)(Points.size() / 3),
		Triangles.data(), (uint32_t)(Triangles.size() / 3), params);
	//
	//	Get the number of convex hulls
	unsigned int nConvexHulls = interfaceVHACD->GetNConvexHulls();
	//printf("V-HACD Done: Hull Count %i\n", nConvexHulls);
	//
	//	Create a new DecompResults structure
	DecompResults* Results = new DecompResults;
	//
	//	Create a new Compound Shape for this decomposition
	Results->CompoundShape = new btCompoundShape();
	//
	//	Iterate through each convex hull and fill results
	for (unsigned int h = 0; h < nConvexHulls; ++h)
	{
		//printf("\tHull: %i\n", h);
		//printf("\t\tPoints: %i\n", Hull.m_points);
		//printf("\t\tTriangles: %i\n", Hull.m_triangles);
		//printf("\t\tVertices: %i\n", vertices.size());
		//
		//	Fill 'Hull' for each individual convex hull
		interfaceVHACD->GetConvexHull(h, Hull);
		//
		//	Create a new Triangle Mesh for this hull
		btTriangleMesh* trimesh = new btTriangleMesh();
		Results->m_trimeshes.push_back(trimesh);
		//
		//	Grab the hulls center position
		const btVector3 centroid(Hull.m_center[0], Hull.m_center[1], Hull.m_center[2]);
		printf("Hull Center %f %f %f\n", Hull.m_center[0], Hull.m_center[1], Hull.m_center[2]);
		//
		//	Iterate through this hulls triangles
		for (unsigned int i = 0; i < Hull.m_nTriangles; i++) {
			//
			//	Calculate indices
			const unsigned int index0 = Hull.m_triangles[i * 3];
			const unsigned int index1 = Hull.m_triangles[i * 3 + 1];
			const unsigned int index2 = Hull.m_triangles[i * 3 + 2];
			//
			//	Calculate vertices
			const btVector3 vertex0(Hull.m_points[index0 * 3], Hull.m_points[index0 * 3 + 1], Hull.m_points[index0 * 3 + 2]);
			const btVector3 vertex1(Hull.m_points[index1 * 3], Hull.m_points[index1 * 3 + 1], Hull.m_points[index1 * 3 + 2]);
			const btVector3 vertex2(Hull.m_points[index2 * 3], Hull.m_points[index2 * 3 + 1], Hull.m_points[index2 * 3 + 2]);
			//
			//	Add this triangle into our Triangle Mesh
			trimesh->addTriangle(vertex0 - centroid, vertex1 - centroid, vertex2 - centroid);
		}
		//
		//	Create a new ConvexShape from this hulls Triangle Mesh
		btConvexShape* convexShape = new btConvexTriangleMeshShape(trimesh);
		Results->m_convexShapes.push_back(convexShape);
		//
		//	Create a transform using centroid as origin
		btTransform trans;
		trans.setIdentity();
		trans.setOrigin(centroid);
		//
		//	Add this ConvexShape to our CompoundShape
		Results->CompoundShape->addChildShape(trans, convexShape);
	}
	//
	// release memory
	interfaceVHACD->Clean();
	interfaceVHACD->Release();
	//
	//	Return our DecompResults containing the CompoundShape full of Convexically Decomposed Convex Shapes
	return Results;
}
The function now returns a 'DecompResults' structure containing all objects created during the processing of our V-HACD results so the user can appropriately use them in their application and delete them when necessary.

Post Reply