Wednesday, 10 March 2010

New Renderer

The new renderer is actually fairly basic in terms of what's already out there, but it serves its purpose. For one it's based entirely on the fixed function pipeline, I'm not sure yet whether I'll write any shaders for this project, for the time being basic FFP stuff is serving me well.

At the highest level the renderer takes a list of skeletons to render, paired off with their current frame given as a pose instance. It configures the pipeline and iterates the list, extracting their hierarchy instances and sending it off along with the pose frame to a function dedicated to drawing skeletons. The function recurses the hierarchy, extracting the quaternion rotation from the relevant bone/joint pose description, concatenates it together with the parent transform as a matrix to get the joint transform for the bone and forwards that onto a bone renderer along with with the resting bone vector. This renderer uses the bone vector to calculate the resting direction and length of the bone (currently using an expensive sqrt), converts those to appropriate rotation and scaling matrices (using dot and cross products ) and concatenates them with the joint transform given to it previously to arrive, eventually, at the bone's final world-space transformation that turns a unit-sphere mesh into a bone. When calculating the scaling the thickness of the bone is calculated to be 0.3 times its height, it seems that a number of other academic skeleton renderers do something similar as it produces a familiar looking skeletal figure with the very tiny heads and feet.

The high-level renderer does this twice, once for the main skeleton and again, with inverted z-axis and culling winding order, to get the reflection. It then uses an arena renderer to draw a checkered, semi-transparent floor.

There are still improvements needed to the renderer, I don't really like performing square roots etc in the renderer, I might move this work to the animation tree if I can. In addition there is no instancing going on, it should be possible to instance the sphere mesh to draw the bones of the skeletons. Having the renderer accept a list of skeleton-pose pairs is a little hacked together at the moment too, it just needs a tidy-up. My supervisor has also requested that I try and use a proper model for the scene too, so I might have a go at getting .X-files working. Whether or not I decide to write any shaders for the renderer remains to be seen, certainly a lot work could be moved to shaders but I don't know HLSL at all so we'll see.

The renderer, as it stands, is pretty complete it terms of how I envisioned it initially, I hadn't planned to do any more than this. It has all the features that I said it would a few blog posts previously, so I'm pleased it has got this far.

That's all again for now, I'll leave with a screenshot of the new renderer displaying some skeletons, you can see it in motion a few blog posts down too.





The BVH Loader

This last month has been a rather productive one in terms of finishing off sections of the API. This post is about the BVH loader itself.

As mentioned previously, the evolution of various core data structures resulted in breaking changes to the old BVH loader. The old loader could only parse the MOTION section of a given BVH document anyway, it was also heavily dependent on reading 'good' files, otherwise resulting in seg-faults - a result of having been quickly hacked together in an evening.

My first attempt at writing a revamped loader concentrated on using the Boost Xpressive library to perform the parsing. With this library you construct expressions using a familiar regular expression style syntax, expressions may recursively refer to themselves thus permitting the construction of context-free grammars (conceptually, push-down automata). The library is built to be more than just a toy however, so rather than sticking to the technical, academic, models it pragmatically gives the user control over backtracking and offers the ability to populate data-structures mid-parse so that by the end you will have accumulated all the relevant information together, no need to further traverse the parse tree afterwards.

Unfortunately, after spending the time to perfect the regexes and tracking down bugs in the grammar, I discovered that for some unknown reason certain files would fail and the Xpressive library would emit a null pointer exception  (which cannot be caught in C++) whilst parsing the HIERARCHY region of the .BVH. Presumably it was caused due to some misuse on my part but the fact that it worked slightly more than half the time was highly confusing. I was unable to identify anything wrong with the offending files either, but an invalid file ought to simply not match the grammar and fail at loading, the library should still not be accessing null pointers.

Ultimately I decided to scrap that loader and take a more straight-forward route. I probably should have just obeyed KISS in the first place although I did enjoy the learning experience associated with Xpressive which is likely to benefit me if/when I use it in other projects. With this version of the parser I simply went with using the white-space tokenisation feature afforded by std::istreams to split up the tokens without reading the entire file into a string to begin with (Xpressive operated primarily on strings). I then used boost::lexical_cast to convert certain numeric values that the stream might fail at (mainly the frame-time part).

Overall the new BVH Parser Version 3 is faster, smaller and simpler than it's Xpressive counterpart, not to mention the fact that it works for all BVH's I've found so far. It also handles invalid or corrupt files much better; the Xpressive version would simply fail at matching the grammar within the library, reporting success or failure back to me as a boolean and so you would get a generic invalid-file exception upon failure. The new version can attach a string message indicating exactly what went wrong and roughly where that is within the file. It doesn't report a line number, it could do but ultimately I didn't want to assume new-lines within the file, as long as tokens are separated by white-space then the parser can correctly interpret the file. As such no new-line counting is performed either.

Both the Xpressive and the new stream-based parsers incrementally populate a data-structure that is tailored to approximate the structure of a BVH file. Abstractly this is a parse-tree, although it can only loosely be called a tree, being a flat structure. This is stored as a data member within a bvh_document class instance, the class exposes a compile() member function that uses this structure and, using the SoA tools described in a previous blog post, will construct a mocap instance (which is little more than an aggregator of skeleton and motion class instances).

The parse-tree structure was originally created for the Xpressive parser; populating a data-structure that is dissimilar to the grammar would be have a more challenging task. After replacing the Xpressive parser with the stream-based parser it opened up the possibility of constructing a mocap directly at parse time; I didn't go down this route though, in addition to not really wanting to re-write more code than is necessary I also like the separation of concerns involved although it may be somewhat less efficient to do things this way. mocaps don't quite maintain all the information that a BVH file provides either, only keeping those bits relevant to the API; mainly information about the order of channels (Euler angles primarily) and ordering of the hierarchy is lost, although this isn't a problem as such, it does mean that a bvh_document instance can round-trip much better due to its internal parse-tree. It sets a precedent for future file formats too for which round-trip imports/exports might be more desirable.

Since, for the time being, exporting isn't supported, the bvh_document class is really just a go-between temporary object. Even when exports are supported the typical use-case will still primarily be imports; as such a convenience function called import_bvh_file exists, it's a pretty trivial function really, implemented like this:


    bvh_document::mocap import_bvh_file(const std::string & path, bool first_frame_as_bind_pose)
    {
        std::ifstream ifs(path.c_str());
        return bvh_document(ifs).compile(first_frame_as_bind_pose);
    }

It makes importing BVH's nice and simple though.

You'll notice that the loader supports the option to interpret the first frame of the MOTION section as being the bind-pose rather than being actual motion. This is quite a common thing to do with BVH's and it's something that has been done to most of the BVH's that I'm using (they're a conversion of Carnegie Mellon University's data-set).

Well that's all for this post, you can see the BVH's in action in the video I posted last time :-)
Next up, I'll talk a bit about the new renderer, stay tuned.

Tuesday, 9 March 2010

First Video

So it's getting to the point now where I have a substantial amount of media to share with you for my project. Thusly, a video of people moving around. It doesn't really demonstrate the full capabilities of the API but it's all a bit in flux at the moment.

With any luck I'll be posting some overdue blogs about how I arrived at this point, getting additively blended quaternions working was quite a feat, more interestingly I believe the solution I have arrived it is somewhat unique.