Bullet binary serialization
From Physics Simulation Wiki
Bullet 2.76 onwards has built-in capability to save the dynamics world to a binary dump, without additional dependencies. This dump can be saved as a .bullet file.
The Maya_Dynamica_Plugin supports export to the .bullet binary format. Also there is a modified Blender 2.49b (updated 2010 June 1st to export object names) version that supports export to .bullet through the game engine, using PhysicsConstraints.exportBullet("fileName").
See BulletSharp binary serialization for a C# version of some of the code on this page.
Saving a dynamics world to a .bullet file
Serialization, saving the objects and shapes into a buffer, is built-in. No additional libraries are necessary. Here is an example how to save the dynamics world to a binary .bullet file:
btDefaultSerializer* serializer = new btDefaultSerializer(); dynamicsWorld->serialize(serializer); FILE* file = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file); fclose(file);
Several Bullet demos show how to load and save .bullet files, including Bullet/Demos/SerializationDemo and Bullet/Demos/ConvexDecompositionDemo.
Saving a single object, shape or acceleration structure
Although it is easiest to serialize the entire world, it is also possible to just serialize small parts into the .bullet file format. The .bullet file format is essentially derived from the .iff format, so it uses chunks to store information. Here is an example how to serialize a collision shape:
btDefaultSerializer* serializer = new btDefaultSerializer(); serializer->startSerialization(); trimeshShape->serializeSingleShape(serializer); serializer->finishSerialization(); FILE* file = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file); fclose(file);
See Bullet/Demos/ConcaveDemo for further information how to load such collision shape or how to serialize just the btOptimizedBvh.
Loading a .bullet file, creating objects and adding them to the world
When loading a .bullet file, the BulletFileLoader library is needed to deal with endian-ness, 32/64 bit conversion. BulletWorldImporter, another utility library, takes the memory objects from BulletFileLoader and instantiates Bullet objects (btRigidBody, btCollisionShape etc) and adds them to the world.
- Make sure to add "Bullet/Extras/Serialization/BulletWorldImporter" to your include path.
- Add BulletWorldImporter and BulletFileLoader to your project (in addition to BulletDynamics, BulletCollision, LinearMath libraries)
//at the top of the file add #include "btBulletWorldImporter.h" //in your source code add btBulletWorldImporter* fileLoader = new btBulletWorldImporter(m_dynamicsWorld); //optionally enable the verbose mode to provide debugging information during file loading (a lot of data is generated, so this option is very slow) //fileLoader->setVerboseMode(true); fileLoader->loadFile("testFile.bullet");
Instead of a file, you can also pass in a memory buffer and length, and use
char* memoryBuffer = ... int len = ...; fileLoader->loadFileFromMemory(buffer,len);
Supported Bullet structures in serialization
Initially we support the following Bullet data structures. Check out Bullet/Extras/Serializer/makesdna/makesdna.cpp file for the most up-to-data support.
- btCollisionObject, btRigidBody and btSoftBody
- btBoxShape, btSphereShape, btCylinderShape, btCapsuleShape, btConvexHullShape, btBvhTriangleMeshShape, btCompoundShape, btGImpactMeshShape, btStaticPlaneShape
- btPoint2PointConstraint, btHingeConstraint, btSliderConstraint, btGeneric6DofConstraint, btConeTwistConstraint
- For btSoftBody the nodes, links and faces are exported, as well as clusters and anchors between soft body and rigid body
Although above structures are stored in the .bullet file, the btWorldImporter only uses a small subset when re-creating the Bullet objects. Look into the btWorldImporter implementation for more details.
Setting and Getting the name for bodies, shapes and constraints
The Dynamica Maya plugin and Blender create unique names for all objects. This is useful to recognize objects, shapes and constraints, for example to bind them with graphics objects.
- When saving the file, the btDefaultSerializer is created, and all names are registered using the registerNameForPointer method.
- When loading the .bullet file, the m_name field is part of the structures: btCollisionObjectData, btRigidBodyData, btCollisionShapeData and btTypedConstraintData.
- Also the 'btBulletWorldImporter::createRigidBody' methods passes this nams as one of the arguments, when available.
Extending the file format
It is possible to add your own data structures to the .bullet format. All data structures are stored in the .bullet fileformat as 'DNA', so you have to re-generated this DNA using the utilities.
- Use cmake-gui or cmake and enable the 'INTERNAL_UPDATE_SERIALIZATION_STRUCTURES' option. This will add the makesdna, BulletDna and HeaderGenerator projects.
- The 'makesdna' utility will parse the C data structures that are used for serialization. Each headerfile needs to be added in the makesdna.cpp file: include the headerfile (right under the commend "// include files for automatic dependencies") and add it to the "char *includefiles" array.
- The 'BulletDNA' project runs the makesdna executable and when succesful it creates new binary DNA in the Bullet/src/LinearMath/btSerializer.cpp file.
There are several requirements and restrictions for the data structures for the .bullet file format. In particular, the data structures have certain alignment requirements, for easier cross-platform support (compiler alignment differences, 32/64 bit, little/big endian in particular).
- The makesdna C headerfile parser is very basic and only supports a very small subset of C99. In particular you need to take care of alignment of members and pointers and add extra 'padding' bytes.
For further information, see the serialization DNA restrictions, size and alignment rules.
- The optional HeaderGenerator can create header files by extracting the DNA structures embedded in each .bullet file. This means you don't need the Bullet SDK in order to load the .bullet file, you can just use the BulletFileLoader and those autogenerated header files. For an example, see Bullet/Extras/Serializer/HeaderFiles/autogenerated
Don't hesitate to ask help in the Bullet physics forums.