home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
RADIANCE
/
SRC
/
RT
/
AMBIENT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-07
|
10KB
|
447 lines
/* Copyright (c) 1992 Regents of the University of California */
#ifndef lint
static char SCCSid[] = "@(#)ambient.c 2.14 11/3/92 LBL";
#endif
/*
* ambient.c - routines dealing with ambient (inter-reflected) component.
*
* 5/9/86
*/
#include "ray.h"
#include "octree.h"
#include "otypes.h"
#include "ambient.h"
#include "random.h"
#define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
typedef struct ambtree {
AMBVAL *alist; /* ambient value list */
struct ambtree *kid; /* 8 child nodes */
} AMBTREE; /* ambient octree */
extern CUBE thescene; /* contains space boundaries */
#define MAXASET 511 /* maximum number of elements in ambient set */
OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
double maxarad; /* maximum ambient radius */
double minarad; /* minimum ambient radius */
static AMBTREE atrunk; /* our ambient trunk node */
static FILE *ambfp = NULL; /* ambient file pointer */
#define AMBFLUSH (BUFSIZ/AMBVALSIZ)
#define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
#define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
extern long ftell(), lseek();
static int initambfile(), avsave(), avinsert(), ambsync();
setambres(ar) /* set ambient resolution */
int ar;
{
/* set min & max radii */
if (ar <= 0) {
minarad = 0.0;
maxarad = thescene.cusize / 2.0;
} else {
minarad = thescene.cusize / ar;
maxarad = 16.0 * minarad; /* heuristic */
if (maxarad > thescene.cusize / 2.0)
maxarad = thescene.cusize / 2.0;
}
if (maxarad <= FTINY)
maxarad = .001;
}
setambient(afile) /* initialize calculation */
char *afile;
{
long headlen;
AMBVAL amb;
/* init ambient limits */
setambres(ambres);
/* open ambient file */
if (afile != NULL)
if ((ambfp = fopen(afile, "r+")) != NULL) {
initambfile(0);
headlen = ftell(ambfp);
while (readambval(&amb, ambfp))
avinsert(&amb, &atrunk, thescene.cuorg,
thescene.cusize);
/* align */
fseek(ambfp, -((ftell(ambfp)-headlen)%AMBVALSIZ), 1);
} else if ((ambfp = fopen(afile, "w+")) != NULL)
initambfile(1);
else {
sprintf(errmsg, "cannot open ambient file \"%s\"",
afile);
error(SYSTEM, errmsg);
}
}
ambnotify(obj) /* record new modifier */
OBJECT obj;
{
static int hitlimit = 0;
register OBJREC *o = objptr(obj);
register char **amblp;
if (hitlimit || !ismodifier(o->otype))
return;
for (amblp = amblist; *amblp != NULL; amblp++)
if (!strcmp(o->oname, *amblp)) {
if (ambset[0] >= MAXASET) {
error(WARNING, "too many modifiers in ambient list");
hitlimit++;
return; /* should this be fatal? */
}
insertelem(ambset, obj);
return;
}
}
ambient(acol, r) /* compute ambient component for ray */
COLOR acol;
register RAY *r;
{
static int rdepth = 0; /* ambient recursion */
double d;
if (ambdiv <= 0) /* no ambient calculation */
goto dumbamb;
/* check number of bounces */
if (rdepth >= ambounce)
goto dumbamb;
/* check ambient list */
if (ambincl != -1 && r->ro != NULL &&
ambincl != inset(ambset, r->ro->omod))
goto dumbamb;
if (ambacc <= FTINY) { /* no ambient storage */
rdepth++;
d = doambient(acol, r, r->rweight, NULL, NULL);
rdepth--;
if (d == 0.0)
goto dumbamb;
return;
}
/* get ambient value */
setcolor(acol, 0.0, 0.0, 0.0);
d = sumambient(acol, r, rdepth,
&atrunk, thescene.cuorg, thescene.cusize);
if (d > FTINY)
scalecolor(acol, 1.0/d);
else {
d = makeambient(acol, r, rdepth++);
rdepth--;
}
if (d > FTINY)
return;
dumbamb: /* return global value */
copycolor(acol, ambval);
}
double
sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
COLOR acol;
register RAY *r;
int al;
AMBTREE *at;
FVECT c0;
double s;
{
double d, e1, e2, wt, wsum;
COLOR ct;
FVECT ck0;
int i;
register int j;
register AMBVAL *av;
/* do this node */
wsum = 0.0;
for (av = at->alist; av != NULL; av = av->next) {
/*
* Ambient level test.
*/
if (av->lvl > al || av->weight < r->rweight-FTINY)
continue;
/*
* Ambient radius test.
*/
e1 = 0.0;
for (j = 0; j < 3; j++) {
d = av->pos[j] - r->rop[j];
e1 += d * d;
}
e1 /= av->rad * av->rad;
if (e1 > ambacc*ambacc*1.21)
continue;
/*
* Normal direction test.
*/
e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
if (e2 < 0.0) e2 = 0.0;
if (e1 + e2 > ambacc*ambacc*1.21)
continue;
/*
* Ray behind test.
*/
d = 0.0;
for (j = 0; j < 3; j++)
d += (r->rop[j] - av->pos[j]) *
(av->dir[j] + r->ron[j]);
if (d*0.5 < -minarad*ambacc-.001)
continue;
/*
* Jittering final test reduces image artifacts.
*/
wt = sqrt(e1) + sqrt(e2);
wt *= .9 + .2*urand(9015+samplendx);
if (wt > ambacc)
continue;
if (wt <= 1e-3)
wt = 1e3;
else
wt = 1.0 / wt;
wsum += wt;
extambient(ct, av, r->rop, r->ron);
scalecolor(ct, wt);
addcolor(acol, ct);
}
if (at->kid == NULL)
return(wsum);
/* do children */
s *= 0.5;
for (i = 0; i < 8; i++) {
for (j = 0; j < 3; j++) {
ck0[j] = c0[j];
if (1<<j & i)
ck0[j] += s;
if (r->rop[j] < ck0[j] - OCTSCALE*s)
break;
if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
break;
}
if (j == 3)
wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
}
return(wsum);
}
double
makeambient(acol, r, al) /* make a new ambient value */
COLOR acol;
register RAY *r;
int al;
{
AMBVAL amb;
FVECT gp, gd;
/* compute weight */
amb.weight = pow(AVGREFL, (double)al);
if (r->rweight < 0.2*amb.weight) /* heuristic */
amb.weight = r->rweight;
/* compute ambient */
amb.rad = doambient(acol, r, amb.weight, gp, gd);
if (amb.rad == 0.0)
return(0.0);
/* store it */
VCOPY(amb.pos, r->rop);
VCOPY(amb.dir, r->ron);
amb.lvl = al;
copycolor(amb.val, acol);
VCOPY(amb.gpos, gp);
VCOPY(amb.gdir, gd);
/* insert into tree */
avsave(&amb); /* and save to file */
return(amb.rad);
}
extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
COLOR cr;
register AMBVAL *ap;
FVECT pv, nv;
{
FVECT v1, v2;
register int i;
double d;
d = 1.0; /* zeroeth order */
/* gradient due to translation */
for (i = 0; i < 3; i++)
d += ap->gpos[i]*(pv[i]-ap->pos[i]);
/* gradient due to rotation */
VCOPY(v1, ap->dir);
fcross(v2, v1, nv);
d += DOT(ap->gdir, v2);
if (d <= 0.0) {
setcolor(cr, 0.0, 0.0, 0.0);
return;
}
copycolor(cr, ap->val);
scalecolor(cr, d);
}
static
initambfile(creat) /* initialize ambient file */
int creat;
{
extern char *progname, *octname, VersionID[];
#ifdef MSDOS
setmode(fileno(ambfp), O_BINARY);
#endif
setbuf(ambfp, bmalloc(BUFSIZ));
if (creat) { /* new file */
fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
progname, colval(ambval,RED),
colval(ambval,GRN), colval(ambval,BLU),
ambounce, ambacc);
fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
ambdiv, ambssamp, ambres,
octname==NULL ? "" : octname);
fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
fputformat(AMBFMT, ambfp);
putc('\n', ambfp);
putambmagic(ambfp);
fflush(ambfp);
#ifndef NIX
sync(); /* protect against NFS buffering */
#endif
} else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
error(USER, "bad ambient file");
}
static
avsave(av) /* insert and save an ambient value */
AMBVAL *av;
{
static int nunflshed = 0;
avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
if (ambfp == NULL)
return;
if (writambval(av, ambfp) < 0)
goto writerr;
if (++nunflshed >= AMBFLUSH) {
if (ambsync() == EOF)
goto writerr;
nunflshed = 0;
}
return;
writerr:
error(SYSTEM, "error writing ambient file");
}
static
avinsert(aval, at, c0, s) /* insert ambient value in a tree */
AMBVAL *aval;
register AMBTREE *at;
FVECT c0;
double s;
{
FVECT ck0;
int branch;
register AMBVAL *av;
register int i;
if ((av = newambval()) == NULL)
goto memerr;
copystruct(av, aval);
VCOPY(ck0, c0);
while (s*(OCTSCALE/2) > av->rad*ambacc) {
if (at->kid == NULL)
if ((at->kid = newambtree()) == NULL)
goto memerr;
s *= 0.5;
branch = 0;
for (i = 0; i < 3; i++)
if (av->pos[i] > ck0[i] + s) {
ck0[i] += s;
branch |= 1 << i;
}
at = at->kid + branch;
}
av->next = at->alist;
at->alist = av;
return;
memerr:
error(SYSTEM, "out of memory in avinsert");
}
#ifdef NIX
static
ambsync() /* flush ambient file */
{
return(fflush(ambfp));
}
#else
#include <sys/types.h>
#include <sys/stat.h>
static
ambsync() /* synchronize ambient file */
{
static FILE *ambinp = NULL;
struct flock fls;
struct stat sts;
#define flen sts.st_size
AMBVAL avs;
long lastpos;
register int n;
/* gain exclusive access */
fls.l_type = F_WRLCK;
fls.l_whence = 0;
fls.l_start = 0L;
fls.l_len = 0L;
if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
error(SYSTEM, "cannot lock ambient file");
/* see if file has grown */
lastpos = lseek(fileno(ambfp), 0L, 1); /* get previous position */
if (fstat(fileno(ambfp), &sts) < 0) /* get current length */
error(SYSTEM, "cannot stat ambient file");
if (n = (flen - lastpos)/AMBVALSIZ) { /* file has grown */
if (ambinp == NULL) { /* use duplicate file */
ambinp = fdopen(dup(fileno(ambfp)), "r");
if (ambinp == NULL)
error(SYSTEM, "fdopen failed in ambsync");
}
while (n--) { /* load contributed values */
readambval(&avs, ambinp);
avinsert(&avs,&atrunk,thescene.cuorg,thescene.cusize);
} /* moves shared file pointer */
if (n = (flen - lastpos)%AMBVALSIZ) /* alignment */
lseek(fileno(ambfp), flen-n, 0);
}
n = fflush(ambfp); /* calls write() at last */
fls.l_type = F_UNLCK; /* release file */
fcntl(fileno(ambfp), F_SETLKW, &fls);
return(n);
}
#endif