What kind of things are needed to draw good 3D models?

Started by
6 comments, last by spek 12 years, 5 months ago
I'm currently writing a game ending, and I want it to have a decent render engine. I plan on having a binary format for all game resources, and I was wondering what kinds of things you would need in a 3D model.
I understand at the minimum you would want vertices, and possibly an index buffer, but I was wondering if anything had any good ideas on what a good 3D model format would be. Should it have shaders, or should the shaders just be separate? I was thinking I could have each Vertex have a position, a normal, and a texture coordinate. Then there could be a bump map, texture, and whatever else I want, but of course some models are rigged, so does anyone have a specific idea on what the bare minimum of a 3D model in a game is?
Advertisement
Make it flexible. One time all that extra data is an unnecessary load. Another day you may need an extra array of data you forgot about. But to give you an idea what could be stored per vertex:
- position
- texture coordinate (primary)
- texture coordinate secundary (third, fourth, ...)
- normal / tangent / bitangent
- (blend)weights
- (bone)weights
- (ambient)occlusion factor(s)

Keep in mind cards normally only have a limited amount(8) of registers to push additional data along with the vertices/normals though.


Other than vertex-data, you can store pretty much everything in your model.
- Animations (skeleton, keyframes)
- Material definitions (texture, shader, parameters)
- Script
- LOD (mesh in several variants)
- Physical collision hulls / ragdoll data
- Sub-objects
- Particle generators, sprites
- Motion definitions
- ...

But unless it's used for specific targets, I would focus on the word "model". Animations and materials for example are usually stored seperate. The model could refer to a material/shader, but the actual code can be done elsewhere. Imagine you fix a shader-bug and have to fix it in all 1.000 model-files...

Step 1 is to write down what you really need, or what you expect in the near future. Step 2 is making a flexible format that can be extended (and backwards compatible), cause you'll be adding or changing stuff for sure. Step 3 is storing the stuff in a smart way so you can load the whole thing into the memory with just a few read calls.
Really, what I'm trying to do is figure out what the best model format is. I don't want animations to be part of the model itself, but animations can go into that map file and you can link an animation to a model or whatever. I have an idea of what I want the vertices to look like

struct Vertex
{
vector3 position;
vector3 normal;
vector2 texcoord;
};

And I definitely want to allow multiple bones per model for rigging or whatever. I plan on having ALL vertex and index data in their respective buffers. This means that every single model in a map will be in the same vertex buffer.
This is exactly the problem with writing an engine in isolation, without the needs of a specific game in mind. Even with our input, it's very unlikely that you will be able to predict the needs of every possible game that might use your engine.

Model formats can contain almost any sort of per-vertex data, but pretty much every game is going to have its own unique requirements. Rather than try to define explicitly what goes into a vertex (position, normal, and so on), you should think in terms of generic streams of data: they are going to need to store floating point data, integer data, with anywhere from 1 to 16 channels in each element - make it as generic as possible, and you might just cover 90% of cases.


I plan on having ALL vertex and index data in their respective buffers. This means that every single model in a map will be in the same vertex buffer.

This is almost certainly a mistake: you are forcing implementation details on your users. What if the game developer decides to animate one of those data streams (say, texture coordinates), but not the rest? Then they might want to place it in a separate vertex buffer optimised for write access.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I would use a variable-sized structure that allows data-described vertex formats, buffers, links to material data, draw-calls, sub-meshes and bounding volumes.
e.g.[source lang=cpp]struct ModelBlob
{
int numFormats;
VertexFormat formats[numFormats];
struct VertexFormat
{
int numStreams;
Stream streams[numStreams];
struct Stream
{
int numElements;
Element elements[numElements];
struct Element
{
int semantic;//position, texcoord0, texcoord1, etc...
int type;//float, float2, float4, byte4, etc...
int offset, stride;
}
}
}
int numVertexBuffers;
Buffer vertexBuffers[numVertexBuffers];
struct Buffer
{
int size;
char* data;
}
int numIndexBuffers;
Buffer indexBuffers[numIndexBuffers];
int numMaterials;
Material materials[numMaterials];
struct Material { /*links to shaders/textures/cbuffers*/};
int numDrawCalls;
DrawCall drawCalls[numDrawCalls];
struct DrawCall
{
byte type;//e.g. indexed, non-indexed, etc...
union { DrawPrimitivesArgs a; DrawIndexedPrimitivesArgs b; };
}
int numSubMeshes;
SubMesh submeshes[numSubMeshes];
struct SubMesh
{
int vertexFormat;//index into formats
int vertexBuffersToBind[formats[vertexFormat].numStreams];//indices into vertexBuffers
int indexBufferToBind;//index into indexBuffers or -1 for non-indexed meshes
int drawCall;//index into drawCalls
int material;//index into materials
}
int numBoundingVolumes;
BoundingVolume boundingVolumes[numBoundingVolume]
struct BoundingVolume
{
Aabb bounds;
int numMeshes;
int meshes[numMeshes];//indices into submeshes
}
}[/source]

This is exactly the problem with writing an engine in isolation, without the needs of a specific game in mind. Even with our input, it's very unlikely that you will be able to predict the needs of every possible game that might use your engine.

Model formats can contain almost any sort of per-vertex data, but pretty much every game is going to have its own unique requirements. Rather than try to define explicitly what goes into a vertex (position, normal, and so on), you should think in terms of generic streams of data: they are going to need to store floating point data, integer data, with anywhere from 1 to 16 channels in each element - make it as generic as possible, and you might just cover 90% of cases.

[quote name='Nyxenon' timestamp='1320710001' post='4881565']
I plan on having ALL vertex and index data in their respective buffers. This means that every single model in a map will be in the same vertex buffer.

This is almost certainly a mistake: you are forcing implementation details on your users. What if the game developer decides to animate one of those data streams (say, texture coordinates), but not the rest? Then they might want to place it in a separate vertex buffer optimised for write access.
[/quote]

I actually do have a specific game in mind for this engine. My idea for my engine will implement its own script engine, which CAN take care of certain rendering. I know exactly how I want the engine to be done, the only big problem I'm having is with model formats.

Before you make hasty judgements and say the task at hand for me is too hard (as far as scripting goes), I have a bit of experience with implementing scripting. I know exactly how I'm going to make the script engine, and it will probably be the easiest part of the engine itself. I've also put most of my planning into the script engine so far. Everything I've thought of for the engine so far I feel that I can do just fine, the only thing I'm not so sure of is putting the models into the map, and how I want to models to be represented/rendered. I think if I could make a model type, I could do proper rendering and all that, but one thing I'm having trouble figuring out how to do is taking the model from say, 3ds max, and putting it into my own binary format which will make it easy to build it into the map file. The map file will have a sort of file table that is indexed, and each asset will have offsets for where in the map file a resource is. After talking with a friend of mine, and doing some research on the matter without yielding any results, I've decided to make the engine a 2D engine. Yet again, this engine will be specific to a certain kind of game. It's not going to be a simple API, the plan for it is to make an editor, a scripting language, and a base executable. You just add in your map files, and start up the executable and it will load what needs to be loaded. Of course, you could add in your own code and use the engine as an api, and this idea will be especially prominent with scripting (as you may want to include your own C++ functions). I guess this topic is solved, so I'll just end it with this:
If anyone would like to help on the (now 2D) game engine, feel free to message me.

I actually do have a specific game in mind for this engine. My idea for my engine will implement its own script engine, which CAN take care of certain rendering. I know exactly how I want the engine to be done, the only big problem I'm having is with model formats.

All right, so you passed the first hurdle. Now, you have a game in mind, and presumably you know what sort of models your game is going to use.

So what, exactly, are the requirements for those models? Do you need tangents for normal/displacement-mapping? Multiple texture coordinates to support multiple texture mappings? How many bone weights are needed at each vertex? Are you going to use skeletal animation, or frame-by-frame animation? Are your skeletal animations going to use matrices or quaternions?

The feeling I get from your posts is that you know what you are doing on the programming end, but you don't have much knowledge of modelling, animation, and modern rendering techniques. And that's fine, but if you want to build a graphics engine, you need to learn. Pick up some modelling software (something free like Blender will do), build yourself a simple model, build a simple armature, skin it, texture it, animate it a little, write an importer for it, render it with normal mapping, with parallax mapping... After all that, you'll have enough experience to start making decisions on what features to include or not in your engine - these things can't really be decided in isolation.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Or actually stick with the existing (Blender, OBJ, Collada, whatever) format :P Now these format's arent't optimized for quickly loading exactly what you need in your game, but making a start there would make sense. Cause in the first place, you'll probably need to convert format X to Y anyway, as the 3D artist is likely going to work in Blender, Max, Maya, Lightwave, Milkshape or the likes. Picking a widely supported format to begin with, would be a wise thing to do.

Speaking of which, the most user-friendly way to implement your own format, is by writing plugins/scripts (load & save) for the 3D packages you use. 3D artists like to tweak and preview their models, so if they have to re-convert the model with multiple steps each time they change a vertex, it becomes annoying. I'd say focus on a few popular 3D modelling programs, including the one you use yourself. Pick a format they both can export AND contains all that is required (many formats do not store animation data!), and start from there. Pick out the good stuff, then eventually write your own custom format for these programs.
Well, there is always Assimp, which loads pretty much every format. Make a xyzformat-to-yourformat converter with that, and be done. Load Blender, OBJ, or Collada or whatever it will be into the converter using Assimp, set up the 3-4 structs for your header, copy the streams, and save everything on disk again.

The game then just loads (or memory maps) that whole thing and has the data in a format as you expect it.

This topic is closed to new replies.

Advertisement