ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.33
Committed: Wed Jun 19 16:36:44 1991 UTC (32 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.32: +93 -59 lines
Log Message:
added virtual sources

File Contents

# User Rev Content
1 greg 1.25 /* Copyright (c) 1990 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 "source.h"
18    
19     #include "otypes.h"
20    
21     #include "cone.h"
22    
23     #include "face.h"
24    
25     #include "random.h"
26    
27    
28     extern double dstrsrc; /* source distribution amount */
29 greg 1.4 extern double shadthresh; /* relative shadow threshold */
30 greg 1.12 extern double shadcert; /* shadow testing certainty */
31 greg 1.1
32 greg 1.4 SRCREC *source = NULL; /* our list of sources */
33 greg 1.1 int nsources = 0; /* the number of sources */
34    
35 greg 1.25 static CONTRIB *srccnt; /* source contributions in direct() */
36     static CNTPTR *cntord; /* source ordering in direct() */
37 greg 1.1
38 greg 1.25
39 greg 1.1 marksources() /* find and mark source objects */
40     {
41 greg 1.33 int i;
42 greg 1.1 register OBJREC *o, *m;
43 greg 1.33 register SRCREC *ns;
44 greg 1.1
45     for (i = 0; i < nobjects; i++) {
46    
47     o = objptr(i);
48    
49     if (o->omod == OVOID)
50     continue;
51    
52     m = objptr(o->omod);
53    
54 greg 1.24 if (!islight(m->otype))
55 greg 1.1 continue;
56    
57 greg 1.6 if (m->oargs.nfargs != (m->otype == MAT_GLOW ? 4 :
58     m->otype == MAT_SPOT ? 7 : 3))
59 greg 1.1 objerror(m, USER, "bad # arguments");
60    
61 greg 1.6 if (m->otype == MAT_GLOW &&
62     o->otype != OBJ_SOURCE &&
63     m->oargs.farg[3] <= FTINY)
64 greg 1.1 continue; /* don't bother */
65    
66 greg 1.33 if ((ns = newsource()) == NULL)
67 greg 1.25 goto memerr;
68 greg 1.1
69 greg 1.33 setsource(ns, o);
70 greg 1.1
71 greg 1.6 if (m->otype == MAT_GLOW) {
72 greg 1.33 ns->sflags |= SPROX;
73     ns->sl.prox = m->oargs.farg[3];
74 greg 1.6 if (o->otype == OBJ_SOURCE)
75 greg 1.33 ns->sflags |= SSKIP;
76 greg 1.6 } else if (m->otype == MAT_SPOT) {
77 greg 1.33 ns->sflags |= SSPOT;
78     if ((ns->sl.s = makespot(m)) == NULL)
79     goto memerr;
80 greg 1.6 }
81 greg 1.1 }
82 greg 1.25 if (nsources <= 0) {
83     error(WARNING, "no light sources found");
84     return;
85     }
86 greg 1.33 markvirtuals(); /* find and add virtual sources */
87 greg 1.25 srccnt = (CONTRIB *)malloc(nsources*sizeof(CONTRIB));
88     cntord = (CNTPTR *)malloc(nsources*sizeof(CNTPTR));
89     if (srccnt != NULL && cntord != NULL)
90 greg 1.33 goto memerr;
91     return;
92 greg 1.25 memerr:
93     error(SYSTEM, "out of memory in marksources");
94 greg 1.1 }
95    
96    
97 greg 1.33 SRCREC *
98     newsource() /* allocate new source in our array */
99     {
100     if (nsources == 0)
101     source = (SRCREC *)malloc(sizeof(SRCREC));
102     else
103     source = (SRCREC *)realloc((char *)source,
104     (unsigned)(nsources+1)*sizeof(SRCREC));
105     if (source == NULL)
106     return(NULL);
107     source[nsources].sflags = 0;
108     source[nsources].nhits = 1;
109     source[nsources].ntests = 2; /* initial hit probability = 1/2 */
110     return(&source[nsources++]);
111     }
112    
113    
114     setsource(src, so) /* add a source to the array */
115 greg 1.4 register SRCREC *src;
116 greg 1.1 register OBJREC *so;
117     {
118     double cos(), tan(), sqrt();
119     double theta;
120     FACE *f;
121     CONE *co;
122     int j;
123     register int i;
124    
125 greg 1.33 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
126 greg 1.1 src->so = so;
127    
128     switch (so->otype) {
129     case OBJ_SOURCE:
130     if (so->oargs.nfargs != 4)
131     objerror(so, USER, "bad arguments");
132     src->sflags |= SDISTANT;
133     VCOPY(src->sloc, so->oargs.farg);
134     if (normalize(src->sloc) == 0.0)
135     objerror(so, USER, "zero direction");
136     theta = PI/180.0/2.0 * so->oargs.farg[3];
137     if (theta <= FTINY)
138     objerror(so, USER, "zero size");
139     src->ss = theta >= PI/4 ? 1.0 : tan(theta);
140     src->ss2 = 2.0*PI * (1.0 - cos(theta));
141     break;
142     case OBJ_SPHERE:
143     VCOPY(src->sloc, so->oargs.farg);
144     src->ss = so->oargs.farg[3];
145     src->ss2 = PI * src->ss * src->ss;
146     break;
147     case OBJ_FACE:
148     /* get the face */
149     f = getface(so);
150     /* find the center */
151     for (j = 0; j < 3; j++) {
152     src->sloc[j] = 0.0;
153     for (i = 0; i < f->nv; i++)
154     src->sloc[j] += VERTEX(f,i)[j];
155 greg 1.33 src->sloc[j] /= (double)f->nv;
156 greg 1.1 }
157     if (!inface(src->sloc, f))
158     objerror(so, USER, "cannot hit center");
159 greg 1.33 src->sflags |= SFLAT;
160     VCOPY(src->snorm, f->norm);
161 greg 1.1 src->ss = sqrt(f->area / PI);
162     src->ss2 = f->area;
163     break;
164     case OBJ_RING:
165     /* get the ring */
166     co = getcone(so, 0);
167     VCOPY(src->sloc, CO_P0(co));
168     if (CO_R0(co) > 0.0)
169     objerror(so, USER, "cannot hit center");
170 greg 1.33 src->sflags |= SFLAT;
171     VCOPY(src->snorm, co->ad);
172 greg 1.1 src->ss = CO_R1(co);
173     src->ss2 = PI * src->ss * src->ss;
174     break;
175     default:
176     objerror(so, USER, "illegal material");
177     }
178     }
179    
180    
181 greg 1.6 SPOT *
182     makespot(m) /* make a spotlight */
183     register OBJREC *m;
184     {
185     extern double cos();
186     register SPOT *ns;
187    
188     if ((ns = (SPOT *)malloc(sizeof(SPOT))) == NULL)
189 greg 1.33 return(NULL);
190 greg 1.6 ns->siz = 2.0*PI * (1.0 - cos(PI/180.0/2.0 * m->oargs.farg[3]));
191     VCOPY(ns->aim, m->oargs.farg+4);
192     if ((ns->flen = normalize(ns->aim)) == 0.0)
193     objerror(m, USER, "zero focus vector");
194     return(ns);
195     }
196    
197    
198 greg 1.1 double
199     srcray(sr, r, sn) /* send a ray to a source, return domega */
200     register RAY *sr; /* returned source ray */
201     RAY *r; /* ray which hit object */
202     register int sn; /* source number */
203     {
204     double ddot; /* (distance times) cosine */
205     FVECT vd;
206     double d;
207     register int i;
208    
209 greg 1.4 if (source[sn].sflags & SSKIP)
210 greg 1.1 return(0.0); /* skip this source */
211    
212     rayorigin(sr, r, SHADOW, 1.0); /* ignore limits */
213    
214     sr->rsrc = sn; /* remember source */
215     /* get source direction */
216 greg 1.33 if (source[sn].sflags & SDISTANT) {
217     if (source[sn].sflags & SSPOT) { /* check location */
218     for (i = 0; i < 3; i++)
219     vd[i] = sr->rorg[i] - source[sn].sl.s->aim[i];
220     d = DOT(source[sn].sloc,vd);
221     d = DOT(vd,vd) - d*d;
222     if (PI*d > source[sn].sl.s->siz)
223     return(0.0);
224     }
225 greg 1.1 /* constant direction */
226 greg 1.4 VCOPY(sr->rdir, source[sn].sloc);
227 greg 1.33 } else { /* compute direction */
228 greg 1.1 for (i = 0; i < 3; i++)
229 greg 1.4 sr->rdir[i] = source[sn].sloc[i] - sr->rorg[i];
230 greg 1.1
231 greg 1.33 if (source[sn].sflags & SFLAT &&
232     (ddot = -DOT(sr->rdir, source[sn].snorm)) <= FTINY)
233 greg 1.1 return(0.0); /* behind surface! */
234     }
235     if (dstrsrc > FTINY) {
236     /* distribute source direction */
237 greg 1.31 dimlist[ndims++] = sn;
238     for (i = 0; i < 3; i++) {
239     dimlist[ndims] = i + 8831;
240     vd[i] = dstrsrc * source[sn].ss *
241     (1.0 - 2.0*urand(ilhash(dimlist,ndims+1)+samplendx));
242     }
243     ndims--;
244 greg 1.33 if (source[sn].sflags & SFLAT) { /* project offset */
245     d = DOT(vd, source[sn].snorm);
246 greg 1.1 for (i = 0; i < 3; i++)
247 greg 1.33 vd[i] -= d * source[sn].snorm[i];
248 greg 1.1 }
249     for (i = 0; i < 3; i++) /* offset source direction */
250     sr->rdir[i] += vd[i];
251    
252 greg 1.4 } else if (source[sn].sflags & SDISTANT)
253 greg 1.1 /* already normalized */
254 greg 1.4 return(source[sn].ss2);
255 greg 1.1
256     if ((d = normalize(sr->rdir)) == 0.0)
257     /* at source! */
258     return(0.0);
259    
260 greg 1.4 if (source[sn].sflags & SDISTANT)
261 greg 1.1 /* domega constant */
262 greg 1.4 return(source[sn].ss2);
263 greg 1.1
264 greg 1.6 /* check proximity */
265 greg 1.27 if (source[sn].sflags & SPROX &&
266     d > source[sn].sl.prox)
267     return(0.0);
268     /* compute dot product */
269 greg 1.33 if (source[sn].sflags & SFLAT)
270 greg 1.27 ddot /= d;
271     else
272     ddot = 1.0;
273 greg 1.6 /* check angle */
274 greg 1.27 if (source[sn].sflags & SSPOT) {
275     if (source[sn].sl.s->siz < 2.0*PI *
276 greg 1.6 (1.0 + DOT(source[sn].sl.s->aim,sr->rdir)))
277 greg 1.27 return(0.0);
278     d += source[sn].sl.s->flen; /* adjust length */
279 greg 1.1 }
280 greg 1.27 /* compute domega */
281     return(ddot*source[sn].ss2/(d*d));
282 greg 1.1 }
283    
284    
285     sourcehit(r) /* check to see if ray hit distant source */
286     register RAY *r;
287     {
288     int first, last;
289     register int i;
290    
291     if (r->rsrc >= 0) { /* check only one if aimed */
292     first = last = r->rsrc;
293     } else { /* otherwise check all */
294     first = 0; last = nsources-1;
295     }
296     for (i = first; i <= last; i++)
297 greg 1.4 if (source[i].sflags & SDISTANT)
298 greg 1.1 /*
299     * Check to see if ray is within
300     * solid angle of source.
301     */
302 greg 1.4 if (2.0*PI * (1.0 - DOT(source[i].sloc,r->rdir))
303     <= source[i].ss2) {
304     r->ro = source[i].so;
305     if (!(source[i].sflags & SSKIP))
306 greg 1.1 break;
307     }
308    
309     if (r->ro != NULL) {
310     for (i = 0; i < 3; i++)
311     r->ron[i] = -r->rdir[i];
312     r->rod = 1.0;
313 greg 1.26 r->rox = NULL;
314 greg 1.1 return(1);
315     }
316     return(0);
317     }
318    
319    
320 greg 1.4 static int
321     cntcmp(sc1, sc2) /* contribution compare (descending) */
322 greg 1.9 register CNTPTR *sc1, *sc2;
323 greg 1.4 {
324     if (sc1->brt > sc2->brt)
325     return(-1);
326     if (sc1->brt < sc2->brt)
327     return(1);
328     return(0);
329     }
330    
331    
332     direct(r, f, p) /* add direct component */
333     RAY *r; /* ray that hit surface */
334     int (*f)(); /* direct component coefficient function */
335     char *p; /* data for f */
336     {
337 greg 1.12 extern double pow();
338 greg 1.4 register int sn;
339 greg 1.12 int nshadcheck, ncnts;
340 greg 1.29 int nhits;
341     double prob, ourthresh, hwt;
342 greg 1.4 RAY sr;
343 greg 1.25 /* NOTE: srccnt and cntord global so no recursion */
344 greg 1.22 if (nsources <= 0)
345 greg 1.25 return; /* no sources?! */
346 greg 1.12 /* compute number to check */
347     nshadcheck = pow((double)nsources, shadcert) + .5;
348 greg 1.8 /* modify threshold */
349     ourthresh = shadthresh / r->rweight;
350 greg 1.4 /* potential contributions */
351     for (sn = 0; sn < nsources; sn++) {
352 greg 1.9 cntord[sn].sno = sn;
353     cntord[sn].brt = 0.0;
354 greg 1.4 /* get source ray */
355     if ((srccnt[sn].dom = srcray(&sr, r, sn)) == 0.0)
356     continue;
357     VCOPY(srccnt[sn].dir, sr.rdir);
358     /* compute coefficient */
359     (*f)(srccnt[sn].val, p, srccnt[sn].dir, srccnt[sn].dom);
360 greg 1.9 cntord[sn].brt = bright(srccnt[sn].val);
361 greg 1.15 if (cntord[sn].brt <= 0.0)
362 greg 1.4 continue;
363     /* compute contribution */
364 greg 1.33 srcvalue(&sr);
365 greg 1.4 multcolor(srccnt[sn].val, sr.rcol);
366 greg 1.9 cntord[sn].brt = bright(srccnt[sn].val);
367 greg 1.4 }
368     /* sort contributions */
369 greg 1.9 qsort(cntord, nsources, sizeof(CNTPTR), cntcmp);
370 greg 1.13 { /* find last */
371     register int l, m;
372    
373     sn = 0; ncnts = l = nsources;
374     while ((m = (sn + ncnts) >> 1) != l) {
375     if (cntord[m].brt > 0.0)
376     sn = m;
377     else
378     ncnts = m;
379     l = m;
380     }
381     }
382 greg 1.12 /* accumulate tail */
383     for (sn = ncnts-1; sn > 0; sn--)
384     cntord[sn-1].brt += cntord[sn].brt;
385 greg 1.10 /* test for shadows */
386 greg 1.29 nhits = 0;
387 greg 1.12 for (sn = 0; sn < ncnts; sn++) {
388 greg 1.10 /* check threshold */
389 greg 1.12 if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
390 greg 1.27 cntord[sn].brt-cntord[sn+nshadcheck].brt)
391     < ourthresh*bright(r->rcol))
392 greg 1.4 break;
393     /* get statistics */
394 greg 1.9 source[cntord[sn].sno].ntests++;
395 greg 1.4 /* test for hit */
396     rayorigin(&sr, r, SHADOW, 1.0);
397 greg 1.9 VCOPY(sr.rdir, srccnt[cntord[sn].sno].dir);
398 greg 1.19 sr.rsrc = cntord[sn].sno;
399 greg 1.4 if (localhit(&sr, &thescene) &&
400 greg 1.33 ( sr.ro != source[cntord[sn].sno].so ||
401     source[cntord[sn].sno].sflags & SFOLLOW )) {
402     /* follow entire path */
403 greg 1.19 raycont(&sr);
404 greg 1.5 if (bright(sr.rcol) <= FTINY)
405 greg 1.4 continue; /* missed! */
406 greg 1.9 (*f)(srccnt[cntord[sn].sno].val, p,
407     srccnt[cntord[sn].sno].dir,
408     srccnt[cntord[sn].sno].dom);
409     multcolor(srccnt[cntord[sn].sno].val, sr.rcol);
410 greg 1.4 }
411     /* add contribution if hit */
412 greg 1.9 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
413 greg 1.29 nhits++;
414 greg 1.9 source[cntord[sn].sno].nhits++;
415 greg 1.4 }
416 greg 1.29 /* surface hit rate */
417     if (sn > 0)
418     hwt = (double)nhits / (double)sn;
419     else
420     hwt = 0.5;
421 greg 1.20 #ifdef DEBUG
422 greg 1.12 sprintf(errmsg, "%d tested, %d untested, %f hit rate\n",
423     sn, ncnts-sn, hwt);
424     eputs(errmsg);
425 greg 1.4 #endif
426     /* add in untested sources */
427 greg 1.12 for ( ; sn < ncnts; sn++) {
428 greg 1.9 prob = hwt * (double)source[cntord[sn].sno].nhits /
429     (double)source[cntord[sn].sno].ntests;
430     scalecolor(srccnt[cntord[sn].sno].val, prob);
431     addcolor(r->rcol, srccnt[cntord[sn].sno].val);
432 greg 1.4 }
433     }
434    
435    
436 greg 1.33 srcvalue(r) /* punch ray to source and compute value */
437     RAY *r;
438     {
439     register SRCREC *sp;
440    
441     sp = &source[r->rsrc];
442     if (sp->sflags & SVIRTUAL) { /* virtual source */
443     RAY nr;
444     /* check intersection */
445     if (!(*ofun[sp->so->otype].funp)(sp->so, r))
446     return;
447     /* relay ray to source */
448     vsrcrelay(&nr, r);
449     srcvalue(&nr);
450     return;
451     }
452     /* compute intersection */
453     if (sp->sflags & SDISTANT ? sourcehit(r) :
454     (*ofun[sp->so->otype].funp)(sp->so, r)) {
455     if (sp->sa.success >= 0)
456     sp->sa.success++;
457     raycont(r); /* compute contribution */
458     return;
459     }
460     if (sp->sa.success < 0)
461     return; /* bitched already */
462     sp->sa.success -= AIMREQT;
463     if (sp->sa.success >= 0)
464     return; /* leniency */
465     sprintf(errmsg, "aiming failure for light source \"%s\"",
466     sp->so->oname);
467     error(WARNING, errmsg); /* issue warning */
468     }
469    
470    
471 greg 1.1 #define wrongsource(m, r) (m->otype!=MAT_ILLUM && \
472     r->rsrc>=0 && \
473 greg 1.4 source[r->rsrc].so!=r->ro)
474 greg 1.1
475     #define badambient(m, r) ((r->crtype&(AMBIENT|SHADOW))==AMBIENT && \
476 greg 1.6 !(m->otype==MAT_GLOW&&r->rot>m->oargs.farg[3]))
477 greg 1.1
478     #define passillum(m, r) (m->otype==MAT_ILLUM && \
479 greg 1.4 !(r->rsrc>=0&&source[r->rsrc].so==r->ro))
480 greg 1.1
481    
482     m_light(m, r) /* ray hit a light source */
483     register OBJREC *m;
484     register RAY *r;
485     {
486     /* check for over-counting */
487     if (wrongsource(m, r) || badambient(m, r))
488     return;
489     /* check for passed illum */
490     if (passillum(m, r)) {
491    
492     if (m->oargs.nsargs < 1 || !strcmp(m->oargs.sarg[0], VOIDID))
493     raytrans(r);
494     else
495     rayshade(r, modifier(m->oargs.sarg[0]));
496    
497     /* otherwise treat as source */
498     } else {
499 greg 1.16 /* check for behind */
500     if (r->rod < 0.0)
501     return;
502 greg 1.1 /* get distribution pattern */
503     raytexture(r, m->omod);
504     /* get source color */
505     setcolor(r->rcol, m->oargs.farg[0],
506     m->oargs.farg[1],
507     m->oargs.farg[2]);
508     /* modify value */
509     multcolor(r->rcol, r->pcol);
510     }
511     }