BvhImporterExporter (for Unity 3D)
BvhImporterExporter (for Unity 3D)
Biovision Hierarchy format (BVH) is a popular motion capture format stored in plain text files. It defines both the motion data and the actual skeleton that should be moved by it.
What BvhImporterExporter does is make it possible to import these .bvh files into the Unity 3D Game Engine at runtime.
- Create a BVH instance.
- Call method to make a GameObject skeleton.
- Call method to make an AnimationClip that moves the skeleton.
From there it's just a matter of using the skeleton the way you want to use it! You can add things to any of the skeleton's child GameObjects or bind a mesh to it if you want.
This tool goes great together with the MeshSkinner tool!
BVH Modification
The imported .bvh file can also be modified via several methods or by changing the bones directly via the allBones[] struct array.
It can then be written back to disk as a completely new .bvh file. Possible modifications via methods:
scale() | You can shrink or enlarge the BVH. |
setFPS() | You can modify the frame rate. |
shiftAnimation() | You can change which frame is the first frame. |
setAnimationOrigin() | You can reposition the animation (with or without the rest pose). |
flattenAnimation() | Prevents the root bones from moving on a given axis. |
rotateAnimationBy() | Rotates the the animation (with or without the rest pose). |
removeFrames() | Removes one or more frames from the animation. |
setBoneNames() | Renames all the skeleton bones. |
replaceBoneNames() | Renames the skeleton bones that matches your given names. |
Some convenience methods also exist, like center(), which positions both the first frame of the animation and the rest position at Vector3.zero.
Another one is align(), which rotates the animation so it points at Vector3.forward (or a direction specified by you).
The best convenience method is perhaps normalize(), which calls center(), align() and flattenAnimationForward(). The last flatten call can be skipped by calling normalize(false).
What does it mean to "flatten" an axis? It makes the animation stand still on one axis while being able to move in the other two. It's useful if you for example want to make seamless walk/running animations, where you need the skeleton to stay in the same spot but still be able to bob up/down and sway left/right. BvhImporterExporter works great as a "raw fix" before fine-tuning an animation in for example Blender. Just make a BVH instance, call normalize() to center/align/flatten and then cell writeToDisk() to save it as a new .bvh file. Finally import that one into Blender.
The constructor also has a couple of useful optional parameters, in particular:
importPercentage | If not 1.0f less than 100% of the available animation frames will be imported. Can be set to negative numbers to auto-adjust the import percentage to a frame rate. Very useful because too heavy AnimationClips only waste resources. Interpolation makes it often near impossible to detect any quality loss. |
zUp | Counts z as up instead of y during the import. Useful for dealing with BVH files exported by Blender. |
parseMotionData | If you only need the rest pose or if you just want to peek at a .bvh file's frame rate this will make import time extremely short when set to false. |
There's also a duplicate() method on each BVH or BVHBone instance to quickly make copies without having to import twice.
The static method BVH.makeEmpty() will create an empty BVH instance if you ever want to make a .bvh file from scratch.
Speed
The tool has been written to be blazingly fast, able to import thousands of frames in a very short time.
It's even faster when not running in the Unity Editor, pretty much doubling in speed in the stand-alone release version of your game.
I'd like to avoid giving an example since different hardwares under different conditions gives different performance (and benchmarks gets more irrelevant over time as typical hardware improves) but here is an example anyway. The .bvh file used is for the conversation gestures that you can see animated here to the right, though not all BVH frames are in the ~14.3 FPS gif. Click it for a larger webm version.
Each row in my benchmark was executed 10 times and then the average amount of milliseconds was calculated.
BVH: 22 bones, 1522 frames, 30 fps, 50.7333333333333 sec.
Hardware (CPU): Intel Core i7-3630QM 2.4-3.4 GHz 6 MB Level3 Cache (sitting in a laptop I bought early 2013)
[EDITOR] new Winterdust.BVH(myPath).makeDebugSkeleton(); 220 ms
[EXEx86] new Winterdust.BVH(myPath).makeDebugSkeleton(); 108 ms
[EDITOR] new Winterdust.BVH(myPath).makeAnimationClip(); 218 ms
[EXEx86] new Winterdust.BVH(myPath).makeAnimationClip(); 108 ms
[EDITOR] new Winterdust.BVH(myPath); 187 ms
[EXEx86] new Winterdust.BVH(myPath); 90 ms
As you can see the actual importing of the file takes the longest, making an AnimationClip out of it took only around 16.5% of the time it took to import it.
makeDebugSkeleton() creates GameObjects for every bone, creates and assigns meshes to each joint, adds a BVHDebugLines component to the container skeleton GameObject AND calls makeAnimationClip() as well as the static method BVH.animateSkeleton() to add an Animation component to the container skeletonGO. All of that doesn't take long in comparison.
This test was done on a very large animation, at 1522 frames. Reducing the imported frames by 66% (from 30 to 10 fps) will decrease import time a lot without really losing any quality thanks to interpolation in the AnimationClip. Having more than 10 keyframes per second is a luxury in most cases, I mean how often do you change your bone's motion in real life? Ten changes per second covers a lot. Here's the first test again with the same .bvh file, just with an import limit:
[EDITOR] new Winterdust.BVH(myPath, -10).makeDebugSkeleton(); 111 ms
[EXEx86] new Winterdust.BVH(myPath, -10).makeDebugSkeleton(); 47 ms
If you only import short looping animations (walk/run) that you've cleaned they usually don't have many frames at all, less than 100 in many cases.
Such short animations will take just a couple of milliseconds to import, especially if you use -10 in the constructor.
Installation
Extract the ZIP archive in your Unity project's "Assets" folder. This places a .dll file (plus two other files) in Assets/Plugins/Winterdust, now ready to be used in your game.
Using a .dll file in Unity doesn't make your game Windows-only, you can still build for any platform (Windows/Linux/OSX).
Note: There is a BVH_README.TXT in the .zip file as well. After you've read it you can delete it if you want to.
Usage
Using the BVH class is simple. You do it through code, not via a MonoBehaviour component in the Unity Editor. How to get started in C#:
using Winterdust;
[...]
BVH myBvh = new BVH("C:\\YourFileHere.bvh");
That imports the .bvh file, it's now ready for use.
There are other optional parameters in the constructor to check out later but the default values works fine most of the time.
GameObject skeletonGO = myBvh.makeDebugSkeleton();
This line creates an animated skeleton from the BVH instance, visualized as a stick figure.
makeSkeleton() does the same thing, except it isn't visualized/animated by default.
AnimationClip clip = myBvh.makeAnimationClip();
This line just creates an AnimationClip. By default it has legacy set to true but you can turn that off (either later or directly in the method call).
That means you can use the AnimationClip both in the Animation component (legacy) and the Animator component (Mecanim).
I recommend using it with the legacy Animation system, Mecanim requires you to use an "Animator Override Controller" (RuntimeAnimatorController) which can be a little advanced.
[NOTE] There is also a constructor accepting the content of a BVH file directly (via a string[] parameter).
This allows you to download .bvh files from external servers or even embed them directly into your code.
Compatibility
You don't have to make a skeleton from every imported BVH, usually you make several AnimationClips from different BVH files and just one "master skeleton" from a BVH that has the same skeleton as the other ones. It's this "master skeleton" that you then do stuff with, for example bind to a mesh.
Bone length usually doesn't matter since BVH usually only rotates the child bones and only reposition the root bone. BvhImporterExporter actually ignores any child bone positions by default to reduce import time, should you need them you can set ignoreChildBonePositions to false in the constructor.
The stored rest pose must always be without rotation in the BVH format as well. This means that you can have a skeleton with a short left arm and it can still be moved beautifully by an AnimationClip created from a different skeleton with a long left arm. They both rotate the same from their rest rotation, which is Quaternion.identity (no rotation).
So skeletons need to have the same bone names and bone hierarchy to be compatible with each other, as well as a somewhat similar rest pose. They don't have to match exactly.
If an AnimationClip tries to move a bone it can't find nothing simply happens, the game doesn't crash or anything.
Documentation
Everything that is accessible (public fields/methods/etc) have detailed XMLDOC describing what they do and how to use them.
They should show up as normal in your code editor as long as the included XML file is placed next to the DLL file.
Where to get .bvh files
You can obtain thousands of free .bvh files online. Most available are humanoid.
[NOTE] I'd like to point out that BvhImporterExporter can handle generic skeletons of any type.
[NOTE] The tool even supports multiple root bones (although I don't recommended that practice).
Here's a popular resource with over 2000 quality .bvh files: cgspeed's Motion Capture archive
If you want them all prepare to reserve ~2.752 GiB of your disk space (around 1 GiB compressed). They are in 120 fps.
+ You can record your own body's movement into .bvh files using for example Kinect, check YouTube for guides.
+ A simpler way is to use Blender and let it record bone positions/rotations while you grab onto them and move your mouse around.
+ If you have an animation in a different format you can use Blender to convert it into the BVH format.
Showcase
BvhImporterExporter supports multi-threading.
It can do almost all of its work on threads other than Unity's main thread.
That's real threads, not Unity's "coroutine" thread-imitation where yield and IEnumerator is used.
The showcase is a BVH Viewer. It creates a background loader for .bvh files in a different thread while the game runs like normal. Once everything has been loaded Unity's main thread takes over and can create GameObjects and AnimationClips, which is only permitted on the main thread.
Download BvhImporterExporter_Showcase.zip below. It's an exe build (Windows 32-bit).
[NOTE] Full C# source code is included for the showcase: BvhImporterExporterShowcase.cs
The viewer can show up to 22 .bvh files at the same time so that many are included in the ZIP.
If you are out scouting for .bvh files and need a way to preview them I recommend you check it out!
Try Before Buy
There is a free demo available so you can see for yourself what this tool can do for you! See below for a download.
Some points about the limitations of the demo:
- Requires an empty text file to be placed into the Resources folder of your Unity project. Simply call the BVH constructor for details.
It needs to be renamed every once in a while. You'll get told by the BVH constructor when the time comes (prints a message in the console).
The text file can be seen as a kind of "demo key". - All features except one is included in the demo version. You'll be able to see exactly what this tool can do for you without having to invest any money!
The exception is writeToDisk(). That method will not work in the demo. It's still there though so you can familiarize yourself with the parameters.
You can test the demo for as long as you want to, just don't release anything that anyone outside of the development team can access. As you probably realize the first demo limitation is to prevent games from being released with a demo version of BvhImporterExporter, since the demo DLL won't work for everybody and will stop working for all eventually.
Licence Agreement
- This tool is per-seat.
If multiple people will access the BVH class in your development team please purchase the tool multiple times. - You may not create some kind of BVH editor using this tool, unless available only to your development team and not shipped in your final product or elsewhere.
Final Words
Try importing a skeleton during runtime today!
Imagine how great mod support your game will have if people can change your in-game animations just by adding .bvh files to a folder or edit your existing ones.
Looking for a way to bind the skeleton to an actual mesh? I've made the perfect tool for that exact purpose:
MeshSkinner - Import a .bvh file, make a skeletonGO, then use it with the MeshSkinner and BAM: you've got a dancing character!
You don't need to create an account here on itch.io in order to buy this tool.
Actual payment is done on PayPal's site (credit card accepted - no account needed).
Note: Some additional info may be required for tax purposes during purchase, if so you will get a "Billing address" message before being taken to PayPal ("2015 VAT MOSS regulations for EU"). Simply fill out the form and press "continue payment". The info is used to calculate what VAT percentage to add on top of the price (if you live in USA it will always be 0%).
Psst! Check out JezzBall Classic while you're here!
Purchase
In order to download this tool you must purchase it at or above the minimum price of $45 USD. You will get access to the following files: