Re: Spotlights and Shadows

New Message Reply Date view Thread view Subject view Author view

Anita Kishore (kishore++at++triavest.com)
Mon, 16 Jun 1997 15:51:03 -0700


On Jun 16, 11:47am, Charles Vonness wrote:
> Subject: Spotlights and Shadows
> If anyone has any source code of an example of how to do spotlights that
> cast shadows in Performer I would greatly appreciate it. I am running
> on an Onyx IR running IRIX 6.2. I am running Performer 2.1 also.
>

Here is the smaple code that is distributed with performer 2.0.1 for RE2.
Hope this helps.

-anita
kishore++at++triavest.com

/*
 * Copyright 1995, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 *
 * UNPUBLISHED -- Rights reserved under the copyright laws of the United
 * States. Use of a copyright notice is precautionary only and does not
 * imply publication or disclosure.
 *
 * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to restrictions
 * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
 * in similar or successor clauses in the FAR, or the DOD or NASA FAR
 * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
 * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that (i) the above copyright notices and this
 * permission notice appear in all copies of the software and related
 * documentation, and (ii) the name of Silicon Graphics may not be
 * used in any advertising or publicity relating to the software
 * without the specific, prior written permission of Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
 * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 * shadows.c: Performer program to demonstrate use of pfLightSource shadowing
 * and projected texturing.
 * Based on simple.c
 *
 * $Revision: 1.7 $ $Date: 1995/12/03 23:53:00 $
 *
 */

#include <stdlib.h>
#include <math.h>
#include <Performer/pf.h>
#include <Performer/pfdu.h>
#include <Performer/pfutil.h>

/*------------------------------------------------------------------*/

void
OpenPipeWin (pfPipeWindow *pw)
{
    pfLightModel *lm;
    int numSamples = 16;

    pfOpenPWin(pw);

#ifdef IRISGL
    /* Shadows require a 32 bit non-multisampled zbuffer */
    do
    {
        zbsize(32);
        stensize(1);
        mssize(numSamples, 32, 1);
        gconfig();

        numSamples >>= 1;

    } while (PF_ABS(getgconfig(GC_BITS_ZBUFFER)) < 32 && numSamples > 0);

    if (numSamples > 0)
        multisample(1);
    else
    {
        RGBsize(12);
        mssize(0, 0, 0);
        zbsize(32);
        stensize(1);
        gconfig();
        multisample(0);
    }

    pfNotify(PFNFY_NOTICE, PFNFY_RESOURCE,
             "mssize(%d, %d, %d) zbsize(%d) Zrange 0x%x - 0x%x\n",
             getgconfig(GC_MS_SAMPLES),
             getgconfig(GC_BITS_MS_ZBUFFER),
             getgconfig(GC_BITS_MS_STENCIL),
             getgconfig(GC_BITS_ZBUFFER),
             getgconfig(GC_MS_ZMIN), getgconfig(GC_MS_ZMAX));
#endif

    lm = pfNewLModel(NULL);
    pfLModelLocal(lm, 1);
    pfApplyLModel(lm);

    pfCullFace(PFCF_BACK);
}

void
DrawChannel (pfChannel *chan, void *data)
{
    pfVec4 clr;

    pfSetVec4(clr, .2f, .2f, .2f, 1.0f);
    pfClear(PFCL_COLOR|PFCL_DEPTH, clr);
    pfDraw();
}

/*
 * Usage() -- print usage advice and exit. This
 * procedure is executed in the application process.
 */
static void
Usage (void)
{
    pfNotify(PFNFY_FATAL, PFNFY_USAGE, "Usage: shadows file.ext ...\n");
    exit(1);
}

/* Compute matrix so +Y axis of DCS is pointing at 'at' */
static void
lookAt(pfDCS *dcs, pfVec3 at)
{
    pfVec3 v, pos;
    pfMatrix mat;
    static pfVec3 yaxis = {0.0f, 1.0f, 0.0f};
     
    /* v is origin of dcs */
    pfGetMatRowVec3(*pfGetDCSMatPtr(dcs), 3, pos);
     
    /* v is direction vector from dcs to 'at' */
    pfSubVec3(v, at, pos);
    pfNormalizeVec3(v);

    /* Rotate y-axis onto v */
    pfMakeVecRotVecMat(mat, yaxis, v);
    pfSetMatRowVec3(mat, 3, pos); /* restore dcs origin */
    pfDCSMat(dcs, mat);
}

#define SPOT_SIZE 256
#define SPOT_RADIUS 64

/*
 * Create circular image for projected spotlight texture.
*/
static pfTexture*
initSpotTex(void)
{
    long i, j, win;
    pfTexture *tex;
    unsigned short *image;

    image = pfMalloc(sizeof(unsigned short) * SPOT_SIZE * SPOT_SIZE,
                     pfGetSharedArena());

    for (i = 0; i < SPOT_SIZE / 2; i++)
    {
        for (j = 0; j < SPOT_SIZE / 2; j++)
        {
            unsigned long val;

            val = 0;

            /* See if corners of texel are within circle. This antialiases
             * the edge of the circle somewhat. */
            if ((i * i + j * j) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if (((i + 1) * (i + 1) + j * j) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if (((i + 1) * (i + 1) + (j + 1) * (j + 1)) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if ((i * i + (j + 1) * (j + 1)) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;

            val >>= 2;

            /* Set all 4 quadrants to val */
            image[(SPOT_SIZE / 2 - i) * SPOT_SIZE + (SPOT_SIZE / 2 - j)] =
                image[(SPOT_SIZE / 2 - i) * SPOT_SIZE + (SPOT_SIZE / 2 + j)] =
                image[(SPOT_SIZE / 2 + i) * SPOT_SIZE + (SPOT_SIZE / 2 + j)] =
                image[(SPOT_SIZE / 2 + i) * SPOT_SIZE + (SPOT_SIZE / 2 - j)] =
                val;
        }
    }

    tex = pfNewTex(pfGetSharedArena());
    pfTexImage(tex, (uint*) image, 2, SPOT_SIZE, SPOT_SIZE, 0);
    pfTexFormat(tex, PFTEX_INTERNAL_FORMAT, PFTEX_IA_8);
    pfTexRepeat(tex, PFTEX_WRAP, PFTEX_CLAMP);

    return tex;
}

#define FOV 60.0f
#define NEAR 1.0f
#define SQRT2INV .7071067811865475244

static pfDCS *shadDCS, *projDCS;

static pfGroup*
initLSources(pfSphere *bsphere)
{
    pfFrustum *shadFrust;
    pfLightSource *shad, *proj;
    pfTexture *tex;
    pfGroup *group;
    float d;
    pfMatrix mat;
    void *arena = pfGetSharedArena();

    /* Create and configure shadow frustum. Fit frustum tightly to scene. */
    shadFrust = pfNewFrust(arena);
    pfMakeSimpleFrust(shadFrust, FOV);

    d = bsphere->radius / sinf(PF_DEG2RAD(FOV/2.0f));
    d = PF_MAX2(d, NEAR + bsphere->radius);

    pfFrustNearFar(shadFrust, NEAR, d + 1.1f * bsphere->radius);

    /* Create and configure white shadow casting light source */
    shad = pfNewLSource();
    pfLSourceMode(shad, PFLS_SHADOW_ENABLE, 1);
    pfLSourceAttr(shad, PFLS_PROJ_FRUST, shadFrust);
    pfLSourceColor(shad, PFLT_DIFFUSE, 1.0f, 1.0f, 1.0f);
    pfLSourceVal(shad, PFLS_INTENSITY, .5f);
    pfLSourcePos(shad, 0.0f, 0.0f, 0.0f, 1.0f); /* Make light local */

    /* Create and configure blue spotlight */
    proj = pfNewLSource();
    tex = initSpotTex();
/* You can load your own spotlight texture if you wish
* tex = pfNewTex(arena);
* pfLoadTexFile(tex, "spotlight.inta");
*/
    pfLSourceMode(proj, PFLS_PROJTEX_ENABLE, 1);
    pfLSourceAttr(proj, PFLS_PROJ_FRUST, shadFrust);
    pfLSourceAttr(proj, PFLS_PROJ_TEX, tex);
    pfLSourceColor(proj, PFLT_DIFFUSE, 0.0f, 0.0f, 1.0f);
    pfLSourceVal(proj, PFLS_INTENSITY, .5f);
    pfLSourcePos(proj, 0.0f, 0.0f, 0.0f, 1.0f); /* Make light local */

    group = pfNewGroup();

    /* Make DCSes to move lights around */
    shadDCS = pfNewDCS();

    pfMakeTransMat(mat, d*SQRT2INV, 0.0f, d*SQRT2INV);
    pfDCSMat(shadDCS, mat);
    lookAt(shadDCS, bsphere->center);

    pfAddChild(shadDCS, shad);
    pfAddChild(group, shadDCS);

    projDCS = pfNewDCS();

    pfMakeTransMat(mat, -d*SQRT2INV, 0.0f, d*SQRT2INV);
    pfDCSMat(projDCS, mat);
    lookAt(projDCS, bsphere->center);

    pfAddChild(projDCS, proj);
    pfAddChild(group, projDCS);

    return group;
}

static pfGeode*
initFloor(pfSphere *bsphere)
{
    pfGeoSet *gset;
    pfGeoState *gstate;
    pfGeode *geode;
    pfVec3 *v;
    pfMaterial *mtl;
    float d;
    void *arena = pfGetSharedArena();

    gset = pfNewGSet(arena);
    gstate = pfNewGState(arena);
    geode = pfNewGeode();

    v = (pfVec3*)pfMalloc(sizeof(pfVec3) * 4, arena);
    d = 3.0f * bsphere->radius;
    pfSetVec3(v[0], -d, -d, -d/3.0f);
    pfSetVec3(v[1], d, -d, -d/3.0f);
    pfSetVec3(v[2], d, d, -d/3.0f);
    pfSetVec3(v[3], -d, d, -d/3.0f);
    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, v, NULL);

    v = (pfVec3*)pfMalloc(sizeof(pfVec3), arena);
    pfSetVec3(v[0], 0.0f, 0.0f, 1.0f);
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_OVERALL, v, NULL);

    pfGSetPrimType(gset, PFGS_QUADS);
    pfGSetNumPrims(gset, 1);

    mtl = pfNewMtl(arena);
    pfMtlColorMode(mtl, PFMTL_BOTH, PFMTL_CMODE_OFF);
    pfGStateAttr(gstate, PFSTATE_FRONTMTL, mtl);
    pfGStateMode(gstate, PFSTATE_ENLIGHTING, 1);

    pfGSetGState(gset, gstate);
    pfAddGSet(geode, gset);

    return geode;
}

int
main (int argc, char *argv[])
{
    double t = 0.;
     
    pfScene *scene;
    pfNode *root;
    pfDCS *dcs;
    pfPipe *p;
    pfPipeWindow *pw;
    pfChannel *chan;
    pfSphere bsphere;
    pfCoord view;
    pfMatrix mat, orbit;
    pfList *texList;
    int ret;

#ifndef IRISGL
    printf("Sorry, shadows doesn't work in OPENGL\n");
    return 0;
#endif
    if (argc < 2)
        Usage();

    /* Initialize Performer */
    pfInit();

    pfQueryFeature(PFQFTR_TEXTURE_PROJECTIVE, &ret);
    if (!(ret == PFQFTR_FAST))
    {
        printf("Sorry, shadows aren't supported on this machine.\n");
        return 0;
    }

    /* Use default multiprocessing mode based on number of
     * processors.
     */
    pfMultiprocess(PFMP_DEFAULT);

    /* Load all loader DSO's before pfConfig() forks */
    pfdInitConverter(argv[1]);

    /* Configure multiprocessing mode and start parallel
     * processes.
     */
    pfConfig();

    /* Append to PFPATH additional standard directories where
     * geometry and textures exist
     */
    pfFilePath(".:/usr/share/Performer/data");

    /* Do not use FLAT_ primitives because they look bad
     * with local lighting.
    */
    pfdBldrMode(PFDBLDR_MESH_LOCAL_LIGHTING, 1);

    /* Read a single file, of any known type. */
    if ((root = pfdLoadFile(argv[1])) == NULL)
    {
        pfExit();
        exit(-1);
    }

    /* Create and attach loaded subgraph to a pfScene. */
    scene = pfNewScene();
    dcs = pfNewDCS();
    pfMakeRotMat(mat, 30.0f, 1.0f, 0.0f, 0.0f);
    pfDCSMat(dcs, mat);
    pfAddChild(dcs, root);
    pfAddChild(scene, dcs);

    /* determine extent of scene's geometry */
    pfGetNodeBSphere (scene, &bsphere);

    /* Create pfLightSources and add to scene */
    pfAddChild(scene, initLSources(&bsphere));

    /* Create "floor" for shadows */
    pfAddChild(dcs, initFloor(&bsphere));

    /* Configure and open GL window */
    p = pfGetPipe(0);
    pw = pfNewPWin(p);
    pfPWinName(pw, argv[0]);
    pfPWinConfigFunc(pw, OpenPipeWin);
    pfPWinOriginSize(pw, 0, 0, 500, 500);
    pfConfigPWin(pw);

    /* Create and configure a pfChannel. */
    chan = pfNewChan(p);
    pfChanScene(chan, scene);
    pfChanNearFar(chan, 1.0f, 5.0f * bsphere.radius);
    pfChanFOV(chan, 45.0f, 0.0f);
    pfCopyVec3(view.xyz, bsphere.center);
    view.xyz[PF_Y] -= 3.0f * bsphere.radius;
    pfSetVec3(view.hpr, 0.0f, 0.0f, 0.0f);
    pfChanView(chan, view.xyz, view.hpr);
    pfChanTravFunc(chan, PFTRAV_DRAW, DrawChannel);

    /* If scene is non-textured then we can save an entire rendering pass */
    texList = pfuMakeSceneTexList(scene);
    if (pfGetNum(texList) == 0)
    {
        pfChanTravMode(chan, PFTRAV_MULTIPASS, PFMPASS_NONTEX_SCENE);
        pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
                 "Scene is non-textured! Using PFMPASS_NONTEX_SCENE "
                 "optimization");
    }

    pfMakeRotMat(orbit, 1.0f, 0.0f, 0.0f, 1.0f);

    /* Simulate for twenty seconds. */
    while (t < 20.0f)
    {
        /* Spin light sources around object */
        pfMultMat(mat, *pfGetDCSMatPtr(projDCS), orbit);
        pfDCSMat(projDCS, mat);
        lookAt(projDCS, bsphere.center);

        pfMultMat(mat, *pfGetDCSMatPtr(shadDCS), orbit);
        pfDCSMat(shadDCS, mat);
        lookAt(shadDCS, bsphere.center);

        /* Initiate cull/draw for this frame. */
        pfFrame();
    }

    /* Terminate parallel processes and exit. */
    pfExit();

    return 0;
}

=======================================================================
List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/
            Submissions: info-performer++at++sgi.com
        Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:55:27 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.