|
OpenGL ® SuperBible, Fourth Edition, begins by illuminating the core techniques of “classic” OpenGL graphics programming, from drawing in space to geometric transformations, from lighting to texture mapping. The authors cover newer OpenGL capabilities, including OpenGL 2.1’s powerful programmable pipeline, vertex and fragment shaders, and advanced buffers. They also present thorough, up-to-date introductions to OpenGL implementations on multiple platforms, including Windows, Mac OS X, GNU/Linux, UNIX, and embedded systems. The book contains 1248 pages of invaluable information for beginners and advanced OpenGL programmers.
Recommended by the author of this tutorial I have gone through a number of tutorials on the Internet (from NeHe to a bunch of others) to numerous books written on the subject of OpenGL. One of the most informative OpenGL books was the OpenGL SuperBible, also known as "The Blue Book" by the people who work in the industry. This is an absolute must if you are serious about learning OpenGL. |
OpenGL - 6 - Model composition
source code
|
|
| JUMP TO - gl0 - gl1 - gl2 - gl2.5 - gl3 - gl4 - gl5 - gl6 - gl7 - gl8 - |
|
This tutorial demonstrates what could probably be called the simplest 3D model format. I named it the m model format. A model file in this format would have a name of "myModel.m" on your hard drive. The format simply consists of triangle vertices specified one by one. The file(which is written in text(translated) mode, as opposed to binary mode) header starts with the tag: beginmodel n. Where n is the number of consequently specified polygons (tringles only). 3 vertices per line define a single polygon/triangle. What's really neat about the m model file format is that you are allowed to define how YOU want the polygon vertices to be stored. In other words, it ignores all formatting except the floating point values which actually specify a vertex position parameter. The m model format parser skips all and every characters unless the character is either a digit from 0 to 1, a minus sign or a dot. Every other character is sent right down the toilet. But let me illustrate this functionality: In the m model format a polygon can be defined as: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| or it can also be defined by using any other style of formatting. Consider the same polygon described above but with a different formatting style: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| The above definition is just as right as it is in the original example. Formatting styles can be also mixed in any way possible, just keep at least a single space between the x, y and z coordinates. Also, try not to specify less triangles than whats defined by beginmodel, or your program will most likely crash during a LoadModel(...); call, but a little later about this. Now, let's see how the model.h header file is defined: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
|
The vertex_t, polygon_t and model_t structs describe a vertex, a polygon and an m format model. This should be obvious. Note that model_t consists of a number of polygons stored in a model and a polygon list. When we load an m model file with a call to LoadModel(...); a number of polygons is read into this structure and is stored in *pList; nPolygons is what n defines by the means of the beginmodel n tag in the beginning of the m model file. n is the number of polygons in the entire models of course, as already described above. model_t sampleModel; is just a definition of a model that could be used for experimenting purposes. As will be seen in this and the following tutorials, we will use sampleModel to load a simple model and display it on the screen. Mouse-based movement will be utilized to see how the light reacts with that model's surface. But that's the topic of the next tutorial. Right now, let's see what the four remaining functions in the header file listing are for:
DrawPolygon (polygon_t *p); simply renders a polygon specified by a polygon_t struct. LoadModel (char *sFilename, model_t *model); loads a m model file specified by sFilename into the address specified by model_t *model; DrawModel (model_t *model, vertex_t *translate, vertex_t *rotate); draws the model specified by model_t *model on the screen. Model must be loaded with a call to LoadModel(...) first. FreeModel (model_t *model); frees memory allocated for model's vertices. Now, let's take a look at the model.cpp file contents. The first part of this code block includes all necessary include-files ("glbase.h"), defines an alternative wrapper for the return value of fgetc(...), defines a function which skips a file stream line, and more importantly the function that reads a single floating-point parameter from the file stream. Keep in mind that because the file model.cpp is a part of a bigger structure - the opengl base code we are developing, all required include files are included within "glmain.h". You will see this file in the source code of this tutorial and you will understand how include files are connected together. For now, your mission is to just understand this code. | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
|
The most significant part of this block of code is the mmReadNextParam (FILE **file); command. What it does is, it takes the passed file stream FILE **file (the stream should be a valid file stream) and parses it until it finds the next floating-point parameter in it. Once it does the parameter is returned. The function is well-commented so it should be obvious for you to see what's going on. I should mention that some commands seen in this block of code come from other files #included within "glbase.h"(and "it is the main file that includes all required files for the base code to operate). Such one is the SysShutdownMSG command. When an error or EOF (end of file) while parsing is encountered, the program exits out with an error description within a message box. If you want to use this code in your own program, that has nothing to do with the OpenGL base code described in these tutorials, then you would mostly likely want to change the calls to SysShutdownMSG by your own error-displaying functions and also get rid of the "glbase.h" include file. But that's something I wouldn't recommend doing at this point.
So let's see what else is contained within model.cpp, after the definition of the mmReadNextParam(...) function: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
|
The LoadModel(...); function loads an m file format model from file passed as the sFilename parameter into the specified address of an existing model_t structure. Note for convenience, that as a sample model we will use the model defined as model_t sampleModel; for most OpenGL tutorials. For example if we had an m-format file "model.m" and we wanted to load it into the sampleModel struct, we would make the following call: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| There is nothing complex about the three remaining functions from model.cpp. These functions are DrawPolygon, DrawModel and FreeModel: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| DrawPolygon simply draws a polygon of type GL_TRIANGLE (remember, we are only using triangles in these tutorials, so whenever DrawPolygon is called, it is implied that we are drawing a triangle and not any other type of a polygon). For this purpose, the polygon_t struct actually defines only 3 vertices. | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| DrawModel renders the model specified by the *model parameter to the screen. The translate vertex (here is actually used as a VECTOR, not a vertex, the struct definition is just identical to that of a vector; as both a vector and a vertex contain only the x,y,z coordinates and nothing else) specifies the position of the model in the global world space. In other words, the translate vector specifies which location [x,y,z] the model will be translated to before displaying it. The r_anglex, r_angley and r_anglez parameters specify the rotation angles of the model around all of the 3 axis. To simply display the model in its original, non-rotated state, and slightly away from the camera, you would want to assign a value of [0.0f, 0.0f, -6.0f] to the translate vector and assign 0.0f to all of the 3 r_anglen parameters. | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| FreeModel simply frees the previously allocated memory of a specified model. This function should be called during the shutdown process of your application. To sum it all up here are the main steps to load, display and free an m file format model assuming the model we're working with is defined as model_t sampleModel: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
|
The source code combines all of the little pieces of information we've been previously talking about in the OpenGL tutorial series. Note, we're not dealing with a single cpp file anymore. The base code is split into a number of files. These files are:
Note the usage of directinput.h and directinput.cpp. These files are derived from my DirectInput tutorial, so that's already been explained. Just to let you know. This is the defining point of the fallout OpenGL base code development so the next tutorial shows you the code structure, how everything fits together and how all files are linked to each other. Take your time to look at the actual source code of this tutorial and read the following one. After you're done, you'll be ready to progress to the next quite important stage in the series of OpenGL tutorials which describes the OpenGL lighting system. When you compile and run the source code, use the mouse to move the loaded object. By pressing and holding down the left mouse button you will be able to drag the object around its x and y axis. By dragging the object fast enough and releasing the mouse button you will set the object in spinning motion defined by the direction of however you were dragging it. And that functionality's utilized by using the following function: | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
|
The model I'm using in this tutorial is a simple quad made out of two polygons. Sorry but I actually don't have time to create something more advanced right now. However, I'm kindly asking everyone who's reading my tutorials to contribute to this tutorial by designing something more complex than what is described by "model.m" in this tutorial. So, open up "model.m" in notepad and hack something up if you have time. I will credit you right on these lines and will update this tutorial with your model. Send it to gregd at falloutsoftware dot com.
|
| JUMP TO - gl0 - gl1 - gl2 - gl2.5 - gl3 - gl4 - gl5 - gl6 - gl7 - gl8 - | |
OpenGL - 6 - Model composition
source code
|
|