i
i
i
i
i
i
i
i
328 13. Programming 3D Graphics in Real Time
void Make3dListS(void){ // make display lists
GLfloat x,y,z,n[3],color[4],spec_color[]=(1.0,1.0,1.0};
FACE
*
fp;
VERTEX
*
v,
*
v1,
*
v2,
*
v0;
normal
*
nv;
int i,j,k,Vi,V[3],jf,jl,count,strip;
if(Nface == 0)return;
scale=GetScaleValue(c)
*
ObjScale;
if((nv=(normal
*
)malloc(sizeof(normal)
*
Nvert)) == NULL)return;
..
// make vertex normals from adjacent vertices
..
if(listID > 0){glDeleteLists(listID,listID);listID=0;}
listID=1; glNewList(listID,GL_COMPILE);
count=0;
glBegin(GL_TRIANGLES);
fp=MainFp; for(i=0;i<Nface;i++,fp++){ // loop over all polygons
if(fp->mapped)continue;
// skip any polygons with image maps applied
v0=(MainVp+fp->V[0]); v1=(MainVp+fp->V[1]); v2=(MainVp+fp->V[2]);
if(!same_color(fp->color)){
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,fp->color);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,spec_color);
}
if(Normalize(v0->p,v1->p,v2->p,n)){
for(j=0;j<3;j++){
Vi=fp->V[j]; v=(MainVp+Vi);
x=((GLfloat)(v->p[0]-c[0]))
*
scale;
// Scale and center the model in the
y=((GLfloat)(v->p[1]-c[1]))
*
scale; // view volume.
z=((GLfloat)(v->p[2]-c[2]))
*
scale;
if(smooth_shading && ((fp->texture >> 7) != 0)){ // smoothed
glNormal3f( nv[Vi][0], nv[Vi][1], nv[Vi][2]);
}
else{ // not smoothed
glNormal3f( n[0], n[1], n[2]);
}
glVertex3f(x,y,z);
}
}
}
}
Listing 13.12. A display list holds all the commands to render the polygons in a mesh
model. Changes of color apply to all subsequent vertices added to the list, and so
each time a change of color is detected, a new set of material property specifications
have to be added to the display list.
i
i
i
i
i
i
i
i
13.1. Visualizing a Virtual World Using OpenGL 329
glEnd();
if(Mapped){
..... // Render any polyongs with image maps - see next listing
}
glEndList();
free(nv);
}
Listing 13.12. (continued).
smooth shading model is required, a precalculated average normal (obtained
from all the polygons attached to a particular vertex) is sent to the render-
ing pipeline along with the vertex coordinates. Listing 13.12 brings all the
required elements together to compile the display list.
13.1.7 Image Mapping
One of OpenGLs major strengths is its image-mapping
7
capability which has
improved considerably in the incremental Versions 1.1 through 1.5 and, as
we shall see in the next chapter, is now (in Version 2.0) nearly as powerful
if(Mapped){ // Render any polygon in the model that uses an image map
.. // declare any local variables here
if(Nmap > 0)for(k=0;k<Nmap;k++){ // loop over all the maps
if(MapsFp[k].pp < 0){ // if the map is a
// reflection map
Image=LoadMAP(MapsFp[k].frefl,&xm,&ym); // load the map & uncompress it
// into pixel array
glEnable(GL_TEXTURE_GEN_S); // For reflection maps the
// texture coordinates
glEnable(GL_TEXTURE_GEN_T); // are generated automatically.
refmap=TRUE;
}
Listing 13.13. Rendering image mapped polygons by looping over the image maps
and polygons. When a polygon is textured with a map, the appropriate texture
coordinates are calculated and the vertices passed to OpenGL.
7
The terms image map, texture, shader are often loosely used to refer to the same thing
because they all result in adding the appearance of detail to a polygonal surface without that
detail being present in the underlying mesh and geometry. Whilst we would prefer to reserve
the words shader and texture for algorithmically generated surface detail, we will, when talking
generally, use them interchangeably.
i
i
i
i
i
i
i
i
330 13. Programming 3D Graphics in Real Time
else { // and ordinary map painted onto surface
Image=LoadMAP(MapsFp[k].filename,&xm,&ym);
refmap=FALSE;
}
if(Image != NULL)makeNextMap(Image,xm,ym); // If map pixels were created
// make the OGL map in
// texture RAM.
glEnable(GL_TEXTURE_2D); // render from a map instead of
// a color
// Tell OGL which type of texture to use and which image map to use.
// If we could
// not load the map we tell OGL to use the simple checker board texture
if(Image != NULL)glBindTexture(GL_TEXTURE_2D,IMAGE_TEXTURE);
else glBindTexture(GL_TEXTURE_2D,CHECK_TEXTURE);
// For OpenFX models we need to get its map parameters so that
// we can generate
// texture coordinates.
GetMapNormal(MapsFp[k].map,MapsFp[k].p,MapsFp[k].x,MapsFp[k].y,mP,mX,mY,mN);
glBegin(GL_TRIANGLES); // now render the polygons
fp=MainFp; for(i=0;i<Nface;i++,fp++){
if((fp->texture & 0x40)!=0x40)continue; // skip if polygon not mapped
brushID=(fp->brush & 0x1f); // which image ?
if(brushID != k)continue; // skip if not this image map
v0=(MainVp+fp->V[0]); v1=(MainVp+fp->V[1]); v2=(MainVp+fp->V[2]);
if(Normalize(v0->p,v1->p,v2->p,n)){ // get polygon normal
for(j=0;j<3;j++){
Vi=fp->V[j]; v=(MainVp+Vi);
x=((GLfloat)(v->p[0]-c[0]))
*
scale; // scale and center model
..// same for y and z ccords ; // in view volume
if(smooth_shading && ((fp->texture >> 7) != 0)){ // smoothed
glNormal3f(nv[Vi][0], nv[Vi][1],nv[Vi][2]);
} else glNormal3f( n[0], n[1], n[2]); // not smoothed
if(MapsFp[k].map == MAP_BY_VERTEX){
// texture coords exist - use them!!
alpha=(GLfloat)v->x; beta=(GLfloat)v->y;
}
else if(MapsFp[k].map == CYLINDER || // OpenFX model - must
// calculate texture coords
MapsFp[k].map == CYLINDER_MOZIAC)
GetMappingCoordC(mN,mX,mY,mP,MapsFp[k].angle,
v->p,&alpha,&beta);
else GetMappingCoordP(mN,mX,mY,mP,v->p,&alpha,&beta);
if(!refmap)glTexCoord2f(alpha,beta);
glVertex3f(x,z,-y);
}}}
glEnd(); // all polygons done with this map
glDisable(GL_TEXTURE_2D); // done texturing with this map
if(refmap){
glDisable(GL_TEXTURE_GEN_S); // We were rendering reflection
glDisable(GL_TEXTURE_GEN_T); // mapping.
}
} // end of map loop
} // end of rendering image maps
Listing 13.13. (continued).
i
i
i
i
i
i
i
i
13.1. Visualizing a Virtual World Using OpenGL 331
as the non-real-time rendering engines. There are few effects that cannot be
obtained in real-time using image mapping.
In the example we are working on, we shall not deploy the
full spectrum of compound mapping where several maps can be
mixed and applied at the same time to the same polygons. Nei-
ther will we use some of the tricks of acceleration, such as loading
all the pixels for several maps as a single image. In many cases,
these tricks are useful, because the fixed-functionality pipeline
imposes some constraints on the way image maps are used in the
rendering process.
Listing 13.13 shows how the parts of the mesh model which have textured
polygons are passed to OpenGL. The strategy adopted is to run through all
the image maps used by the mesh model (there could be a very large number
of these). For each map (map i), its image is loaded and the pixels are passed
to OpenGL and loaded into texture RAM. After that, all the polygons are
checked to see whether they use map i. If they do then the texture coordinates
are obtained. OpenGL requires per-vertex texture coordinates, and, therefore,
if we are loading an OpenFX model, we must generate the vertex texture
coordinates. 3ds Max already includes texture coordinates for each vertex,
and so these meshes they can be passed directly to OpenGL.
The code t hat is necessary to process the image by loading it, decoding
it and making the OpenGL texture is shown in Listing 13.14. To round
off the discussion on image mapping, if you look back at Listing 13.13, you
will notice the calls to the functions
glEnable(GL TEXTURE GEN S); and
glEnable(GL TEXTURE GEN T);. If these parameters are enabled, OpenGL
will ignore any texture coordinates specified for vertices in the model and
instead generate its own based on the assumption that what one sees on the
mesh surface is a reflection, as if the image were a photograph of the surround-
ing environment. This is the way OpenGL simulates reflective/mirrored sur-
faces and the extremely useful application of environment maps as discussed
in Section 7.6.
This takes us about as far as we need to go with OpenGL for the moment.
We have seen how to render image-mapped polygons from any viewpoint and
either move them or move the viewpoint. We can use a good lighting model
and can draw objects or virtual worlds constructed from many thousands of
planar triangular or other polygonal primitives, in real time. It is possible to
extend and use this code, so we shall call on it as the basis for some of the
i
i
i
i
i
i
i
i
332 13. Programming 3D Graphics in Real Time
// load the Image map into pixel array
unsigned char
*
LoadMAP(char
*
CurrentFile,int
*
xx,int
*
yy){
// JPEG type image
if(strstr(CurrentFile,".JPG")||strstr(CurrentFile,".jpg"))
// read, decompress and return pointer
return LoadJpeg(CurrentFile,xx,yy);
// other maps
else if(....
return NULL;
}
// This function makes the OpenGL image map from a block of 24 bit pixels
in RGB order void makeNextMap(unsigned char
*
pixels24, int x, int y){
int xi,yi;
// OpenGL ony accepts image maps whose height and width
// are a power of 2. In order to make that map we
// must find a suitable power of 2 and use the utility
// library to interpolate from the original dimensions.
// Because this must be done in the CPU it will be very slow.
// However because we are building a display list this
// only has to be done ONCE and not when we are running the list.
unsigned char
*
px;
if (x < 96)xi=32;
else if(x < 320)xi=64;
else xi=128;
if (y < 96)yi=32;
else if(y < 320)yi=64;
else yi=128;
if((px=(unsigned char
*
)malloc(xi
*
yi
*
3)) == NULL){
free((char
*
)pixels24);
return;
}
// scale the image to chosen power of two dimension
gluScaleImage(GL_RGB,x,y,GL_UNSIGNED_BYTE,pixels24,xi,yi,GL_UNSIGNED_BYTE,px);
free((char
*
)pixels24); // we don’t need the original image any more
// Next make the texture in GPU RAM
glBindTexture(GL_TEXTURE_2D,DUMMY_TEXTURE);
glTexImage2D(GL_TEXTURE_2D,0,3,xi,yi,0,GL_RGB,GL_UNSIGNED_BYTE,(GLvoid
*
)px);
free((char
*
)px); // we don’t need any CPU memory it’s all in GPU
}
Listing 13.14. Creating the image ma p requires three steps: it must be loaded and
decompressed, then it has to be converted into a form that OpenGL can use (i.e.,
its height and width must be a power of two) then it can be passed to OpenGL and
loaded into the texture RAM on the display adapter.
..................Content has been hidden....................

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