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