The Bullet library will be added to Unity as a native plugin. We will need a build of Bullet for every platform we intend to support. In this example I build for x86, x64. This describes the process using Visual Studio but it will be similar using other IDE’s.
Clone the github project:
https://github.com/Phong13/BulletSharpPInvoke.git
This contains bullet source code in:
- libbulletc/src/src
- libbulletc/src/Extras
It also contains BulletSharpPInvoke wrappers that export the Bullet API using Platform Invoke in:
- libbuleltc/src/libbulletc
The github project also contains solutions for Android (NDK), iOS (XCode), OSX (XCode), Windows (Visual Studio).
If you wanted to build a new Visual Studio project from scratch, Create a new project in Visual Studio:
Templates -> Visual C++ -> Win32 -> Win32 project
If you want to create Windows Universal DLL then choose:
Templates -> Windows -> Universal -> DLL
Create the project beside the other projects in libbulletc.
The easiest way to add the sourcecode is to drag and drop the folders into Visual Studio, XCode or Eclipse. Not all the source folders are needed. Only include:
- libbulletc/src/src/LinearMath
- libbulletc/src/src/BulletCollision
- libbulletc/src/src/BulletDynamics
- libbulletc/src/src/BulletSoftBody
- libbulletc/src/src/BulletInverseDynamics
- libbulletc/src/src/btBulletCollisionCommon.h
- libbulletc/src/src/btBulletDynamicsCommon.h
- libbulletc/src/Extras/HACD
- libbulletc/src/Extras/Serialize
- libbulletc/src/Extra/ConvexDecomposition
- libbulletc/libbulletc
Update the properties for the configurations you intend to build:
C++ Additional Include Directories:
- $(SolutionDir)..\..\src\src;
- $(SolutionDir)..\..\src\Extras\Serialize\BulletWorldImporter;
- $(SolutionDir)..\..\src\Extras\HACD;
- $(SolutionDir)..\..\src\Extras\Serialize\BulletXMLWorldImporter;
- $(SolutionDir)..\..\src\Extras\Serialize\BulletFileLoader;
- $(SolutionDir)..\..\src\Extras\ConvexDecomposition;
- %(AdditionalIncludeDirectories)
The project should build now into a .dll
Copy The C# Wrappers To Your Unity Project
Copy the created .dll to Unity3d /Assets/Plugins/[platformName] folder. Configure the plugin in the inspector so that Unity will use the correct plugin for the correct platform.
One final problem is that the C# wrappers use unsafe code which produces compiler errors.
Add a scms.rsp file to the root of the project folder. This is a text file, add the line.
-unsafe
This will work for the editor and some build targets. It does not appear to work for all build targets. If the build target you are using does not work try compiling the BulletSharpPInvoke project into a .dll and adding that to your project instead of the wrappers.
Debugging
It is possible to debug from Unity into the native C++ code using Visual Studio. This may be possible with other IDEs but I have not tried. To do this compile a debug version of the library and copy the .dll and .pdb to the Unity plugins folder. In visual studio set the path to the Unity executable:
Configuration -> Debugging -> Command:
C:\Program Files\Unity.5.3.1\Editor\Unity.exe
To start Unity use Visual Studio -> Debug -> Start Debugging. This will launch Unity. Any breakpoints you have set in the bullet sourcecode will trigger. More information can be found at: https://msdn.microsoft.com/en-us/library/605a12zt.aspx
Some Problems You Might Run Into
XCode Link errors:
Got link errors Undefined symbols for architecture “x86_64” for btSoftBody….rayFromToTriangle. This appears to be because this function is declared inline in the .h file
but the definition is in the .cpp file. I tried to fix by removing the “inline” in the bullet btSoftBody.h file but still got the error (I think I might have missed an overload). Fixed the problem by removing the function in the pinvoke wrapper file.
MonoPInvokeCallback problems:
Mono allows callbacks from native code (Bullet) to Managed (Unity). On some platforms (iOS, Windows Store) the functions being called must be:
- static
- decorated with [MonoPInvokeCallback]
This required some refactoring of the BulletSharp wrappers:
Have a wrapper on Managed side and Native side. The Managed side defines one or more delegates. These are passed to the Native side in the constructor. Bullet calls these delegates:
Native side:
wrapper needs a member variable to store a ptr to managed object type is void*. Add void* argument to constructor and methods that will be static. Constructor should store ptr in member variable.
Managed Side: Constructor needs to pass refrerence to object that can be passed back to static methods: GCHandle handle = GCHandle.Alloc(this, GCHandleType.Normal); _native = btMotionStateWrapper_new( Marshal.GetFunctionPointerForDelegate(_getWorldTransform), Marshal.GetFunctionPointerForDelegate(_setWorldTransform), GCHandle.ToIntPtr(handle));
Functions assigned to delegate variables must be static and must take IntPtr as first argument Add [MonoPInvokeCallback ....] to decorate static function The function should get a handle and call method on instance MotionState ms = GCHandle.FromIntPtr(msPtr).Target as MotionState; ms.GetWorldTransform(out worldTrans);
If You Find This Plugin Useful Please Consider Donating To The Project