Hi everyone,
I’ve been working on and off on a library for importing 3D models from various formats and converting them into a single standard data structure for easy use and manipulation. So far I’ve been working on OBJ and FBX binary formats, with the intention of including FBX ASCII and Collada formats in the near future and then continue to build until I get sick of it basically. Work is pretty heavy going at the moment so development on this has slowed a bit, but since it seems to work pretty reliably I thought I’d release a rough build for people to play with and give feedback on. I’ve tested it with around 20 OBJ and FBX models downloaded from TF3DM so far.
An early build is available here: https://github.com/RGreenlees/JUMI-Java-Model-Importer
Unfortunately I don’t have a lot of time at the moment, so there’s no detailed documentation. This is top of my list of priorities but it might take a bit of time. It is capable of importing the following:
- OBJ models (including parsing the material library). Can also handle relative index notation (with negative indices)
- FBX binary models (SDK version 6.0 and up tested)
- Vertices, UVs and normals
- Texture information (including embedded texture data for FBX files)
- Material data
- Skeleton (FBX only)
Each mesh definition in the FBX file, and each group or object in the OBJ file will be treated as a separate mesh object with its own vertices, normals and UVs assigned, so to render the whole scene just batch up your models accordingly.
I have added some utility functions including the following:
- Triangulate mesh (only supports quads at the moment)
- Flip UVs (horizontal and vertical)
- Scale mesh
- Set the mesh’s max extent (i.e. The distance of the furthest point from the origin). Useful if you want the mesh to be a certain size.
Some example code:
JUMIScene scene = JUMILoader.loadModel("C:/models/sponza.obj"); // Let's load Crytek's Sponza model
JUMIMesh sampleMesh = scene.getMeshByIndex(0); // Grab the first mesh in the scene
System.out.println(sampleMesh);
JUMIMaterial sampleMaterial = sampleMesh.getMaterialByIndex(0); // Grab the first material defined on the mesh
System.out.println(sampleMaterial);
JUMITexture sampleTexture = sampleMesh.getDiffuseTexture(); // Let's look closer at this material's defined diffuse texture
System.out.println(sampleTexture);
for (JUMIMesh a : scene.getAllMeshes()) {
a.triangulate(); // We want to render with GL_TRIANGLES
a.setScale(0.1f); // Shrink it a little
a.flipUVY(); // Our model uses DX coordinates so need to flip for OpenGL
}
// Begin loading geometry
float[] modelVerts = sampleMesh.getVertices();
float[] modelUVs = sampleMesh.getUVs();
float[] modelNormals = sampleMesh.getNormals();
int[] modelIndices = sampleMesh.getVertexIndices();
// Create buffers and load into VBO etc.
Your output from the above calls to println might look like this:
In this case OBJ models never have embedded texture data, but some FBX models have and if they do, you can retrieve the binary from the JUMITexture object.
This should hopefully prove useful to someone out there. I have kept it out of the WIP showcase as it is still very rough. Here are a list of features still missing:
- Parsing animation data from FBX files. Might need some help as it’s bloody confusing and I’m not sure what it should look like in the JUMI structure
- Associating diffuse/normal/specular textures to materials in FBX. Can’t see a way to determine that texture A is this material’s diffuse map. All textures get lumped into the “Unassociated textures” section for now
- The code is messy in places, including a hideous series of if-else statements using instanceof. Once I’m happy with my data structures I’ll go back and tidy this up and make it all neat
- Bone data is missing weights and vertex references. Until I sort out animation it’s kind of pointless anyway
Finally, some performance stats using my Quad-core i7:
OBJ
Sponza.obj (381 meshes, 184k vertices total) = 1.5s to create scene
Dragon.obj (1 Mesh, 439k vertices total) = 7.5s to create scene
FBX
Standard character mesh (1 mesh, 9k vertices total) = 0.3s to create scene
Detailed character mesh (10 meshes, 33k vertices total) = 0.4s to create scene
Thanks!