Inertia's picture

Interface for 3D Models?

Hello again,

i've been wondering if there are any plans for an Interface for 3D Models in OpenTK? I've written a .MS3D Parser (www.milkshape3d.com) that can read meshes/materials/joints from the file and i'd like to make it available to other Tao/OpenTK users, but i'm currently a bit uncertain what to ditch of the parsed data, because the possible uses for a mesh loader can range from an editor application (that wants as much data and comments as possible) to an application that needs nothing besides the vertex positions.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler.'s picture

I am planning to write some simple parsers (for Wavefront.OBJ and maybe .X) for OpenTK, but that's more of a long term goal. Right now I'm working on the core functionality (windowing, fonts that kind of stuff), which leaves little time to work on higher level functionality.

I don't have much experience with parsers so I don't know if this is possible, but what I'd try to do is parse only what the user explicitly asks for. If he asks for the comments, sure, load them, otherwise ignore them completely. With some caching this should scale well even to editors.

Is your parser able to output .MS3D files too, or only read them? Also, how are you planning to distribute it? I'm sure both Tao and OpenTK users will appreciate your work, good model parsers are hard to come by in .Net!

Inertia's picture

[Formats]
I've looked into these file formats aswell before chosing MS3D, .OBJ has the big disadvantage (like .3DS) of being popular but ancient and not supporting skeletal animation (..and if I bother writing a Model loader i want animations too). Alias .FBX and Collada both looked promising but there are no official specifications for FBX. Collada is well documented but also very young and updated regularly, which implies alot of updates to the loader and/or version conflicts.

A drawback of MS3D is that you cannot have more than 64k vertices/triangles per model, but that should be enough for a long time for real-time content. To my knowledge Gears of War is currently the polycount king, by using 10k triangles per character. Using more than that will most likely not yield any visual improvements (you already need to use a magnifying glass on a Screenshot to find any sharp edges, and you will definitely not notice any while the model is in motion) unless screen size and resolutions increase dramatically.

[Parsing]
Reading the chunks from MS3D works pretty much like this: first there is an 16-Bit ushort numVertices in the file, then theres numVertices times the Vertex struct. Skipping parts of the file by advancing the stream's index by numVertices*sizeof(Vertex struct) should be doable, but you cannot skip reading numVertices.

I'll give your suggestion some thought, haven't considered that possibility yet since my plan was to load the complete Model first, translate it into an Shader-, Animation- and Vertex-Cache-friendly structure (which i hoped your Interface could specify) and do a binary dump from that into my own minimalistic file format. The reason is, that if you want more than OpenGL's fixed-function Gouraud shaded material and have more than 1 animation, it's necessary to write some kind of editor that allows to define materials and a way to group the animation-keyframes into sequences like walking forwards/right/left/back, jump, attack, etc. (milkshape exports all animations as a single large array of keyframes). At this point I do not intend to provide a complete animation library including editors, what I had in mind is providing the loader and a simple demo application that shows how to render a model with fixed-functionality and skinning. The possibilities how to define the materials and sequences are too numberous to do a simple abstraction for such a library IMHO.

Saving MS3D is not much more difficult than parsing it (since you have to understand the file format either way), but involves alot more error checking. Right now I do not see any use for that, except for a mesh editor application? Considering a converter, you should know that Milkshape itself can import several dozen different formats (and there exist plugins and a SDK for more), so even if a developer team has several artists each using different modelling/animation packages there will be a way to import the file into Milkshape and save out a .MS3D (we did exactly that for a HL Mod).

I haven't given deployment much thought yet, I was hoping someone was already working on Model loaders for OpenTK and could provide an Interface to pass the parsed data to, I wouldn't mind if it was simply included into your library. It's not a commercial enterprise, after all I've chosen Milkshape also because of it's low-cost-yet-powerful nature ...and no, although this may sound like a PR campaign, i'm not working for the developers of Milkshape :P It's simply the best option I found for my requirements.

-Inertia

Inertia's picture

It seemed to be the best solution to just load everything, solely for the purpose of keeping the parsing simple to maintain (in case the file format changes it will be much less trouble going through a few straightforward functions than going through code bloated by conditionals and layers of abstraction). What appears to be the biggest problem is the the lack of a Math library for handling Vectors/Quaternions/Matrices that can be fed to OpenGL. I've written some helpers for that purpose, but i'm getting the impression it'd be a good idea to stop working on the loader and write a properly designed and debugged Math library first. Especially when it comes to skeletal animation it is very tricky to figure out if the bug is introduced by the math helpers or wrong conversion of the parsed data (I've managed to build a proper skeleton for the bind pose, but the animation keyframes are rather complicated math and currently just garbage).

Hope this helps you, when you implement your own loaders for OpenTK :)

P.S. I'd really appreciate if someone could point me towards a solid and proven 3D Math library for C#, the only thing that came close to what i'm looking for was the Exocortex3D Library, but it appears to be abandoned since 5 years or so...

the Fiddler.'s picture

There are two free math libraries for .Net that I know of, dotnum and Math .Net. The second seems active, but I don't think the first one is maintained anymore.

I am going to add basic Vector, Matrix and Quaternion functions in OpenTK, but this is in the back burner right now. If you do write some math functions yourself, I'd love to add them in OpenTK (there's only so much a single developer can do!). However, I don't think that a pure managed solution will be fast enough for skeletal animation - but that's another story entirely.

In any case, I think model loading/optimisation/animation is best left to higher-level libraries, with OpenTK/Tao providing access to the low-level rendering functions. Any other solution would be too limiting. The only reason I am/was thinking to write a simple loader, is to add some more complex demos for OpenTK.

Inertia's picture

Thanks for the links! Math.Net appears promising, i'll take a closer look at it. I'm afraid the helpers I wrote so far won't be of much use to you, it's nowhere near a full implementation of vector math and obviously contains bugs. Just the operations required by my current project.
Maybe you should take a look at http://www.exocortex.org/3dengine/ and contact Ben Houston if you find the library useful, it seems abandoned and he might not bother if you adopt it for OpenTK (it contains Vector3, Triangle, Plane, Matrix4x4 and Quaternion classes which can interact). It was written for a 3D engine and might be exactly what you are looking for. The only reasons why I'm currently not using it are 1) abandoned and 2) it could use more overloads. Besides that it appears quite mature, well documented and debug'd.

[higher-level libraries]
Agreed, that's why I posted here at the OpenTK forums instead of the Tao ones. I don't think any of your projects should go as far as trying to provide allround libraries for model/world rendering (that's where projects like Axiom come into play), my guess was simply that I'd more likely find the interface I was looking for over here ;) Nevertheless it would have been quite some help for me (and I assume for others too) if there were some public examples how to start implementing your own model loaders, no matter what the relation between "do" and "don't"s looks like. It'd be at least a starting point when you grow tired of glu models.

I've written 2 little games in XNA before switching back to OpenGL (Tao), and the only things I miss are the helper classes that increase productivity such as the 3D math library, easy content loading and (last but definitely not least) the documentation. (This is not a complaint, just an observation from my perspective.) It was just nice to prototype an idea in very short time, without having to deal with texture/model formats and loading. Thanks to DevIL basic texture loading is quite easy in Tao, but models are not (that's why I started this MS3D loader). Maybe this will help other people's productivity too, and motivate them to share their work aswell. After all, productivity is why most of us code C# now ;)

-Inertia

JTalton's picture

I would be very interested in a common parsing of 3D model formats. It is not an easy task though.

I have been (very slowly) working on a simple model editor.
http://www.golem3d.com
It currently only supports mesh animations, and if I ever get the full feature set finished for that, I have designed the code to support skeletal animations in the future.

I converted it to use OpenTK from Tao today, and it seems to work well.

It seems like we would need two common parsing formats, one for mesh animations, and one for skeletal animations.

Inertia's picture

nice work, the interface appears more intuitive than Milkshape's. Tbh I haven't looked into mesh animations yet, how does a keyframe look like? a float for the time of the keyframe and then a huge array containing all Vertices (Position, Normal, UV, Color etc)? Can materials and triangulation change aswell? Or do you store a matrix for each mesh in the model as keyframes and the meshes themselves remain static? Sorry if those a stupid questions, but a quick google search resulted in skeleton based solutions for the first few pages.

What's probably similar for both (mesh- and skeletal-animation) solutions is that the animations are one large array of keyframes, which must be split in order to extract sequences (walk, run, jump etc). This could be a starting point for abstraction?

JTalton's picture

Thanks. It is a fun pet project.

Most mesh animated models have the exact same number of vertices for each frame. This allows smooth interpolation between frames for all vertices. Normals for each vertex in each frame are also stored. There is one texture coordinate for each vertex of the model.

The only real format my editor supports currently is the Quake II (.md2) format which is exactly above. It is a lossy format that compresses the values down to a short and has a scale and translation for each frame to change the short back to the right values. The standard frame rate for quake II models is 10 fps.

Golem3D has a plugin architecture for model formats. I have a lot of plans for it, including skeletal support (eventually), but it all takes a good bit of time.

One format I have looked at is the Ogre3D engine model format. They use binary formats but have a converter to convert to an XML format. There is one file for the mesh (no animation in it) and a separate file for the skeletal animation that can be applied to the mesh. I have found that their implementation is pretty well thought out. I think that would be a good place to start if writing up some requirements.

The nice thing about an XML format is that someone can write a XSLT transform that can convert the XML into another format. The problem with XML is that the files can get really large. But drive space is getting cheaper and cheaper so that may not be an issue.

James

Inertia's picture

Thanks for the info! Converting to short is an interesting idea, i've made the observation too that the model's vertices could probably fit into half-precision floats, but didn't investigate it much further yet (category: future optimizations ;]).

Maybe you should take a look at the Collada format http://www.khronos.org/collada/ , it's a XML format aswell and supported by more and more applications. To my knowledge http://www.feelingsoftware.com offers a C++ library that can read/write Collada files (you'd probably have to write a wrapper, but that would be alot less hassle to maintain than writing the loader on your own). Tbh I didn't look into it much, because I wanted to write a loader on my own to get a deeper understanding of skeletal animation.

Another possibility (I just came up with it recently) for importing models could be using XNA to import the Model/textures/shaders and convert that into your application's internal format. The HLSL shaders would ofcourse be useless and users must install the XNA Framework, but you could use any format XNA can import (afaik .FBX and .X natively, but i've seen loaders for .BVH and .DAE too). This might not be a good solution for your editor though, since you will probably want to be able to export to the formats aswell.

Inertia's picture

I've found something that goes into the direction of what I had in mind when originally starting this topic, the file Examples/Shapes/Shape.cs in the OpenTK distribution attempts to mimic an interface like I had in mind.

Is this serious, or just an example to workaround the lacking GLU objects?

What I really had in mind is something like this to specify a Geometry Interface:

fully abstract class iMesh3D
    {
        struct Vertex;
        Vertex[] Vertices;
        uint[] Indices; // ~1 billion Quads
        byte VertexCacheOpt; // 0 if none, otherwise the Vertex Cache size the mesh is optimized for.
        BeginMode PrimitiveType; // Points? Tristrip? Quads?
        bool UseDrawElements; // else use GL.DrawArrays
        uint RangeStart, RangeEnd; // RangeEnd==0 draw all
        Material matter; // which shader/tex must be bound to draw
        uint VBO;
        uint IBO;
        byte Validity; // bitmask to check array state
        // ClientMemVertices = 0x01, ClientMemIndices= 0x02, VBOVertices = 0x04, VBOIndices = 0x08
    }

and some base class derived from it, defining a default Vertex. Note that this does not include Orientation or a Draw() method, it's rather an interface so model loader, editing-, optimizing- and rendering-functions have an common interchange type.