Koeky 3D Framework : Loading Models

In this chapter I will explain how to load models using a model loader I have written. I will also explain a basic layout of a model in the Koeky 3D Framework.

First the bad news: model loading is not natively supported in Koeky 3D. I have chosen not to write a default model loader because there are dozens of model formats out there and I don't know which I do want to support and which I do not want to support.
Therefore I have decided to leave the loading of models to you. This way you have absolute freedom in choosing the model format of your liking.
I am not, however, completely evil. I have written a modelloader which will load Milkshape models (*.ms3d). It is part of the source code in a seperate project called 'MilkModelLoader'.

Now: to load a model!

What is a model in Koeky 3D?

This is entirely up to you. But in a very simple scenario I would say a model is the following:
  • A collection of vertex data (vertex positions, texture coordinates etc.)
  • A collection of meshes (each mesh has a index buffer, refering to the above data).
  • A material per mesh (textures, lighting parameters etc.)

In code this could look like this:
class Model
{
    /// <summary>
    /// The world transform of this model
    /// </summary>
    public Matrix4 world;
    /// <summary>
    /// The vertex array
    /// </summary>
    public VertexArray vertexArray;
    /// <summary>
    /// The index buffer per triangle mesh
    /// </summary>
    public IndexBuffer[] indexBuffers;
    /// <summary>
    /// The texture per triangle mesh
    /// </summary>
    public Texture2D[] textures;

    public Model(Matrix4 world, VertexArray vertexArray, IndexBuffer[]
                          indexBuffers, Texture2D[] textures)
    {
        this.world = world;
        this.vertexArray = vertexArray;
        this.indexBuffers = indexBuffers;
        this.textures = textures;
    }

    /// <summary>
    /// Renders the model
    /// </summary>
    /// <param name="glManager"></param>
    public void Draw(GLManager glManager)
    {
        glManager.World = this.world;
        glManager.BindVertexArray(this.vertexArray);
        // render every mesh
        for(int i = 0; i < this.indexBuffers.Length; i++)
        {
            glManager.BindIndexBuffer(this.indexBuffers[i]);
            glManager.BindTexture(this.textures[i], TextureUnit.Texture0);

            glManager.DrawElementsIndexed(BeginMode.Triangles, this.indexBuffers
                                 [i].Count, 0);
        }
    }
}


This is a very simple example ofcourse but you can easily expand on this so it can have several textures (like a normal or specular map).

There is also a GLModel and GLMesh class in the Koeky 3D Framework. I am not certain if I will keep these classes around tough. I feel like I cannot cover every possible implementation of a model and therefore I shouldn't even try. But let me know if you think these classes are worthy additions to Koeky 3D.

Loading a model using the Milkshape loader

Loading a model is really simple:
// Create a MilkshapeLoader object
MilkshapeLoader loader = new MilkshapeLoader();
MilkshapeModel milkModel;

// Load the milkshape model
MilkshapeLoadResult result = loader.LoadModel("AwesomeModel.ms3d", out milkModel);

// Check if we loaded the model correctly
if (result != MilkshapeLoadResult.ModelLoaded)
{
    // Model failed to load
    MessageBox.Show("Error: " + result.ToString());
}


After this piece of code you got a complete Milkshape model in memory. Even better: the model is optimized so redundant vertices are removed. At this point you can acces an array with the vertices, texture coordinates, normals, bone indices and bone weights. Every mesh is already available with an array usable by an index buffer.

Turning the Milkshape model in a Koeky 3D model

We are now going to turn the loaded milkshape model into the model format we described above.
First we have to store the vertex data in vertex buffers like this:
// Create the vertex buffer
VertexBuffer verticesBuffer = new VertexBuffer(BufferUsageHint.StaticDraw, 
                   (int)BufferAttribute.Vertex, milkModel.vertices);
VertexBuffer texCoordBuffer = new VertexBuffer(BufferUsageHint.StaticDraw, 
                    (int)BufferAttribute.TexCoord, milkModel.texCoords);
VertexBuffer normalBuffer = new VertexBuffer(BufferUsageHint.StaticDraw, 
                    (int)BufferAttribute.Normal, milkModel.normals);


And next we need to create a vertex array object
VertexArray vertexArray = new VertexArray(verticesBuffer, texCoordBuffer, normalBuffer);


And, ofcourse, we need to create an IndexBuffer and Texture2D for every mesh:
// Create the index buffers, for every triangle mesh one
IndexBuffer[] indexBuffers = new IndexBuffer[milkModel.meshes.Length];
Texture2D[] textures = new Texture2D[milkModel.meshes.Length];

for (int i = 0; i < milkModel.meshes.Length; i++)
{
    MilkshapeMesh mesh = milkModel.meshes[i];
    indexBuffers[i] = new IndexBuffer(BufferUsageHint.StaticDraw, mesh.indices);
    textures[i] = TextureConstructor.ConstructTexture2D(mesh.material.texturePath);
}


Finally we need to create the actual model itself:
this.model = new Model(modelTransform, vertexArray, indexBuffers, textures);


That's it! We now have turned the Milkshape model into a model we can actually render on the screen.


Last edited Jun 14, 2012 at 7:43 PM by Mathyn, version 1

Comments

No comments yet.