i
i
i
i
i
i
i
i
13.1. Visualizing a Virtual World Using OpenGL 323
void FreeObject(void){
///// Free up all the memory buffers used to hold
...// the mesh detail and reset pointers
MainVp=NULL; MainFp=NULL; MapsFp=NULL;
Nvert=0; Nface=0; NvertGlue=0; Nmap=0;
}
void LoadModel(char
*
CurrentDirFile, int fid){ // load the mesh
FreeObject(); // make sure existing mesh is gone
if(fid == FI_3DS)Load3dsObject(CurrentDirFile); // select loading function
else LoadOfxObject(CurrentDirFile); // by filename extension
ListAdjFaces(); // find a list of all polygons which are adjaent
// to each other
FixUpOrientation(); // make sure all the faces have consistent normals
StripFaces(); // order the polygons into strips if possible
}
int LoadOfxObject(char
*
FileName){ // load the OpenFX model - the file
// is segmented
int fail=1; // into chunks
long CHUNKsize,FORMsize;
if( (fp=fopen(FileName,"rb")) == NULL)return 0;
// check headers to see if this is an OpenFX file
if (fread(str,1,4,fp) != 4 || strcmp(str,"FORM") != 0){ fail=0; goto end; }
if (getlon(&FORMsize) != 1) goto end;
if (fread(str,1,4,fp) != 4 || strcmp(str,"OFXM") != 0){ fail=0; goto end; }
loop: // we have an OpenFX file so go get the chunks
if (fread(str,1,4,fp) != 4 ) goto end;
if (getlon(&CHUNKsize) != 1) goto end;
if (strcmp(str,"VERT") == 0){ReadVertices(CHUNKsize);}
// read the vertices
else if(strcmp(str,"FACE") == 0)ReadOldFaces(CHUNKsize,0);
// read the polygons
else if ... // read other required chunks
else getchunk(CHUNKsize); // read any chunks not required
goto loop;
end:
fclose(fp);
return fail; // 1 = success 0 = failure
}
Listing 13.10. Loading the OpenFX and 3 ds Max mesh models involves parsing the
data file. The les are organized into chunks. After reading the data, it is processed
to make sure that all the polygons have a consistent surface normal. The function
StripFaces() provides a rudimentary attempt to optimize the order of the trian-
gular polygons so that they are amenable to OpenGLs acceleration.
i
i
i
i
i
i
i
i
324 13. Programming 3D Graphics in Real Time
and lights and viewpoint positioned. Transformations are assembled using a
matrix stack so that previous transformations can be undone easily (simply
by popping the stack). A viewing transformation, the
GL PROJECTION trans-
formation, is necessary to specify the viewing conditions such as the field of
view. When rendering, these two transformations are combined to form the
image of a 3D point on the 2D image plane. The image plane itself is scaled
so as to fit into the viewport, which is dimensioned so that it fits into the
encapsulating windows client area.
The initialization phase also creates a small image map (checker board
pattern) to a ct as a substitute in the event that a map from the mesh file cannot
be created during rendering. Making texture maps in OpenGL involves two
main steps: preparing the image data, including assigning it an identifier, and
writing that image data into the display adapter’s texture memory. There are
some restrictions on the format of the data that may be used to define pix el
textures in OpenGL, such as the dimensions must be a power of two.
To perform this additional initialization, the code takes the form shown
in Listing 13.9.
13.1.5 Loading the Model
If you want to see all the detail of how the ver tex, polygon and image map
information is extracted from the 3D data files, consult the actual source code.
Listing 13.10 gives a brief summary. Both the OpenFX and 3DS mesh les
Figure 13.5. OpenGL provides a mechanism for sending strips of triangles to the
rendering pipeline. In this example, we see that triangular polygons 1 to 8 (ver tices
1 to 10) can be combined as a single triangle strip. Triangles 9 and 10 cannot be
included in the strip because they violate the vertex/edge ordering. OpenGL has a
structure called a triangle fan to deal with such cases.
i
i
i
i
i
i
i
i
13.1. Visualizing a Virtual World Using OpenGL 325
Figure 13.6. The stripping algorithm tries to build strips of adjacent triangular poly-
gons. This helps to reduce the number of vertices that have to be rendered by
OpenGL. For example, if you can make a strip from 100 adjacent polygons, you
reduce the number of
glVertex..() calls from 300 to 201.
i
i
i
i
i
i
i
i
326 13. Programming 3D Graphics in Real Time
use a storage scheme based on chunks. There is a chunk to store the vertex
data, one to store the triangle face/polygon data and numerous others. Each
chunk comes with a header (OpenFX has a four-character ID and 3DS a
two-byte magic number) and a four-byte length. Any program parsing this
file can jump over chunks looking for those it needs by moving the file pointer
forward by the size of a chunk.
A fairly simplistic algorithm which attempts to locate strips of triangles
such as those in the mesh illustrated in Figure 13.5 is provided by function
StripFaces(). The strategy of the algorithm is summarized in Figure 13.6.
The algorithm locates groups of polygons that can form strips and sets the
member variable
next in each polygons data structure so that it behaves like
a linked list to vector a route through the array of polygons stored in RAM
at an address pointed to by
MainFp. By following this trail, the polygons can
be rendered as a triangle strip, thus taking advantage of OpenGLs rendering
acceleration for such structures.
13.1.6 Rendering the 3D Data
We shall discuss rendering with the use of five listings so as to highlight the
differences which occur when one uses OpenGL to render simply-shaded
polygons, polygons that make up the whole or part of a smooth, rather than
faceted, object. We shall also introduce the display list, which allows further
optimization of the rendering process.
Display lists are very useful because they allow us to prepare a kind of
ready-made scene, one that can be quickly configured and rendered without
having to load all the vertices and images from the host computer’s RAM.
For a VR application, a display list can be used to store all the OpenGL
commands to render a mesh model, independent of taking any particular
view. The programs user can then view the object from any angle by calling
the display list after position and rotation transformations are set up. Using a
display list works in this case because the mesh does not change over time. If the
mesh were deforming or moving, the list would have to be regenerated after each
change to the mesh.
The function which is called to render a particular view or in response
to a
WM PAINT message appears in Listing 13.11. Note that a transformation
of 5.0 is applied to the negative z-axis; this moves the model away from
the camera so that it all is visible, i.e., we see the outside. If the model were
of a virtual environment, we would wish to keep it centered at (0, 0, 0) and
i
i
i
i
i
i
i
i
13.1. Visualizing a Virtual World Using OpenGL 327
GLvoid Draw3dScene(HWND hWnd,BOOL shaded){ // called when window is drawn
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); // clear frame buffer
// and Z-buffer
glShadeModel(GL_SMOOTH); // draw using GOURAUD shading
glPushMatrix(); // store existing
// transformations
glLoadIdentity(); // start with NO transformation
glTranslatef(xpos_offset, ypos_offset, -5.0); // move mesh model
glRotatef(up_angle,1.0,0.0,0.0); // rotate up or down
glRotatef(round_angle+180.0,0.0,1.0,0.0); // rotate to get side view
glScalef(view_scale, view_scale, view_scale); // scale to fit into view
if(listID > 0){ // If a display list of the
glEnable(GL_LIGHTING); // mesh with maps etc is ready
glCallList(listID); // draw it with lighting
// enabled.
glDisable(GL_LIGHTING);
}
glPopMatrix(); // restore the previous
// transformation
glFlush(); // make sure OGL pipeline is
// all done
}
Listing 13.11. Rendering the scene using a display list.
expand it so that we can move about inside it. We should, however, still make
sure that it all lies on the camera side of the rear clipping plane.
Compiling a display list is not a complex process because the normal
rendering commands are issued in exactly the same way that they would be
when rending directly to the frame buffer:
..
glNewList(listID,GL_COMPILE);
// start to build a Display List
glBegin(GL_TRIANGLES);
// render triangular polygons by calling glVertex() three times
glEnd();
glEndList();
// end the display list
..
To build a display list for the mesh, we must loop over every face/polygon
and call glVertex..() for each of its three vertices. To achieve the correct
lighting, a surface normal will also have to be defined at each vertex. When a
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.122.235