Show Menu

helicopter render feature

Constructing the Clairvoyance engine provided, and continues to provide, many opportunities for problem solving. A major component of any graphics engine is loading and rendering three-dimensional models, and we wanted Clairvoyance to handle this responsibility as elegantly as possible. Since 3D models are integral to having a functional 3D application, it was important that we develop a robust and reliable system for importing them.

We began by outlining a few requirements that our model loading system must accommodate:

Our first attempt at creating a model loader was simplistic and ultimately flawed. It supported only Wavefront .OBJ files, and had strict requirements on how the data was to be structured in the file. For what was required of it at the time, it was moderately successful and met the basic needs of our engine. It made efficient use of vertex and index buffers, and incorporated shared vertices to reduce unnecessary data storage. However, a few notable problems existed – namely, an inability to correctly identify UV positions, as well as an inability handle a vertex with multiple normal vectors.

Our second iteration of our model loading system discarded the existing code almost entirely, and went in a new direction. After researching some open source solutions, we came across a library called Assimp, named after a shortened portmanteau of Open Asset Import Library. Assimp provided an incredibly convenient and robust framework with which we now use to load our models in the Clairvoyance engine. Incorporating Assimp yielded many code changes to our engine, as well as some minor changes the Assimp library itself.

This route provided many advantages. Though there are truly a variety of reasons, I have listed a few:

Programming with the Assimp SDK did not prove difficult, and we can use it to meet any sort of model importing requirement we come across. An example code excerpt from our test implementations is shown:

// buffer for faces
glGenBuffers(1, &buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 3, faceArray, GL_STATIC_DRAW);

// buffer for vertex positions
if (mesh->HasPositions()) {
       glGenBuffers(1, &buffer);
       glBindBuffer(GL_ARRAY_BUFFER, buffer);
       glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mVertices, GL_STATIC_DRAW);
       glEnableVertexAttribArray(vertexLoc);
       glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
}

// buffer for vertex normals
if (mesh->HasNormals()) {
       glGenBuffers(1, &buffer);
       glBindBuffer(GL_ARRAY_BUFFER, buffer);
       glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mNormals, GL_STATIC_DRAW);
       glEnableVertexAttribArray(normalLoc);
       glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
}

 

Currently, we are working on integrating shaders into our engine, and in doing so we are simultaneously making improvements to our model loading system, as well as related rendering hierarchies. At this stage, we are doing a lot of research, and conducting code tests outside of the engine itself. In a separate application, I am testing the use of Assimp-implemented models and GLSL shaders.

 

A helicopter rendered using Assimp and GLSL

A helicopter rendered using Assimp and GLSL

In that example, the focus is to understand the syntax of Assimp and its limitations, as well as to incorporate shaders to render the models Assimp loads. This exercise did not include developing upon concepts of scalability or robust code architecture, which continue to be extensive, ongoing puzzles in the Clairvoyance engine.

Using GLSL in this example demonstrated to me that the language is powerful and relatively easy to transition into from CG. Using GLSL allows me to use many of the existing OpenGL and OpenGL Extension functions to reduce dependencies. Implementing shaders goes hand in hand with implementing models: the data taken in from the model must be organized in a way that is compatible with the needs of the shader, and vice versa.

I am currently developing on the cumulative knowledge that our research has provided, and am working to integrate it into our engine. A robust model importer means that I can safely assume any future problems to lie within the context of the shaders. Assimp provides a strong foundation for our models and allows me to dedicate time to working on the shader system.

Clairvoyance is being constructed to implement GLSL shaders and to support the use of multiple shaders gracefully. Clairvoyance makes use of passes, and will be capable of multi-pass rendering techniques. A technique stores its related passes, and is itself stored in a material class. A renderable model will have a related material as well as one or more techniques to reference a specific shader combination.

Importing Models

A major component of any graphics engine is loading and rendering three-dimensional models, and we wanted Clairvoyance to handle this responsibility as elegantly as possible. Since 3D models are integral to having a functional 3D application, it was important that we develop a robust and reliable system for importing them.