ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.45
Committed: Mon Oct 21 12:58:06 1991 UTC (32 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.44: +76 -103 lines
Log Message:
added source sampling (-ds option)

File Contents

# User Rev Content
1 greg 1.42 /* Copyright (c) 1991 Regents of the University of California */
2 greg 1.1
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * source.c - routines dealing with illumination sources.
9     *
10     * 8/20/85
11     */
12    
13     #include "ray.h"
14    
15 greg 1.4 #include "octree.h"
16    
17 greg 1.1 #include "otypes.h"
18    
19 greg 1.35 #include "source.h"
20 greg 1.1
21 greg 1.35 /*
22     * Structures used by direct()
23     */
24 greg 1.1
25 greg 1.35 typedef struct {
26 greg 1.45 int sno; /* source number */
27 greg 1.35 FVECT dir; /* source direction */
28     COLOR coef; /* material coefficient */
29     COLOR val; /* contribution */
30     } CONTRIB; /* direct contribution */
31 greg 1.1
32 greg 1.35 typedef struct {
33 greg 1.45 int sndx; /* source index (to CONTRIB array) */
34 greg 1.35 float brt; /* brightness (for comparison) */
35     } CNTPTR; /* contribution pointer */
36 greg 1.1
37 greg 1.25 static CONTRIB *srccnt; /* source contributions in direct() */
38     static CNTPTR *cntord; /* source ordering in direct() */
39 greg 1.45 static int maxcntr = 0; /* size of contribution arrays */
40 greg 1.1
41 greg 1.25
42 greg 1.1 marksources() /* find and mark source objects */
43     {
44 greg 1.33 int i;
45 greg 1.1 register OBJREC *o, *m;
46 greg 1.36 register int ns;
47 greg 1.35 /* initialize dispatch table */
48     initstypes();
49     /* find direct sources */
50 greg 1.1 for (i = 0; i < nobjects; i++) {
51    
52     o = objptr(i);
53    
54 greg 1.35 if (!issurface(o->otype) || o->omod == OVOID)
55 greg 1.1 continue;
56    
57     m = objptr(o->omod);
58    
59 greg 1.24 if (!islight(m->otype))
60 greg 1.1 continue;
61    
62 greg 1.6 if (m->oargs.nfargs != (m->otype == MAT_GLOW ? 4 :
63     m->otype == MAT_SPOT ? 7 : 3))
64 greg 1.1 objerror(m, USER, "bad # arguments");
65    
66 greg 1.6 if (m->otype == MAT_GLOW &&
67     o->otype != OBJ_SOURCE &&
68     m->oargs.farg[3] <= FTINY)
69 greg 1.1 continue; /* don't bother */
70    
71 greg 1.35 if (sfun[o->otype].of == NULL ||
72     sfun[o->otype].of->setsrc == NULL)
73     objerror(o, USER, "illegal material");
74    
75 greg 1.36 if ((ns = newsource()) < 0)
76 greg 1.25 goto memerr;
77 greg 1.1
78 greg 1.37 setsource(&source[ns], o);
79 greg 1.1
80 greg 1.6 if (m->otype == MAT_GLOW) {
81 greg 1.36 source[ns].sflags |= SPROX;
82     source[ns].sl.prox = m->oargs.farg[3];
83 greg 1.6 if (o->otype == OBJ_SOURCE)
84 greg 1.36 source[ns].sflags |= SSKIP;
85 greg 1.6 } else if (m->otype == MAT_SPOT) {
86 greg 1.36 source[ns].sflags |= SSPOT;
87     if ((source[ns].sl.s = makespot(m)) == NULL)
88 greg 1.33 goto memerr;
89 greg 1.38 if (source[ns].sflags & SFLAT &&
90     !checkspot(source[ns].sl.s,source[ns].snorm)) {
91     objerror(o, WARNING,
92     "invalid spotlight direction");
93     source[ns].sflags |= SSKIP;
94     }
95 greg 1.6 }
96 greg 1.1 }
97 greg 1.25 if (nsources <= 0) {
98     error(WARNING, "no light sources found");
99     return;
100     }
101 greg 1.33 markvirtuals(); /* find and add virtual sources */
102 greg 1.45 /* allocate our contribution arrays */
103     maxcntr = nsources + MAXSPART*2; /* start with this many */
104     srccnt = (CONTRIB *)malloc(maxcntr*sizeof(CONTRIB));
105     cntord = (CNTPTR *)malloc(maxcntr*sizeof(CNTPTR));
106 greg 1.36 if (srccnt == NULL || cntord == NULL)
107 greg 1.33 goto memerr;
108     return;
109 greg 1.25 memerr:
110     error(SYSTEM, "out of memory in marksources");
111 greg 1.1 }
112    
113    
114 greg 1.45 srcray(sr, r, si) /* send a ray to a source, return domega */
115 greg 1.1 register RAY *sr; /* returned source ray */
116     RAY *r; /* ray which hit object */
117 greg 1.45 SRCINDEX *si; /* source sample index */
118 greg 1.1 {
119 greg 1.45 double d; /* distance to source */
120     FVECT vd;
121     register SRCREC *srcp;
122     register int i;
123 greg 1.1
124 greg 1.45 rayorigin(sr, r, SHADOW, 1.0); /* ignore limits */
125 greg 1.1
126 greg 1.45 while ((d = nextssamp(sr->rorg, sr->rdir, si)) != 0.0) {
127     sr->rsrc = si->sn; /* remember source */
128     srcp = source + si->sn;
129     if (srcp->sflags & SDISTANT) {
130     if (srcp->sflags & SSPOT) { /* check location */
131 greg 1.1 for (i = 0; i < 3; i++)
132 greg 1.45 vd[i] = srcp->sl.s->aim[i] - sr->rorg[i];
133 greg 1.40 d = DOT(sr->rdir,vd);
134 greg 1.41 if (d <= FTINY)
135 greg 1.45 continue;
136 greg 1.40 d = DOT(vd,vd) - d*d;
137 greg 1.45 if (PI*d > srcp->sl.s->siz)
138     continue;
139 greg 1.40 }
140 greg 1.45 return(1); /* sample OK */
141 greg 1.40 }
142 greg 1.45 /* local source */
143 greg 1.6 /* check proximity */
144 greg 1.45 if (srcp->sflags & SPROX && d > srcp->sl.prox)
145     continue;
146 greg 1.6 /* check angle */
147 greg 1.45 if (srcp->sflags & SSPOT) {
148     if (srcp->sl.s->siz < 2.0*PI *
149     (1.0 + DOT(srcp->sl.s->aim,sr->rdir)))
150     continue;
151     /* adjust solid angle */
152     si->dom *= d*d;
153     d += srcp->sl.s->flen;
154     si->dom /= d*d;
155 greg 1.1 }
156 greg 1.45 return(1); /* sample OK */
157     }
158     return(0); /* no more samples */
159 greg 1.1 }
160    
161    
162 greg 1.35 srcvalue(r) /* punch ray to source and compute value */
163     RAY *r;
164 greg 1.1 {
165 greg 1.35 register SRCREC *sp;
166 greg 1.1
167 greg 1.35 sp = &source[r->rsrc];
168     if (sp->sflags & SVIRTUAL) { /* virtual source */
169     /* check intersection */
170     if (!(*ofun[sp->so->otype].funp)(sp->so, r))
171     return;
172     raycont(r); /* compute contribution */
173     return;
174 greg 1.1 }
175 greg 1.35 /* compute intersection */
176     if (sp->sflags & SDISTANT ? sourcehit(r) :
177     (*ofun[sp->so->otype].funp)(sp->so, r)) {
178     if (sp->sa.success >= 0)
179     sp->sa.success++;
180     raycont(r); /* compute contribution */
181     return;
182 greg 1.1 }
183 greg 1.35 if (sp->sa.success < 0)
184     return; /* bitched already */
185     sp->sa.success -= AIMREQT;
186     if (sp->sa.success >= 0)
187     return; /* leniency */
188     sprintf(errmsg, "aiming failure for light source \"%s\"",
189     sp->so->oname);
190     error(WARNING, errmsg); /* issue warning */
191 greg 1.1 }
192    
193    
194 greg 1.4 static int
195     cntcmp(sc1, sc2) /* contribution compare (descending) */
196 greg 1.9 register CNTPTR *sc1, *sc2;
197 greg 1.4 {
198     if (sc1->brt > sc2->brt)
199     return(-1);
200     if (sc1->brt < sc2->brt)
201     return(1);
202     return(0);
203     }
204    
205    
206     direct(r, f, p) /* add direct component */
207     RAY *r; /* ray that hit surface */
208     int (*f)(); /* direct component coefficient function */
209     char *p; /* data for f */
210     {
211 greg 1.42 extern int (*trace)();
212 greg 1.12 extern double pow();
213 greg 1.4 register int sn;
214 greg 1.45 SRCINDEX si;
215 greg 1.12 int nshadcheck, ncnts;
216 greg 1.29 int nhits;
217 greg 1.45 double prob, ourthresh, hwt;
218 greg 1.4 RAY sr;
219 greg 1.25 /* NOTE: srccnt and cntord global so no recursion */
220 greg 1.22 if (nsources <= 0)
221 greg 1.25 return; /* no sources?! */
222 greg 1.4 /* potential contributions */
223 greg 1.45 initsrcindex(&si);
224     for (sn = 0; srcray(&sr, r, &si); sn++) {
225     if (sn >= maxcntr) {
226     maxcntr = sn + MAXSPART;
227     srccnt = (CONTRIB *)realloc((char *)srccnt,
228     maxcntr*sizeof(CONTRIB));
229     cntord = (CNTPTR *)realloc((char *)cntord,
230     maxcntr*sizeof(CNTPTR));
231     if (srccnt == NULL || cntord == NULL)
232     error(SYSTEM, "out of memory in direct");
233     }
234     cntord[sn].sndx = sn;
235 greg 1.9 cntord[sn].brt = 0.0;
236 greg 1.4 /* compute coefficient */
237 greg 1.45 (*f)(srccnt[sn].coef, p, srccnt[sn].dir, si.dom);
238 greg 1.34 cntord[sn].brt = bright(srccnt[sn].coef);
239 greg 1.15 if (cntord[sn].brt <= 0.0)
240 greg 1.4 continue;
241 greg 1.45 VCOPY(srccnt[sn].dir, sr.rdir);
242 greg 1.35 /* compute potential */
243     sr.revf = srcvalue;
244     rayvalue(&sr);
245 greg 1.34 copycolor(srccnt[sn].val, sr.rcol);
246     multcolor(srccnt[sn].val, srccnt[sn].coef);
247 greg 1.9 cntord[sn].brt = bright(srccnt[sn].val);
248 greg 1.4 }
249     /* sort contributions */
250 greg 1.45 qsort(cntord, sn, sizeof(CNTPTR), cntcmp);
251 greg 1.13 { /* find last */
252     register int l, m;
253    
254 greg 1.45 ncnts = l = sn;
255     sn = 0;
256 greg 1.13 while ((m = (sn + ncnts) >> 1) != l) {
257     if (cntord[m].brt > 0.0)
258     sn = m;
259     else
260     ncnts = m;
261     l = m;
262     }
263     }
264 greg 1.12 /* accumulate tail */
265     for (sn = ncnts-1; sn > 0; sn--)
266     cntord[sn-1].brt += cntord[sn].brt;
267 greg 1.45 /* compute number to check */
268     nshadcheck = pow((double)ncnts, shadcert) + .5;
269     /* modify threshold */
270     ourthresh = shadthresh / r->rweight;
271 greg 1.10 /* test for shadows */
272 greg 1.29 nhits = 0;
273 greg 1.12 for (sn = 0; sn < ncnts; sn++) {
274 greg 1.10 /* check threshold */
275 greg 1.12 if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
276 greg 1.27 cntord[sn].brt-cntord[sn+nshadcheck].brt)
277     < ourthresh*bright(r->rcol))
278 greg 1.4 break;
279     /* test for hit */
280     rayorigin(&sr, r, SHADOW, 1.0);
281 greg 1.45 VCOPY(sr.rdir, srccnt[cntord[sn].sndx].dir);
282     sr.rsrc = srccnt[cntord[sn].sndx].sno;
283     source[sr.rsrc].ntests++; /* keep statistics */
284 greg 1.4 if (localhit(&sr, &thescene) &&
285 greg 1.45 ( sr.ro != source[sr.rsrc].so ||
286     source[sr.rsrc].sflags & SFOLLOW )) {
287 greg 1.33 /* follow entire path */
288 greg 1.19 raycont(&sr);
289 greg 1.42 if (trace != NULL)
290     (*trace)(&sr); /* trace execution */
291 greg 1.5 if (bright(sr.rcol) <= FTINY)
292 greg 1.4 continue; /* missed! */
293 greg 1.45 copycolor(srccnt[cntord[sn].sndx].val, sr.rcol);
294     multcolor(srccnt[cntord[sn].sndx].val,
295     srccnt[cntord[sn].sndx].coef);
296 greg 1.4 }
297     /* add contribution if hit */
298 greg 1.45 addcolor(r->rcol, srccnt[cntord[sn].sndx].val);
299 greg 1.29 nhits++;
300 greg 1.45 source[sr.rsrc].nhits++;
301 greg 1.4 }
302 greg 1.29 /* surface hit rate */
303     if (sn > 0)
304     hwt = (double)nhits / (double)sn;
305     else
306     hwt = 0.5;
307 greg 1.20 #ifdef DEBUG
308 greg 1.12 sprintf(errmsg, "%d tested, %d untested, %f hit rate\n",
309     sn, ncnts-sn, hwt);
310     eputs(errmsg);
311 greg 1.4 #endif
312     /* add in untested sources */
313 greg 1.12 for ( ; sn < ncnts; sn++) {
314 greg 1.45 sr.rsrc = srccnt[cntord[sn].sndx].sno;
315     prob = hwt * (double)source[sr.rsrc].nhits /
316     (double)source[sr.rsrc].ntests;
317     scalecolor(srccnt[cntord[sn].sndx].val, prob);
318     addcolor(r->rcol, srccnt[cntord[sn].sndx].val);
319 greg 1.1 }
320     }