SGI lighting model?
Mason Woo
woo at madonna.SGI.COM
Wed Aug 31 04:54:33 AEST 1988
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 at SGI.COM UUCP: {ames,ucbvax,decwrl,sun}!sgi!woo
More information about the Comp.sys.sgi
mailing list