Game Development

Blog 825: My Milkshape Brings All the Models to the Unity

I’ve been using Milkshape 3D for all my modelling and animation needs since I first discovered it in my Warcraft III days (though it wasn’t until Guesst finally cracked animation export to MDX that I really got going). To be fair it was the first 3D modelling and animation tool I ever used, but I fell in love nonetheless. It’s very simple; you might say it’s lacking in features, but I say it’s clean and focused, and it’s ideally suited to working on the low-poly creatures, vehicles and decorations that I enjoy/am capable of making.

There is one tiny wrinkle: in order to get that artwork into Unity, I have to export it to an interchange format. That’s a whole extra three or four clicks! What if… what if Unity could understand Milkshape files directly?

My Milkshape Brings All the Models to the Unity

My interest was ignited when I read about Unity’s scripted importers; I don’t really know when this feature first appeared, but it allows you to pick a file extension and then provide all the logic that turns whatever is inside that file into meshes and prefabs that Unity understands. Seamlessly, just like the built-in importers for common file types.

Meshes and prefabs? I build those through automatic systems all the time — I wrote my own terrain engine after all, once I realised that meshes are just collections of 3D coordinates with triangles playing join-the-dots. Why shouldn’t I be able to do that based on data incoming from another program?

I would also like to be able to strip my “guide” meshes, so I don’t have a thousand bits of duplicate junk imported that I only use to help me animate.

But Milkshape files are a proprietary binary format! Whether or not I could understand the concept of 3D mesh data, I had no way of understanding how the file was structured to actually load that data… or did I?

On the Milkshape website’s download page, there is a stand-alone Milkshape file viewer that includes the C++ source code. Sure, I’m not about to start doing anything in C++ (though the thought of building some specialised extensions to Milkshape itself has crossed my mind), but when I took a peek inside it was actually surprisingly comprehensible — it’s just a load of values that must be read in a defined sequence.

All I had to do was convert a few datatypes from their C++ forms to C# equivalents while I reimplemented the sequence and that was that. I had loaded the Milkshape data! Me, who used to be terrified of binary files!

Sitting here hoping that I did not BYTE off more than I can chew.

Obviously it’s not as easy as that. Milkshape stores mesh data in a slightly different way than Unity, so there’s an extra translation step.

Most notably, while Unity stores everything in a mesh per-vertex, Milkshape stores a lot of vertex data as part of the triangles — so two adjacent triangles that share an edge have independent normals and UV coordinates for the overlapping, “shared” vertices. Indeed, the only way to know if they are truly shared is if they have identical normals and UV coordinates (well, and belong to the same Smoothing Group); that’s not an insurmountable problem, you just have to look for duplicates and collapse them together. (A thing I am well-versed in doing, because Terragne generates a load of duplicate triangles and I don’t know why so I just strip them at the end. Truly I am the laziest of devs.)

Then there was also the absolute classic, that both Unity and Milkshape use subtly different coordinate systems. I didn’t notice this until I had UV-mapping implemented and noticed that the texture was backwards. Looks like the X axis is negative in Unity, tsk tsk. Thankfully they’re otherwise the same; both Y-up and Z-forward.

You can tell this one came in via my importer because there are… uh… still a few UV kinks to be worked out.

So there’s me with geometry in and behaving (mostly) nicely. Geometry, that is precisely half the problem.

I have no idea how to handle animations in Unity. Even as a user, I’ve never got arbitrary animation clips to record and replay; this is why all my arbitrary motions are scripted (oops). Animated characters made in Milkshape and imported via FBX file are a black box and I have no idea how any of it is realistically stitched together. The best I’ve ever done is take an existing skinned mesh and reassign it to a different set of bones, to enable “clothing” in an avatar system I once experimented with at a previous job.

I mean, I’ve managed to get the skeleton in easily enough; that’s a straightforward set of coordinates in a heirarchy, and each vertex clearly knows what bone it’s assigned to. I even got all the animation data in, the set of movement and rotation keyframes and their timings. I know the rotation keys are quaternions and Unity understands those so I believe it’s intact and serviceable (though how the negative-X coordinate change affects the 4D space of quaternions is anyone’s guess).

But after that? Uhhh… let’s make that a problem for another day.

As it stands, though, being able to do all my static meshes without extra export/import steps could still be a boon. After all, having to manage two parallel folder structures for the source art files and the game exports is a constant source of confusion. You would not believe how often I name a source file one way and its target export another and then get lost when I need to make a change.

Of course the long term dream is: if I can get Unity to fully understand Milkshape files at editor/import time, it couldn’t take much more to get them importing at runtime — and then we can start dreaming about mod support…

And you tell me...

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.