File Formats for 3D Game Performance

Started by
15 comments, last by EddieV223 11 years, 6 months ago
Good day, everybody smile.png

Opinions very, but I would like to get experienced ones on which 3D object file formats-including for terrain, vehicles, trees, and so forth-result in the best performance, all other things being equal. This is the general question.

The more specific question is, which file formats for 3D objects make better performance for the C# based games which I will be creating?

Why in the world would any game developer use 3ds file format? Is there some kind of performance advantage because it conforms to the old naming conventions?

The 3D model game file formats which I have used are 3ds, obj, x, and a proprietary one not published yet, so I have some experience.

Any and all comments, discussions, and criticism is welcome as long as it is somehow related.


Clinton

Personal life and your private thoughts always effect your career. Research is the intellectual backbone of game development and the first order. Version Control is crucial for full management of applications and software. The better the workflow pipeline, then the greater the potential output for a quality game. Completing projects is the last but finest order.

by Clinton, 3Ddreamer

Advertisement

Good day, everybody smile.png

Opinions very, but I would like to get experienced ones on which 3D object file formats-including for terrain, vehicles, trees, and so forth-result in the best performance, all other things being equal. This is the general question.

The more specific question is, which file formats for 3D objects make better performance for the C# based games which I will be creating?

Why in the world would any game developer use 3ds file format? Is there some kind of performance advantage because it conforms to the old naming conventions?

The 3D model game file formats which I have used are 3ds, obj, x, and a proprietary one not published yet, so I have some experience.

Any and all comments, discussions, and criticism is welcome as long as it is somehow related.


Clinton


Most exchange formats are not good for real time 3d. Common exchange formats being, fbx, 3ds, collada ect. You will want to use a format made specifically for real time, such as x, mesh (ogre3d) ect... The difference is in load times mostly but also depending on how the program stores the data internally, you may also get better performance.

If this post or signature was helpful and/or constructive please give rep.

// C++ Video tutorials

http://www.youtube.com/watch?v=Wo60USYV9Ik

// Easy to learn 2D Game Library c++

SFML2.2 Download http://www.sfml-dev.org/download.php

SFML2.2 Tutorials http://www.sfml-dev.org/tutorials/2.2/

// Excellent 2d physics library Box2D

http://box2d.org/about/

// SFML 2 book

http://www.amazon.com/gp/product/1849696845/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=1849696845&linkCode=as2&tag=gamer2creator-20

Uh, the file format will have zero impact in actual rendering performance, as the model will be converted to the program's internal format regardless of the original format. As for loading performance, it really depends, binary formats are usually the fastest, and also take the least space on disk, but are comparatively much harder to parse.

For instance, many people use .obj not because it is fast, but because it is very easy to parse, readily editable by any text editor, and is usually good enough for most models even if it is quite wasteful in terms of storage. But loading the same model from a .obj and from a .3ds will yield the exact same model representation in your game's memory and there will be no performance difference after loading is complete.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

The best format for a game that is loading models on the fly will be a custom one that maps directly to it's internal data structures. Otherwise, it doesn't matter.

binary formats are usually the fastest, and also take the least space on disk, but are comparatively much harder to parse.

Hm, I would say the exact opposite (talking about the parsing part).

Text formats are easier for human to read and understand, but reading them from a code is harder because you must do some string processing, finding keywords etc. and last but not least - converting textual representations of numbers into actual numbers.

Binary formats are nearly impossible for a human to read. But for a computer code it's usually very easy. Specifically when talking about 3D mesh formats, there isn't much surplus information in the binary files, all you need to know is that for example the first 4 bytes represent the number of faces, then you have 3*4 bytes for a normal vector, then 3*3*4 bytes for 3 vertices of a face etc etc etc (simplified example of a binary stl).
And when reading those bytes, for example 12 bytes of a normal vector, you can directly use this data to fill your vector structure in the code, no processing needed, just file.read or memcpy.


The best format for a game that is loading models on the fly will be a custom one that maps directly to it's internal data structures. Otherwise, it doesn't matter.

My vote for this. There's nothing better than being able to fill your whole vertex buffer by a single file.read call, reading (vertexsize * vertexcount) bytes.

[quote name='Bacterius' timestamp='1349243010' post='4986291']
binary formats are usually the fastest, and also take the least space on disk, but are comparatively much harder to parse.

Hm, I would say the exact opposite (talking about the parsing part).

Text formats are easier for human to read and understand, but reading them from a code is harder because you must do some string processing, finding keywords etc. and last but not least - converting textual representations of numbers into actual numbers.

Binary formats are nearly impossible for a human to read. But for a computer code it's usually very easy. Specifically when talking about 3D mesh formats, there isn't much surplus information in the binary files, all you need to know is that for example the first 4 bytes represent the number of faces, then you have 3*4 bytes for a normal vector, then 3*3*4 bytes for 3 vertices or a face etc etc etc (simplified example of a binary stl).
And when reading those bytes, for example 12 bytes of a normal vector, you can directly use this data to fill your vector structure in the code, no processing needed, just file.read or memcpy.
[/quote]
Well, theoretically I would agree with you (and your explanation is correct) but usually, textual formats are left as simple as possible because, well, optimizing something that isn't meant to be fast is contradictory, whereas binary formats are usually much more complex as they feature stuff like binary compression, recursive model structures, special constructs, etc... to make them even more efficient. They also often contain tons of metadata.

In short, I correct my statement: binary formats often contain much more stuff to parse, but are indeed easier to parse by a computer.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Just another note to the latest posts - if you decide to make your own mesh file format, you really should make it binary and as Daaark said map it directly to your internal structures. I personaly wouldn't see any point in creating a custom text mesh file format.
I did specifically what Daaark mentions. I work with .dae (COLLADA) files in the 3d editor, but then use a custom tool to load those up (with AssImp.NET), convert the data to my proprietary mesh object, and then serialize that out into a binary file. That way I only ever store exactly what the library needs to build the mesh at runtime.

Hazard Pay :: FPS/RTS in SharpDX (gathering dust, retained for... historical purposes)
DeviantArt :: Because right-brain needs love too (also pretty neglected these days)

In my current engine, I use in-place binary formats wherever possible. Most of these don't require any kind of parsing step, or OnLoad/Init type functions whatsoever. You just read the file from disk into memory, cast the binary blob to some specific type of structure, and your game is ready to go immediately. Loading times are completely bound by I/O speed.

The main thing that OnLoad/Parse functions do is patch up pointer values, because you obviously can't serialize pointers to disk directly -- so most of my resource structures don't use pointers, which means they can be read/written to disk as-is, without any kind of serialization layer. Instead of pointers, I use offsets and integer addresses.

e.g. Some structures from my shader file format look like:struct CBuffer
{
u32 index;
StringOffset name;
Offset<CBufferDefaults> defaults;
Offset<List<VariableInfo>> variables;
};

struct Sampler
{
u32 index;
StringOffset name;
Offset<SamplerState> samplerState;
};

struct Technique
{
u32 passMask;
Offset<List<Pass>> passes;
Offset<List<CBuffer>> cbuffers;
Offset<List<Sampler>> samplers;
};
struct ShaderPackBlob
{
...
u32 numTechniques;
ArrayOffset<Technique> techniques;
ArrayOffset<StringOffset> techniqueNames;
};
The shader compiler tool takes [font=courier new,courier,monospace].hlsl[/font]/[font=courier new,courier,monospace].cg[/font] files, parses/compiles them, and uses a C# binary writer to write out the above structures. The C++ engine can then just load the whole binary file into memory, and cast it to a [font=courier new,courier,monospace]ShaderPackBlob[/font], and the game can access any of the sub-structures without having to parse the file.
[edit] Just realised you're asking for a C# engine...
I'm not sure how to implement in-place loading of binary structures like this in C#, but it would probably involve [font=courier new,courier,monospace]unsafe[/font] and [font=courier new,courier,monospace]StructLayout(LayoutKind.Explicit)[/font]...

...clever binary casting techniques, etc...


Can I ask how you handle writing out objects that are runtime-dependent? (I may be making a false assumption here, as well). I was under the impression that things like buffers and Texture objects that require a device context to create are volatile "memory-only" elements. That's one thing I still do in my onLoad methods from the binary format: create the device-contextual buffers via the game's DX11 device before handing off the object reference.

Am I completely off-base in my understanding of these objects? Or is the data valid, and I just need to do what you mention and correct the buffer's internal relation to the device that will render it?

Hazard Pay :: FPS/RTS in SharpDX (gathering dust, retained for... historical purposes)
DeviantArt :: Because right-brain needs love too (also pretty neglected these days)

This topic is closed to new replies.

Advertisement