Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!purdue!decwrl!sgi!woo From: woo@madonna.SGI.COM (Mason Woo) Newsgroups: comp.sys.sgi Subject: Re: SGI lighting model? Summary: code which demonstrates lighting models on IRIS Message-ID: <20761@sgi.SGI.COM> Date: 30 Aug 88 18:54:33 GMT References: <8808252117.aa03442@SPARK.BRL.MIL> Sender: daemon@sgi.SGI.COM Organization: Silicon Graphics Inc, Mountain View, CA Lines: 405 Here is some code which we use in the Advanced Graphics Course to teach the use of lighting models on the IRIS. A whole day is devoted to the understanding of lighting. This sample draws a flat-shaded, lighted sphere. It demonstrates lmdef(), lmbind(), mmode(), n3f(), and other subroutines. It can be easily (very easily) modified to draw a Gouraud-shaded sphere. For more information on Customer Education courses, call 800-356-9492. Mason Woo--Manager, Customer Education Silicon Graphics /* liteye.c * liteye.c displays the simplest lighting model. * It displays a unit sphere with the light displayed from above. * The lightmodel chooses the simplest model possible, * with a local viewer, no attenuation or ambient light. * The light source is differs from the default by placing * the infinite light above the scene. * The default material characteristics are selected. * The light is attached to the eye. */ #include "gl.h" #include "device.h" #include "math.h" #include "stdio.h" #define SIMPLE_LM 1 float idmatrix[4][4] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; main () { short attached; short value; int dev; int x, dx, oldx; /* mouse movement */ float pt_sphere[40][40][3]; /* endpoints of the sphere */ int lat, longit; /* number of longitude/latitude sides */ dx = 0; attached = 1; initialize (&lat, &longit, pt_sphere); while (TRUE) { while (qtest() || !attached) { dev = qread (&value); if (dev == ESCKEY) { gexit(); exit(0); } else if (dev == REDRAW) { reshapeviewport (); drawscene (dx, lat, longit, pt_sphere); } else if (dev == INPUTCHANGE) attached = value; } /* end while qtest or not attached */ oldx = x; x = getvaluator (MOUSEX); if (getbutton (LEFTMOUSE)) dx = dx + (x - oldx); drawscene(dx, lat, longit, pt_sphere); } /* end while (TRUE) */ } /* end main() */ /* The initialize subroutine positions the window and specifies * its future constraints. The program is in double buffer mode * for animation and RGB mode for lighting. * The sphere is initialized with a unique radius, * and the number of points in its longitude and latitude directions. * mmode(MVIEWING) separates the projection and viewing matrices. * The tables with the definitions for the lighting model, * the light sources, and the material characteristics are loaded * initlightdef(). * The simple lighting model defined in initlightdef is selected. */ initialize (lat, longit, pt_sphere) int *lat, *longit; /* number of longitude/latitude sides */ float pt_sphere[40][40][3]; /* endpoints of the sphere */ { int gid; float radius; /* radius of the sphere */ prefposition (XMAXSCREEN/4, XMAXSCREEN*3/4, YMAXSCREEN/4, YMAXSCREEN*3/4); gid = winopen ("liteye"); minsize (XMAXSCREEN/10, YMAXSCREEN/10); keepaspect (XMAXSCREEN, YMAXSCREEN); winconstraints(); doublebuffer(); /* lighting in RGB mode */ RGBmode(); gconfig(); qdevice (ESCKEY); qdevice (REDRAW); qdevice (INPUTCHANGE); qenter (REDRAW, gid); lsetdepth (0x0, 0x7FFFFF); zbuffer (TRUE); radius = 1.0; *lat = 15; *longit = 20; initsphere (radius, *lat, *longit, pt_sphere); /* separate the viewing and projection matrices for lighting */ mmode (MVIEWING); /* initialize the lighting definitions */ /* load them into the lighting tables */ initlightdef (); /* select (bind) the lighting model from the table */ /* use for all scenes */ lmbind(LMODEL, SIMPLE_LM); /* initialize the viewing stack before binding the light */ /* load an identity matrix onto the viewing stack */ /* since viewing and modeling commands multiplies what's on the stack */ loadmatrix (idmatrix); polarview (5.0, 0, 0, 0); /* turn on the lights */ /* select a light source from the table */ /* attach a light source to the eye */ /* select a light source BEFORE the viewing matrix has been loaded */ /* the viewing matrix is reloaded in drawscene() */ lmbind(LIGHT0, 1); } /* Initialize the lighting definitions for the * lighting model, the light sources and the material characteristics. * Load the definitions into the lighting tables. */ initlightdef () { /* lighting model definitions */ static float simple_lm[] = { AMBIENT, 0.0, 0.0, 0.0, LOCALVIEWER, 1.0, LMNULL }; /* light source definitions */ static float top_lt[] = { POSITION, 0.0, 1.0, 0.30, 0.0, LMNULL }; /* no material characteristic definitions */ /* use the default lighting material */ /* Select the simple lighting model */ lmdef (DEFLMODEL, SIMPLE_LM, 0, simple_lm); /* load the light definition into the table of lights */ /* lmdef (DEFLIGHT, 1, 0, NULL); */ lmdef (DEFLIGHT, 1, 0, top_lt); /* load the material characteristics into material characteristics table */ /* use the default material characteristics */ lmdef (DEFMATERIAL, 1, 0, NULL); } /* Draw the objects with fixed projection (perspective) and * changing viewing (polarview) transformations. dx is the * amount the mouse has moved, and it changes the incidence angle. * * Note that the routine is called from MVIEWING mode. * The projection command automatically updates the projection matrix * (as opposed to the viewing matrix). * * The light is attached to the eye. */ drawscene (dx, lat, longit, pt_sphere) int dx; int lat, longit; /* number of longitude/latitude sides */ float pt_sphere[40][40][3]; /* endpoints of the sphere */ { float aspect, x, y; x = (float) XMAXSCREEN; y = (float) YMAXSCREEN; aspect = x/y; czclear (0x00FFFFFF, 0x7FFFFF); /* select the current material characteristic from the table */ lmbind(MATERIAL, 1); /* automatically loads the projection matrix 1-deep stack */ perspective (450, aspect, 1.0, 10.0); /* initialize the viewing stack */ /* load an identity matrix onto the viewing stack */ /* since viewing and modeling commands multiplies what's on the stack */ loadmatrix (idmatrix); polarview (5.0, 0, dx, 0); fillsphere_fn (lat, longit, pt_sphere); swapbuffers (); } /* * This contains subroutines to render lighted geometric models. * These objects have normals associated with them. * The coordinates for these shapes must initially be calculated and * loaded into arrays. * * The subroutines in this file are: * initsphere(rad, nlat, nlong, point) * fillsphere_fn (nlat, nlong, point) * fillsphere_Gn (nlat, nlong, point) */ /* initsphere(rad, nlat, nlong, point) * rad is the radius of the sphere. * nlat and nlong are the number of horizontal and vertical sides * around the sphere. point is an array of (x, y, z) vertices. * This subroutine calculates and returns the coordinates for the * vertices of a sphere which is centered at (0.0, 0.0, 0.0). * * If there are more than 25 sides to the cross section, or 50 sides * to the top view, the number of sides is limited. * See figure in manual for how these formulas were derived. */ initsphere (rad, nlat, nlong, point) float rad; int nlat; int nlong; float point[][40][3]; { int i, j, maxlat, maxlong; double pi, twopi, inclat, jj; double dval, magnitude; pi = 3.1415926535; twopi = pi * 2.0; maxlat = 40; maxlong = 40; if (nlat > maxlat) nlat = maxlat; if (nlong > maxlong) nlong = maxlong; inclat = pi/2.0; for (i = 0; i < nlat; i = i + 1) { /* go around cross section */ magnitude = cos (inclat) * rad; dval = sin (inclat) * rad; for (j = 0; j < nlong; j = j + 1) point[i][j][1] = (float) dval; for (j = 0; j < nlong; j = j + 1) { /* go around top view */ jj = (double) j; dval = cos (twopi*jj/nlong) * magnitude; point[i][j][0] = (float) dval; dval = sin (twopi*jj/nlong) * magnitude; point[i][j][2] = (float) dval; } inclat = inclat - (pi/(float) (nlat-1)); } } /* fillsphere_fn (nlat, nlong, point) * Use initsphere() to initialize coordinates. * nlat and nlong are the number of horizontal and vertical sides * around the sphere. point is an array of (x, y, z) vertices. * * This subroutine draws a filled sphere with normals for * flat shading. One normal is sent down the pipe for each polygon. * First, except for boundaries, most of the sphere is drawn. * Then where the top view wraps around is drawn (between endpoints * nlong-1 and 0). Then where the cross section meets its beginning * is drawn (between endpoints nlat-1 and 0). Finally, one final * rectangle is drawn, where both cross section and top view wrap * back to the 0 array element endpoint. */ fillsphere_fn (nlat, nlong, point) int nlat, nlong; float point[][40][3]; { int i, j; float normal[3]; /* draw most of the polygons in the sphere */ for ( i = 0; i < nlat-1; i = i+1 ) for ( j = 0; j < nlong-1; j = j+1 ) { /* find the normal as the average the four point vectors */ normal[0] = ( point[i][j+1][0] + point[i+1][j+1][0] + point[i+1][j+1][0] + point[i][j][0] ) / 4.0; normal[1] = ( point[i][j+1][1] + point[i+1][j+1][1] + point[i+1][j+1][1] + point[i][j][1] ) / 4.0; normal[2] = ( point[i][j+1][2] + point[i+1][j+1][2] + point[i+1][j+1][2] + point[i][j][2] ) / 4.0; bgnpolygon(); n3f( normal ); v3f( point[i][j+1] ); v3f( point[i+1][j+1] ); v3f( point[i+1][j] ); v3f( point[i][j] ); endpolygon(); } /* once around the cross section, where the top view wraps around */ for ( i = 0; i < nlat-1; i = i+1 ) { /* find the normal as the average the four point vectors */ normal[0] = ( point[i][0][0] + point[i+1][0][0] + point[i+1][nlong-1][0] + point[i][nlong-1][0] ) / 4.0; normal[1] = ( point[i][0][1] + point[i+1][0][1] + point[i+1][nlong-1][1] + point[i][nlong-1][1] ) / 4.0; normal[2] = ( point[i][0][2] + point[i+1][0][2] + point[i+1][nlong-1][2] + point[i][nlong-1][2] ) / 4.0; bgnpolygon(); n3f( normal ); v3f( point[i][0] ); v3f( point[i+1][0] ); v3f( point[i+1][nlong-1] ); v3f( point[i][nlong-1] ); endpolygon(); } } /* fillsphere_Gn (nlat, nlong, point) * Use initsphere() to initialize coordinates. * nlat and nlong are the number of horizontal and vertical sides * around the sphere. point is an array of (x, y, z) vertices. * * This subroutine draws a filled sphere with normals for * flat shading. One normal is sent down the pipe for each polygon. * First, except for boundaries, most of the sphere is drawn. * Then where the top view wraps around is drawn (between endpoints * nlong-1 and 0). Then where the cross section meets its beginning * is drawn (between endpoints nlat-1 and 0). Finally, one final * rectangle is drawn, where both cross section and top view wrap * back to the 0 array element endpoint. */ fillsphere_Gn (nlat, nlong, point) int nlat, nlong; float point[][40][3]; { int i, j; float normal[3]; /* draw most of the polygons in the sphere */ for ( i = 0; i < nlat-1; i = i+1 ) for ( j = 0; j < nlong-1; j = j+1 ) { bgnpolygon(); n3f( point[i][j+1] ); v3f( point[i][j+1] ); n3f( point[i+1][j+1] ); v3f( point[i+1][j+1] ); n3f( point[i+1][j] ); v3f( point[i+1][j] ); n3f( point[i][j] ); v3f( point[i][j] ); endpolygon(); } /* once around the cross section, where the top view wraps around */ for ( i = 0; i < nlat-1; i = i+1 ) { bgnpolygon(); n3f( point[i][0] ); v3f( point[i][0] ); n3f( point[i+1][0] ); v3f( point[i+1][0] ); n3f( point[i+1][nlong-1] ); v3f( point[i+1][nlong-1] ); n3f( point[i][nlong-1] ); v3f( point[i][nlong-1] ); endpolygon(); } } -- Mason Woo--Manager, Customer Education Internet: woo@SGI.COM UUCP: {ames,ucbvax,decwrl,sun}!sgi!woo