Java Model Importer - Design Discussion

Hi everyone,

I’m currently working on a library for importing various model types. The idea is that with a single easy command ModelImporter.import(Path to file), it will return an object representing the scene. The scene currently consists of all the individual meshes in an array with the ability to retrieve an individual mesh by index or name, and any lights, cameras, textures etc defined within the import. If anyone has ever used the AssImp library (which is written in C++) then I basically want to try and create that but in pure Java.

I wanted to spark a discussion on how to structure the scene object in such a way that it makes it fast and efficient for people to handle things like animations and the like. At the moment the scene consists of a mesh array containing each mesh defined within the scene, and each mesh contains various primitive array types for things like vertices, normals, indices and so on. This works fine if all you want to do is render a static mesh with a texture, as I can just do Mesh.getVertices() and buffer those into the VBO, followed by Mesh.getUVs(), Mesh.getIndices() and so on. However, I want to support animation as well, and I’m not sure how efficient this type of structure is going to be when you throw that into the mix.

I was wondering if anyone would be able to offer some ideas on what the structure might look like, to make it as easy and fast as possible to extract the vertex information you need, interpolate it based on animation data and get it buffered into the VBO with the minimum of fuss? Remember that I want this to be format-agnostic, so format-specific stuff should be avoided if possible.

Thanks in advance!

So I have done something like this before for a few formats. Essentially I just built everything around the way COLLADA structures it’s data. It’s an extremely comprehensive format that covers everything and it’s designed by lots of collaborators (the Khronos ARB) so it’s quite a good average of all the stuff out there.

Also it’ll probably be the most complex format you will support so better that you bend everything else to fit it than vice versa.

Hi again,

I’ve made some progress and finished importing most of the data I need for animated models. However, I’m a little stuck at the rigging and animation part. This is a simplified breakdown of how the imported scene is organised:

https://dl.dropboxusercontent.com/u/88069272/JUMIScene.png

The scene contains an array of each mesh, and any “orphan” textures which aren’t associated with a particular mesh.

Meshes are generated by essentially collapsing the model hierarchy into a single mesh object that contains all the geometry data, associated material definitions, textures etc. as well as rigging information like deformers and limb nodes.

Currently the mesh contains a single limb node reference which is the root. Every JUMILimbNode contains an array of other limb nodes which are their children. To retrieve the skeleton you start with the root and then recursively work through the hierarchy.

Each mesh also has a skin deformer associated with it, which contains an array of clusters (or sub-deformers). On the diagram I forgot to include the JUMICluster attributes, which include float arrays for weights, transforms and transform links, as well as an int array for the indices.

I was thinking of combining JUMICluster and JUMILimbNode into a single class JUMIBone since I don’t think there’s any need for a separate cluster and limb node object.

What I wanted to know was the basic process for animation. I’ve looked online but I find a lot of heavy maths and C++ code examples when all I really want is a layman’s explanation on how an animation works. My understanding is this:

  • A keyframe contains information on the position of each limb node
  • Each limb node has a series of indices which point to vertices within the model, and corresponding weights to determine how much influence it has on those vertices
  • To get the final position of each vertex, you find the limb nodes that affect it, determine how much each has moved from the “default” position and blend them accordingly, based on the weight each exerts on the vertex

Is this correct? Also, I noticed that clusters have an array of doubles called “transform” and another called “transform link”, what do these do? Thanks.

So you are right. But the maths really isn’t that complicated. If I were you I’d take a look at the COLLADA specs. https://www.khronos.org/files/collada_spec_1_4.pdf. They really are so useful. Chapter 4 is a programming guide and it has a section called “Skinning a Skeleton in COLLADA.” Which should explain everything you need to know about skeletal animation. The implementation can be a bit difficult but there are other posts here to help with that.

As for your clusters, I have no idea what they are.

Thanks for the reply, good to know that I’m headed in the right direction. The challenge now is to understand where the keyframe data is in the FBX format, it’s very hard to find any good information because most people just post code examples using the SDK, which doesn’t explain the actual data structures underpinning it.

I think clusters and limb nodes together form what we might define as a “bone” or “joint”, with limb nodes describing the hierarchy and clusters defining the actual numbers for deforming the mesh. The FBX mindset is to apparently make things as complicated as possible.

Thanks very much for the PDF, I’ll take a look through when I have some time :slight_smile:

Sounds plausible. It is a proprietary format after all. But apparently Blender has written their own importer, and have been nice enough to write up some unofficial specs: http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ and http://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure. Which might be of some help.

Those two links are what allowed me to get this far :slight_smile:

Thinking about it a bit more, the crux of the issue is that I cannot find much info on the old, deprecated animation system which was replaced by the current animation stack and layers system in SDK 7.1 (2011). For some reason, a large proportion of the free models from TF3DM use version 6.0 which has the “Takes” node and what look like horribly complicated data structures (a “key” consists of around 8 properties, with a mix of booleans and long values, what do they mean? No indication).

I think the simple answer here is to not support animation on models that use the old system, and if someone wants to use animation then they just need to use an exporter to update the model accordingly. I noticed Blender doesn’t allow imports of v6.0 models at all, so at least I can allow importing of the static mesh, materials and texture data.

Once I have this done, I’ll release an early version for people to play with :slight_smile: so far it’s taking around 100ms to import a model with ~7000 vertices, normals, UVs and embedded texture data into the JUMI data structure outlined above. I’ll also look at allowing export back into FBX, which should be quite simple now that I know the FBX format quite well.