From: Simon Mills (simon++at++wgs.estec.esa.nl)
Date: 06/16/2000 00:22:11
ross::barna wrote:
>
> > If it helps, I also implemented this but I altered all pfGeoSet alpha
> > values under the given node. I did this rather than change the
> > pfMaterial alpha values because materials may be shared with other
> > geometry and that would have adverse effects. I also had to take care in
> > the case that the geometry already had some transparent materials so I
> > had to combine any material alpha with my overall fade factor. Oh yes,
> > and it had to work on most hardware i.e. not iR specific so I couldn't
> > use multisample masks.
>
> do you have any sample code that i can read through?
> i would also like to implement fading...
OK, here's my test code as a follow up to my previous posting. I my case
I was using it to fade models made in Multigen on O2/Octane/Onyx2. As
usual, any comments or improvements are welcome ;-).
Regards, Simon
________________________________________________________________________
Simon Mills
Silicon Worlds S.A.
c/o Modelling & Simulation Section (TOS-EMM) Tel: +31 (0)71 565 3725
European Space Agency (ESA/ESTEC) Fax: +31 (0)71 565 5419
Postbus 299, 2200AG Noordwijk e-mail: simon++at++wgs.estec.esa.nl
The Netherlands http://www.estec.esa.nl/wmwww/EMM
________________________________________________________________________
/*
* fade.c++
*
* Fade a node or sub-hierarchy i.e vary it's transparency in real-time.
*
* Simon Mills ESA/ESTEC/TOS-EMM
* 01-Mar-99
*
* Notes:
*
* Modifies the node's draw traversal mask. Any changes from the default will
* be overriden.
*
* The changes to be alpha values in the geosets should use pfFlux to be
* frame accurate. The direct values are used at present. IF the change is
* slow this inaccuracy is not noticeable.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <Performer/pf.h>
#include <Performer/pfui.h> // for processKeybd()
#include <Performer/pfutil.h>
#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfScene.h>
#include <Performer/pf/pfGeode.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pr/pfType.h>
#include <Performer/pr/pfGeoSet.h>
#include <Performer/pr/pfGeoState.h>
#include <Performer/pr/pfMaterial.h>
#include "fly.h"
/******************************************************************************
*
* APPLICATION PROCESS ROUTINES
*
******************************************************************************/
/* Part of scene to fade */
static pfNode *Node;
/*****************************************************************************/
/* Lookup node of given type by name */
static pfNode *
lookupNode(pfNode *root, pfType *type, const char *name)
{
pfNode *node;
node = root->lookup(name, type);
if (node == NULL)
pfNotify(PFNFY_WARN, PFNFY_PRINT, "Fade: Node '%s' not found", name);
else
pfNotify(PFNFY_INFO, PFNFY_PRINT,
"Fade: found %s '%s'", type->getName(), name);
return node;
}
void
PostInitApp(int argc, char *argv[])
{
pfNotify(PFNFY_INFO, PFNFY_PRINT, "Fade: Press 'P' key to fade node on/off");
if (argc != 2) {
pfNotify(PFNFY_WARN, PFNFY_PRINT, "Fade: must give the name of node");
return;
}
/* Get part of scene by name */
Node = lookupNode((pfNode *)ViewState->scene,
pfNode::getClassType(), argv[1]);
}
/**************************** UPDATE SECTION *******************************/
static void
setGeodeAlpha(pfGeode *geode, float alpha)
{
int nrGSets = geode->getNumGSets();
pfGeoSet *gset;
int nColors;
int minIndex, maxIndex; // dummy
pfVec4 *clist;
ushort *ilist; // dummy
pfGeoState *gstate;
pfMaterial *mat;
float matAlpha, finalAlpha;
// For each geoset in the geode
for (int g = 0; g < nrGSets; g++) {
gset = geode->getGSet(g);
// Check we have a color array bound
if (gset->getAttrBind(PFGS_COLOR4) == PFGS_OFF)
pfNotify(PFNFY_WARN, PFNFY_PRINT,
"Fade: no color array to modify - giving up");
else {
// Get geostate material otherwise get global material
gstate = gset->getGState();
mat = (pfMaterial *) gstate->getAttr(PFSTATE_FRONTMTL);
if (!mat) {
mat = pfGetCurMtl(PFMTL_FRONT);
}
// Get material's alpha and use this as basis
if (mat)
matAlpha = mat->getAlpha();
else
matAlpha = 1.0f;
// Get geoset color array
nColors = gset->getAttrRange(PFGS_COLOR4, &minIndex, &maxIndex);
gset->getAttrLists(PFGS_COLOR4, (void **)&clist, &ilist);
// Override transparency in the color arrays.
// Assuming there is no transparency set in the colour arrays
// N.B. This should use pfFluxes to be frame accurate!
finalAlpha = matAlpha * alpha;
for (int c = 0; c < nColors; c++)
clist[c][3] = finalAlpha;
// Place geoset into transparent bin if requires blending.
// This is to avoid rendering artifacts during fade.
if (alpha < 1.0f)
gset->setDrawBin(PFSORT_TRANSP_BIN);
else
gset->setDrawBin(-1);
// Check if geoset GL display list needs recompiling (for iR)
if (gset->getDrawMode(PFGS_COMPILE_GL) == PF_ON)
gset->setDrawMode(PFGS_COMPILE_GL, PF_ON);
}
}
}
static int
cbUpdateAlpha(pfuTraverser *trav)
{
pfNode *node = trav->node;
float alpha = *((float *) trav->data);
/* Update geode transparency */
if (node->isOfType(pfGeode::getClassType())) {
setGeodeAlpha((pfGeode *)node, alpha);
}
return PFTRAV_CONT;
}
static int
setTransparencyOn(pfTraverser *trav, void *data)
{
// Override transparency and don't draw pixels with < 1% alpha
pfTransparency(PFTR_HIGH_QUALITY);
pfAlphaFunc(0.01f, PFAF_GEQUAL);
pfOverride(PFSTATE_TRANSPARENCY | PFSTATE_ALPHAFUNC, PF_ON);
return PFTRAV_CONT;
}
static int
setTransparencyOff(pfTraverser *trav, void *data)
{
// Remove override on transparency and alpha function
pfOverride(PFSTATE_TRANSPARENCY | PFSTATE_ALPHAFUNC, PF_OFF);
pfAlphaFunc(0.0f, PFAF_OFF);
pfTransparency(PFTR_OFF);
return PFTRAV_CONT;
}
/* Set transparency of all geometry under node */
static void
updateAlpha(pfNode *node, float alpha)
{
pfuTraverser trav;
// Check node is valid
if (!node) {
pfNotify(PFNFY_WARN, PFNFY_PRINT, "UpdateAlpha: node is NULL");
return;
}
// Install or clear node pre-, post-callbacks
if (alpha < 1.0f)
node->setTravFuncs(PFTRAV_DRAW, setTransparencyOn, setTransparencyOff);
else
node->setTravFuncs(PFTRAV_DRAW, NULL, NULL);
// If alpha is 0 just disable drawing
// N.B. This overrides any draw trav mask that was set!
if (alpha == 0.0f)
node->setTravMask(PFTRAV_DRAW, 0x00000000, PFTRAV_SELF, PF_SET);
else
node->setTravMask(PFTRAV_DRAW, 0xFFFFFFFF, PFTRAV_SELF, PF_SET);
// Traverse all geosets under node and update transparency
pfuInitTraverser(&trav);
trav.preFunc = cbUpdateAlpha;
trav.data = α
pfuTraverse(node, &trav);
}
/*
* Just for testing
*/
static int FadeOn = FALSE;
void
ProcessKeyboard(pfuEventStream *events) /* process keyboard in addition to Fly standard keys */
{
int i;
int j;
int key;
int dev;
int val;
/*
* N.B. Only alter the queue if you wish to disable Fly functions
*/
for (j = 0; j < events->numDevs; j++)
{
dev = events->devQ[j];
val = events->devVal[j];
if (events->devCount[dev] > 0)
{
switch(dev)
{
/* Main keyboard */
case PFUDEV_KEYBD:
for (i = 0; i < events->numKeys; i++)
{
key = events->keyQ[i];
if (events->keyCount[key])
{
switch(key)
{
case 'p': /* extra command */
printf("p key pressed\n");
FadeOn = !FadeOn;
break;
}
}
}
break;
}
}
}
}
/* Make function which "stops" fading of geode to do tidying up etc. ? */
void
PostUpdateApp(void)
{
float alpha;
static int prevFadeOn = FALSE;
double currTime = pfGetTime();
static double startTime = 0.0;
static int fading = FALSE;
float fadeDuration = 2.0f;
//alpha = ( 1.0f + cosf(2.0f * (float)pfGetTime()) ) / 2.0f;
// Detect start of fading
if ((FadeOn && !prevFadeOn) || (!FadeOn && prevFadeOn)) {
startTime = currTime;
fading = TRUE;
}
// During fading (1 sec) compute and set new transparency
if (fading) {
if (FadeOn) {
alpha = PF_MAX2(0.0f, 1.0f - (float) (currTime - startTime)/fadeDuration);
if (alpha == 0.0f)
fading = FALSE;
}
else {
alpha = PF_MIN2(1.0f, (float) (currTime - startTime)/fadeDuration);
if (alpha == 1.0f)
fading = FALSE;
}
printf("Alpha = %f\n", alpha);
if (Node)
updateAlpha(Node, alpha);
}
prevFadeOn = FadeOn;
}
This archive was generated by hypermail 2b29 : Fri Jun 16 2000 - 00:22:23 PDT