OpenGL does not provide any native data structures that represent 3D models. Rather it provides a configurable graphics server that renders basic primitives. In order to render more complex objects you need to generate them from those primitives. This is part of the design of OpenGL that makes it extremely flexible. However, it does mean that you need to do a lot of leg work if you want to render an arbitary model. GLU and GLUT can be used to generate some objects, but a model importer is required to use objects created in popular 3D modelling programs (such as 3D Studio) or captured using a laser scanner.
The Clean input/output library CLIO provides functions to load 3D models saved in .3ds and .ply formats. The function is:
GLuint clioLoadModel(CLcontext* context, char* const filename);
A CLcontext contains a set of lights, materials, textures, meshes, and
models. A mesh is a set of primitives that share the same surface
properties (material and texture) and a model is a set of meshes. A
CLcontext contains all these structures in one place so that they can
be shared (eg. different meshes use the same texture) and serialised
easily. The clioLoadModel function loads a model into a
context and returns the index of the model in the context's model
array, or -1 on error.
Comment out the calls to initialise materials and textures in your code. The clioLoadModel() function will load this information from the model file.
/* _InitMaterial(); */
/* _InitTexture(); */
/* _InitTextureSphereEnvMap(); */
Create global context and model pointers;
CLcontext* context; CLmodel* model;
A CLcontext is a collection of materials, lights,
textures, meshes, and models. They are stored together to allow
reference by indices (to make serialisation easier) and to store the
miniumu number of instances. (For example, a number of meshes can
share the same texture or material). The CLmodel struct
is a set of meshes stored as mesh indices. We will create a context
structure and send it to clioLoadModel() where it will be
filled with information from the file. The
clioLoadModel() function will return an index into the
context's model array. Do this in the _Init function in
your code.
/* initialise context */ context = clDefaultContext(clNewContext()); model = context->models[clioLoadModel(context, "Fish.3ds")]; cluUpdateContext(context);
clNewContext() allocates memory for the context and
clDefaultContext() sets the memory to default values.
clUpdateContext() generates display lists for lights,
materials, and meshes in the context. It also generates texture
objects for the context's textures.
"Fish.3ds" is the name of a simple fish model that should be in your directory or you can download it here. It contains 3286 vertices and 6280 polygons in 6 meshes. It also contains material properties for those 6 meshes.
Remove the code for rendering the teapot and replace it with a call to the clRenderModel function.
/* render the model */ glPushMatrix(); glTranslatef(0.0f, 0.0f, -10.0f); glRotatef(angle, 1.0f, 1.0f, 0.0f); clRenderModel(model); glPopMatrix();
Running it should look like this:
If your attempt didn't work then just ask for help, or you can check this file for a solution.
CL update and rendering functions operate subject to the state of the
CL server (just like OpenGL!). (If you have the CL distribution you
can try the CL demo program clcube.c to see how these
options affect rendering). Here is a list of CL rendering options:
CL_NONE |
disable all CL options | CL_LIGHT_DISPLAY_LIST |
use display lists to store lights on the GL | CL_MATERIAL_DISPLAY_LIST
| use display lists to store materials on the GL | CL_TEXTURE_OBJECT
| use texture objects to store textures on the GL | CL_COLOUR
| send per-mesh colour to the GL | CL_MATERIAL
| load materials per-mesh | CL_TEXTURE
| load textures per-mesh | CL_TEXTURE_ENV_MODE
| set the per-mesh texture environment mode on the GL | CL_VERTICES
| send vertices to the GL | CL_NORMALS
| send per-vertex normals to the GL | CL_COLOURS
| send per-vertex colours to the GL | CL_TEXCOORDS
| send per-vertex texture coordinates to the GL | CL_EDGEFLAGS
| send per-vertex edgeflags to the GL | CL_MESH_DISPLAY_LIST
| use display lists to store meshes on the GL | CL_ALL
| enable all CL options |
If you have time you can add features to your program. (It could be useful to do so while you have a few seasoned OpenGL programmers around to answer questions). If you are interested in adding more rendering features to the program and didn't opt for the Extra page you may find something interesting there.
Aside from that you can experiment with different OpenGL rendering modes or even modifying the CLmodel you have loaded. Maybe try modifying the vertices to deform it in some interesting way. GLUT provides a basic menu system and mouse event handler. You could try using GLUT menus for rendering options and the mouse event callbacks for mouse input to rotate the model or zoom the camera. You could inspect the CL demo program clcube.c for an example of GLUT mouse control and menus.
Check out the manpages for glutMouseFunc(),
glutMotionFunc(), glutPassiveMotionFunc(),
glutCreateMenu, glutSetMenu,
glutAddMenuEntry, glutAddSubMenu, and
glutAttachMenu.