Creating non-rectangular shapes w/ >4 sides

bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

Hi all. I have what I think should be an easy question. How do I create polyhedrons in Bullet that aren't boxes? I'm trying to build a physics approximation of some complex geometry and it would be helpful to be able to make shapes like the one I've included (a hexahedron).

Apologies if I've missed something obvious; I didn't see anything in the demos I checked out or via a quick forum search. Oh, and if you don't mind including code (or pointing me to demo code), I'd appreciate it.

Thanks!
You do not have the required permissions to view the files attached to this post.
c6burns
Posts: 149
Joined: Fri May 24, 2013 6:08 am

Re: Creating non-rectangular shapes w/ >4 sides

Post by c6burns »

There's a snippet on building trimeshes here:
http://bulletphysics.org/mediawiki-1.5. ... e_Snippets
bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

Thanks for that! I'll play around with it and see if it gives what I need. In the meantime, any other suggestions are welcome.
bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

The method posted above seems to work, but I think I'm doing something wrong somewhere because I can't get my shape to work if it's not static. I just stuck it into AppBasicDemo like this:

Code: Select all

//Triangle mesh hexahedron
		btTriangleMesh *mTriMesh = new btTriangleMesh();

		// For whatever your source of triangles is
		//   give the three points of each triangle:
		//1
		btVector3 v0(0,0,0);
		btVector3 v1(0,0,.5);
		btVector3 v2(-.25,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//2
		v0.setValue(-.25,0,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//3
		v1.setValue(-.5,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//4
		v2.setValue(-.25,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//5
		v0.setValue(-.5,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//6
		v1.setValue(-.25,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//7
		v0.setValue(0,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//8
		v2.setValue(0,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//9
		v1.setValue(-.25,-.15,.5);
		v2.setValue(0,0,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//10
		v0.setValue(-.25,0,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//11
		v1.setValue(0,0,0);
		v0.setValue(0,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//12
		v2.setValue(0,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//13
		v0.setValue(-.5,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//14
		v2.setValue(-.5,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		
		btCollisionShape *mTriMeshShape = new btBvhTriangleMeshShape(mTriMesh,true);

		//if(mass != 0.0)		//attempted mass of 1
		//{
		//	mTriMeshShape->calculateLocalInertia(mass,inertia);
		//}

		btTrans.setOrigin(btVector3(0,3,0));
		btDefaultMotionState* triMotionState = new btDefaultMotionState(btTrans);
		btRigidBody::btRigidBodyConstructionInfo hexCI(0,triMotionState,mTriMeshShape);   //static like this works
		btRigidBody* hexRigidBody = new btRigidBody(hexCI);
		hexRigidBody->setContactProcessingThreshold(BT_LARGE_FLOAT);	//don't really know what this does; stole it from DemoApplication and seems to have no effect
		m_dynamicsWorld->addRigidBody(hexRigidBody);

		hexRigidBody->setCollisionFlags(hexRigidBody->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);	//Makes boxes use the custom callback function
When the object is static, it works okay and shows up like in the picture. When it is dynamic, though, it crashes. Debugging shows that the problem is in btTriangleMeshShape.cpp here:

Code: Select all

void	btTriangleMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{
	(void)mass;
	//moving concave objects not supported
	btAssert(0);
	inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
}
Based on where it kicked me out, I'm guessing it thinks my shape is concave. But... it shouldn't be, right? What's going on here?
You do not have the required permissions to view the files attached to this post.
bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

Well, I found some problems with my self-determined triangle mesh, so I modified it a bit. This makes me really wish I knew how to get the mesh from the proprietary software I'm using... even getting the vertexes from 12 triangles is a pain! I made the changes below, but it still crashes in the same place when I attempt to make the shape dynamic.

Code: Select all

//1 - verified
		btVector3 v0(0,0,0);
		btVector3 v1(0,0,.5);
		btVector3 v2(-.5,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//2 - verified
		v0.setValue(-.25,0,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//3 - verified
		v1.setValue(-.5,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//4 - verified
		v2.setValue(-.25,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//5 - verified
		v0.setValue(0,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//6 - verified
		v1.setValue(0,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//7 - verified
		v0.setValue(0,0,.5);
		v1.setValue(-.25,0,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//8 - verified
		v1.setValue(0,-.15,.5);
		mTriMesh->addTriangle(v0,v1,v2);
		//9 - verified
		v2.setValue(0,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//10 - verified
		v0.setValue(0,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//11 - verified
		v1.setValue(-.5,0,0);
		mTriMesh->addTriangle(v0,v1,v2);
		//12
		v2.setValue(-.5,-.15,0);
		mTriMesh->addTriangle(v0,v1,v2);
Is what I'm trying to do not possible, or am I making a mistake somewhere (probably much more likely)?
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Creating non-rectangular shapes w/ >4 sides

Post by rtrius »

btBvhTriangleMeshShape is for static meshes; GImpact can be used for dynamic meshes:
http://bulletphysics.org/Bullet/BulletF ... Shape.html

If the shapes are convex, it may also be worth looking at the btConvexHullShape:
http://bulletphysics.org/Bullet/BulletF ... Shape.html
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by Flix »

A btConvexHullShape best fits any convex polygon in Bullet: IMO you should use it.
Additionally, it's easier: you just need to pass in your (8?) vertices :D

But remember that the center of mass of the object is vertex (0,0,0)! (So you may need to perform a shift operation on your vertices).
bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

Thanks, guys! I managed to build my dynamic hexahedron using btConvexHullShape. The center of gravity thing is kind of annoying, though... that's going to make placing my objects a headache. Do you know of any way to get Bullet to calculate a new center of gravity so I don't have to figure it out for myself every time I create a shape this way?

I'm including the code I used in case it is helpful to anyone else searching the forums (or for improvement suggestions, of course :)).

Code: Select all

//convexhull hexahedron
		btVector3 verts[8] = {
			btVector3(0,0,0),
			btVector3(-.5,0,0),
			btVector3(-.5,-.15,0),
			btVector3(0,-.15,0),
			btVector3(0,0,.5),
			btVector3(0,-.15,.5),
			btVector3(-.25,-.15,.5),
			btVector3(-.25,0,.5)
		};

		btVector3 shift = btVector3(-.1875,-.075,.25);	//not exact, just a test to get the COM inside the shape

		btConvexHullShape * hexShape = new btConvexHullShape();

		for(int i = 0; i<8; i++)
		{
			verts[i] = verts[i] - shift;	//should center the hexahedron (roughly) around (0,0,0)
			hexShape->addPoint(verts[i]);
		}

		if(mass != 0.0)		//inertia only needs to be calculated for non-static objects, and mass = 0 objects are static in Bullet
		{
			hexShape->calculateLocalInertia(mass,inertia);
		}
		btTrans.setOrigin(btVector3(0,3,0));
		btDefaultMotionState* hexMotionState = new btDefaultMotionState(btTrans);
		btRigidBody::btRigidBodyConstructionInfo hexCI(mass,hexMotionState,hexShape,inertia);
		btRigidBody* hexRigidBody = new btRigidBody(hexCI);
		hexRigidBody->setContactProcessingThreshold(BT_LARGE_FLOAT);
		m_dynamicsWorld->addRigidBody(hexRigidBody);

		hexRigidBody->setCollisionFlags(hexRigidBody->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);	//Makes boxes use the custom callback function
You do not have the required permissions to view the files attached to this post.
bwelch
Posts: 48
Joined: Thu Dec 12, 2013 4:04 pm

Re: Creating non-rectangular shapes w/ >4 sides

Post by bwelch »

I found this thread after some searching http://www.bulletphysics.org/Bullet/php ... shift+demo and tried to cannibalize the relevant parts in the hopes that I could get Bullet to figure out the center of mass for me:

Code: Select all

//convexhull hexahedron (not centered on the origin)
		btVector3 verts[8] = {
			btVector3(0,0,0),
			btVector3(-.5,0,0),
			btVector3(-.5,-.15,0),
			btVector3(0,-.15,0),
			btVector3(0,0,.5),
			btVector3(0,-.15,.5),
			btVector3(-.25,-.15,.5),
			btVector3(-.25,0,.5)
		};

                //this shape will be the hexahedron
                btConvexHullShape * hexShape = new btConvexHullShape();

		for(int i = 0; i<8; i++)
		{
			hexShape->addPoint(verts[i]);
		}

                //make a compound shape for use of calculatePrincipalAxisTransform
		btCompoundShape* hexCompound = new btCompoundShape();
		btTransform hexLocalTrans;
		hexLocalTrans.setIdentity();
		
                //add the off-center hull shape to the compound shape
		hexCompound->addChildShape(hexLocalTrans, hexShape);
		btTransform principal;
		btVector3 principalInertia;

                //if I had multiple shapes in the compound, this would handle them
		btScalar* masses = new btScalar[hexCompound->getNumChildShapes()];
		for (int j=0;j<hexCompound->getNumChildShapes();j++)
 		{
			//evenly distribute mass
			masses[j]=mass/hexCompound->getNumChildShapes();
		}

		hexCompound->calculatePrincipalAxisTransform(masses,principal,principalInertia);

		btCompoundShape* newHexCompound = new btCompoundShape();
		for (int i=0;i<hexCompound->getNumChildShapes();i++)
		  {
			  btTransform newChildTransform = principal.inverse()*hexCompound->getChildTransform(i);
			  newHexCompound->addChildShape(newChildTransform,hexCompound->getChildShape(i));
		  }

		//hexShape->initializePolyhedralFeatures();	//seems to sharpen the shape but leave an annoying invisible border

		if(mass != 0.0)
		{
			newHexCompound->calculateLocalInertia(mass,inertia);
		}

		btTrans.setOrigin(btVector3(0,3,0));
		btDefaultMotionState* hexMotionState = new btDefaultMotionState(btTrans);
		btRigidBody::btRigidBodyConstructionInfo hexCI(mass,hexMotionState,newHexCompound,inertia);
		btRigidBody* hexRigidBody = new btRigidBody(hexCI);
		hexRigidBody->setContactProcessingThreshold(BT_LARGE_FLOAT);
		m_dynamicsWorld->addRigidBody(hexRigidBody);
Unfortunately, this doesn't seem to work, at least not as I've implemented it. The shape still behaves as if all of the mass is located at the corner (0,0,0), giving it really wonky motion. Can anyone see what I've done wrong?

Thanks again for all of the guidance so far.