New 3D model format and single header SDK

Started by
29 comments, last by bzt 4 years, 2 months ago

Hi Promit,

Thanks for your words. I haven't though of my project as cool, only hopefully useful that might save a lot of trouble for beginners.

About WebGL viewer, it can be done, sure. However it would require to implement the M3D importer in Javascript if I'm correct (assuming you meant a portable viewer in a browser).
About the WebGL converter, if you meant .glTF output by that, then it's already done. The M3D format is supported in Assimp, and Assimp can convert into .glTF2. Also you can load M3D files into Unity, Godot, and with a little hack into Unreal as well, not to mention the numerous other engines that use Assimp. But keep in mind that a library that aims to be universal is never as performant as the one that specializes in one file format only.

About Maya, Max and ZBursh: I don't have those, and if they are not Open Source, I'm not interested in them. The M3D format is Open Source and MIT licensed, the specification is freely available to anyone. If someone on this forum wants to create a plugin for those software, the contribution would be much appreciated. I'll provide all the help I can give with that, but I won't write plugins for proprietary software that I don't use.

What do you mean by VSCode plugin? The M3D SDK has just 5 simple functions altogether. All the IDEs I've tried were able to read the header file and provide code-completitions and suggestions, both for the C functions, structs and for the C++ wrapper class methods. What do you expect from that plugin to do exactly? The M3D SDK itself is tested under VS, and MSVC compiles it without a single warning.

A little update, I've just pushed a new version of the m3dview viewer which now compiles under MinGW/SDL2 too.

Cheers,
bzt

Advertisement

Hi Promit,

It took me a day, but I've implemented a WebGL version (a WebGL converter already exists). It is a polyfill that allows you to use M3D files in IMG tags just as any other image files. The whole source is approx. 33k (minified), and it is written in pure Javacript, totally dependency-free (no jQuery and other bloated libraries needed). Once loaded, the IMG tags are replaced by CANVAS tags, and you can rotate the models in 3D using drag'n'drop. I haven't tested it yet, but it should work on mobiles with touchscreens too.

https://gitlab.com/bztsrc/model3d/tree/master/webgl-js

This is obviously not a fully featured loader, it is just a technical Proof of Concept. It can load coloured meshes, same as the example 80 SLoC C code on repository's main page, but this loader also generates smooth normals if the loaded model lacks that information.

Please note that Javascript is not supposed to be used like this. For example, there's no way to access the image file's original raw data. I had to download them again with an XMLHttpRequest (that's the ONLY way to get binary data in JS besides the local file reader). And you can't simply use binary operations in JS, you have to copy the data over and over again from bufferArray into TypedArrays and local variables forth and back again. Some combinations are impossible even in theory, because the JS specification just s*cks (for example, try to convert an UInt32 variable with a color into an UInt8Array or Float32Array ;-) ). Javascript was simply not designed to efficiently handle binary data. But I've hacked it to do that, so there you go!

Cheers,
bzt

If you are aiming for maximum compression, then the use of png for embedded textures is unfortunate. In my experience lzma+bmp beats png for compression ratio, and lossless webp beats both.

Hello,

I think your format is very interesting!

If my project (http://causetree.com) is successful, I will take a closer look.

I would only need a loader in Java ... ;-)

Best regards

Arvid Größer

@a light breeze: I've never aimed at maximum compression. Having a decent ratio with fast uncompression time was more important. Also I deliberately picked a well-known and widely adopted RFC standardized deflate algorithm. PNG was chosen because it uses exactly the same algorithm, which means smaller code base. (sidenote: lzma + bmp? ROTFL I can't believe you're serious about this)

@ArvidGrößer: Java can link with C libraries. Just create a .c/.cpp file, include the m3d.h header in it, compile as shared library. (I personally don't code in Java, I used to do that decades ago, and I made a promise to myself never again.)

Cheers,
bzt

For bmp, read "raw uncompressed data". Yes, lzma-compressed raw data beats png in my experience.

There are two problems with using png. One is that it's compressed, even if the rest of the file is not, which means that applying external compression on the entire file will result in double-compression, which is a waste of both space and time. The other is that carries with it a ton of header data that I don't want or need.

For maximum compression, I use lzma and webp (lossless if I can afford it, lossy if my need for maximum compression overrides my need for clean-looking textures). For maximum speed, I use raw uncompressed data. Your file format provides neither, though it may provide an acceptable compromise for some cases.

bzt said:

Hi Promit,

It took me a day, but I've implemented a WebGL version (a WebGL converter already exists). It is a polyfill that allows you to use M3D files in IMG tags just as any other image files. The whole source is approx. 33k (minified), and it is written in pure Javacript, totally dependency-free (no jQuery and other bloated libraries needed). Once loaded, the IMG tags are replaced by CANVAS tags, and you can rotate the models in 3D using drag'n'drop. I haven't tested it yet, but it should work on mobiles with touchscreens too.

https://gitlab.com/bztsrc/model3d/tree/master/webgl-js

This is obviously not a fully featured loader, it is just a technical Proof of Concept. It can load coloured meshes, same as the example 80 SLoC C code on repository's main page, but this loader also generates smooth normals if the loaded model lacks that information.

Please note that Javascript is not supposed to be used like this. For example, there's no way to access the image file's original raw data. I had to download them again with an XMLHttpRequest (that's the ONLY way to get binary data in JS besides the local file reader). And you can't simply use binary operations in JS, you have to copy the data over and over again from bufferArray into TypedArrays and local variables forth and back again. Some combinations are impossible even in theory, because the JS specification just s*cks (for example, try to convert an UInt32 variable with a color into an UInt8Array or Float32Array ;-) ). Javascript was simply not designed to efficiently handle binary data. But I've hacked it to do that, so there you go!

Cheers,
bzt

Nice! Seems like it was a very straightforward conversion even with the weird JS issues, which I think is a positive comment about the model format as well.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
a light breeze said:

For bmp, read "raw uncompressed data". Yes, lzma-compressed raw data beats png in my experience.

There are two problems with using png. One is that it's compressed, even if the rest of the file is not, which means that applying external compression on the entire file will result in double-compression, which is a waste of both space and time. The other is that carries with it a ton of header data that I don't want or need.

For maximum compression, I use lzma and webp (lossless if I can afford it, lossy if my need for maximum compression overrides my need for clean-looking textures). For maximum speed, I use raw uncompressed data. Your file format provides neither, though it may provide an acceptable compromise for some cases.

Hi,

I'm well aware, how uncompressed bmp looks like, thank you. It could be that for some images lzma produces better results, but since lzma is not nearly as widely adopted as RFC1950, I wouldn't bother to check. Unlike your images which are specific to your engine, these model files supposed to be parsed by many applications and many languages (not all has lzma libraries).

On your problems about png: why is it a problem that it's compressed? You don't need to inline textures in the model files at all, that's optional. Actually there are two use cases:
1. distribution: the goal is compactness and consistent encoding using widely adopted algorithms only, so you inline textures in quantized pngs. It is more important to have only one file than providing fast load times anyway. Creating a Huffmann-tree of a compressed bit-chunk is not waste of space, it could further compress the data (strongly depends on the actual data), and it is neither waste of time because time component does not count at all in this case.
2. in a game engine: the goal is modularity, you most definitely DON'T want to embed any textures, because you'd like to instantiate the same model for different objects. (Example: think about Minecraft's villager and zombie villager. Same model, same animations, different textures). In this case you can use any image format for the textures you like, because they are stored and handled separately to the model.

What you mean by "carries with it a ton of header data that you don't want or need"? Makes no sense! First, you were not listening, the M3D SDK is a single header file which can uncompress pngs on its own, no need for tons of headers, just the one. Second, it's not much code anyway. Third, the same algorithm is used for the model files, so you NEED THOSE regardless if you store textures in png or not, and the actual png specific part is insignificant (a few small functions, nothing more). When compiled into x86_64, the compression related code is about 20K (and the entire SDK is about 80k). Yes, you can use uncompressed 3D models in a game engine to speed up load time, in which case that 20K is unnecessary, but frankly it does not worth complicating the SDK for that much code. What is that 20K compared to your entire game? 0.00001% ? 0.0000000001% ?

As I've said maximum compression was never a goal, using a well-known and widely adopted compression on the other hand is. The M3D files encodes vertices and meshes very efficiently, even without stream compression it produces pretty small binary files (much smaller than the competition, that's for sure). As a bonus, we can use exactly the same code for decompressing inlined textures.

Cheers,
bzt

Promit said:
Nice! Seems like it was a very straightforward conversion even with the weird JS issues, which I think is a positive comment about the model format as well.

Thanks! Yes, the model format stores data only relevant for the model and only in a form that's relevant to the model itself (no engine specific parts or encodings), so it is extremely easy to port. If you like, model data is based on pure geometry only (a triangle consist of three points in 3D space after all, no matter of the engine or visualization framework :-) )

Cheers,
bzt


Hi,

A little update on this, there are new features. As a reminder, the format's SDK is a dependency-free, single C/C++ header file, has a Blender exporter and included in Assimp too (with limited support unfortunately).

https://bztsrc.gitlab.io/model3d

The Model 3D format now can efficiently store:
- triangle mesh
- per triangle normals
- skeletal animations
- PBR materials
- inlined textures
- procedural textures and surfaces (a proof-of-concept Lua binding is provided, but you can use other scripts)
- parameterized mathematical formulas (like Bezier curves, B-splines, NURBS etc.)
- multilingual, UTF-8 annotation labels (new)
- voxel images (new)

The converter utility is capable of converting from the following formats:
- Wavefront OBJ (with automatic mesh triangulation, plus imports curves, splines, NURBS etc.)
- BINVOX voxel files
- Magicavoxel VOX files
- Qubicle QB files
- 3DS classic format
- 3DS MAX format
- DAE files
- PLY, STL and other 3D scanner outputs
- able to convert textures into quantized PNG images on-the-fly
- all static model formats that Assimp can interpret
- all animated model formats that Assimp understands and contains only skeletal animation (direct mesh animation not supported, only when aiNodeAnims are referencing aiBone nodes)

There's an extremely simple m3dview tool included, which can display animated models and showcases how to use the SDK API (available backends GLFW, SDL, GLUT, compiles under Linux, MacOSX and Win (mingw)). You can use this viewer to display any Model 3D file using OpenGL (tested up to 2,1 million triangles) and to debug animation frames and skeleton interpolations. Example models can be downloaded from the website (static meshes, rigged and animated models, coloured meshes as well as with materials and inlined textures etc.)

Cheers,
bzt

This topic is closed to new replies.

Advertisement