ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.41
Committed: Tue Aug 6 14:07:03 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.40: +3 -1 lines
Log Message:
fixed bugs in virtual sources through prisms

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 "otypes.h"
18    
19 greg 1.35 #include "source.h"
20 greg 1.1
21     #include "random.h"
22    
23 greg 1.35 /*
24     * Structures used by direct()
25     */
26 greg 1.1
27 greg 1.35 typedef struct {
28     FVECT dir; /* source direction */
29     COLOR coef; /* material coefficient */
30     COLOR val; /* contribution */
31     } CONTRIB; /* direct contribution */
32 greg 1.1
33 greg 1.35 typedef struct {
34     int sno; /* source number */
35     float brt; /* brightness (for comparison) */
36     } CNTPTR; /* contribution pointer */
37 greg 1.1
38 greg 1.25 static CONTRIB *srccnt; /* source contributions in direct() */
39     static CNTPTR *cntord; /* source ordering in direct() */
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.25 srccnt = (CONTRIB *)malloc(nsources*sizeof(CONTRIB));
103     cntord = (CNTPTR *)malloc(nsources*sizeof(CNTPTR));
104 greg 1.36 if (srccnt == NULL || cntord == NULL)
105 greg 1.33 goto memerr;
106     return;
107 greg 1.25 memerr:
108     error(SYSTEM, "out of memory in marksources");
109 greg 1.1 }
110    
111    
112     double
113     srcray(sr, r, sn) /* send a ray to a source, return domega */
114     register RAY *sr; /* returned source ray */
115     RAY *r; /* ray which hit object */
116     register int sn; /* source number */
117     {
118     double ddot; /* (distance times) cosine */
119     FVECT vd;
120     double d;
121     register int i;
122    
123 greg 1.4 if (source[sn].sflags & SSKIP)
124 greg 1.1 return(0.0); /* skip this source */
125    
126     rayorigin(sr, r, SHADOW, 1.0); /* ignore limits */
127    
128     sr->rsrc = sn; /* remember source */
129     /* get source direction */
130 greg 1.33 if (source[sn].sflags & SDISTANT) {
131 greg 1.1 /* constant direction */
132 greg 1.4 VCOPY(sr->rdir, source[sn].sloc);
133 greg 1.33 } else { /* compute direction */
134 greg 1.1 for (i = 0; i < 3; i++)
135 greg 1.4 sr->rdir[i] = source[sn].sloc[i] - sr->rorg[i];
136 greg 1.1
137 greg 1.33 if (source[sn].sflags & SFLAT &&
138     (ddot = -DOT(sr->rdir, source[sn].snorm)) <= FTINY)
139 greg 1.1 return(0.0); /* behind surface! */
140     }
141     if (dstrsrc > FTINY) {
142     /* distribute source direction */
143 greg 1.31 dimlist[ndims++] = sn;
144     for (i = 0; i < 3; i++) {
145     dimlist[ndims] = i + 8831;
146     vd[i] = dstrsrc * source[sn].ss *
147 greg 1.39 (1.0 - 2.0*urand(urind(ilhash(dimlist,ndims+1),samplendx)));
148 greg 1.31 }
149     ndims--;
150 greg 1.33 if (source[sn].sflags & SFLAT) { /* project offset */
151     d = DOT(vd, source[sn].snorm);
152 greg 1.1 for (i = 0; i < 3; i++)
153 greg 1.33 vd[i] -= d * source[sn].snorm[i];
154 greg 1.1 }
155     for (i = 0; i < 3; i++) /* offset source direction */
156     sr->rdir[i] += vd[i];
157 greg 1.40 /* normalize */
158     d = normalize(sr->rdir);
159 greg 1.1
160 greg 1.40 } else if (!(source[sn].sflags & SDISTANT))
161     /* normalize direction */
162     d = normalize(sr->rdir);
163 greg 1.1
164 greg 1.40 if (source[sn].sflags & SDISTANT) {
165     if (source[sn].sflags & SSPOT) { /* check location */
166     for (i = 0; i < 3; i++)
167 greg 1.41 vd[i] = source[sn].sl.s->aim[i] - sr->rorg[i];
168 greg 1.40 d = DOT(sr->rdir,vd);
169 greg 1.41 if (d <= FTINY)
170     return(0.0);
171 greg 1.40 d = DOT(vd,vd) - d*d;
172     if (PI*d > source[sn].sl.s->siz)
173     return(0.0);
174     }
175     return(source[sn].ss2); /* domega constant */
176     }
177     /* check direction */
178     if (d == 0.0)
179 greg 1.1 return(0.0);
180 greg 1.6 /* check proximity */
181 greg 1.27 if (source[sn].sflags & SPROX &&
182     d > source[sn].sl.prox)
183     return(0.0);
184     /* compute dot product */
185 greg 1.33 if (source[sn].sflags & SFLAT)
186 greg 1.27 ddot /= d;
187     else
188     ddot = 1.0;
189 greg 1.6 /* check angle */
190 greg 1.27 if (source[sn].sflags & SSPOT) {
191     if (source[sn].sl.s->siz < 2.0*PI *
192 greg 1.6 (1.0 + DOT(source[sn].sl.s->aim,sr->rdir)))
193 greg 1.27 return(0.0);
194     d += source[sn].sl.s->flen; /* adjust length */
195 greg 1.1 }
196 greg 1.27 /* compute domega */
197     return(ddot*source[sn].ss2/(d*d));
198 greg 1.1 }
199    
200    
201 greg 1.35 srcvalue(r) /* punch ray to source and compute value */
202     RAY *r;
203 greg 1.1 {
204 greg 1.35 register SRCREC *sp;
205 greg 1.1
206 greg 1.35 sp = &source[r->rsrc];
207     if (sp->sflags & SVIRTUAL) { /* virtual source */
208     /* check intersection */
209     if (!(*ofun[sp->so->otype].funp)(sp->so, r))
210     return;
211     raycont(r); /* compute contribution */
212     return;
213 greg 1.1 }
214 greg 1.35 /* compute intersection */
215     if (sp->sflags & SDISTANT ? sourcehit(r) :
216     (*ofun[sp->so->otype].funp)(sp->so, r)) {
217     if (sp->sa.success >= 0)
218     sp->sa.success++;
219     raycont(r); /* compute contribution */
220     return;
221 greg 1.1 }
222 greg 1.35 if (sp->sa.success < 0)
223     return; /* bitched already */
224     sp->sa.success -= AIMREQT;
225     if (sp->sa.success >= 0)
226     return; /* leniency */
227     sprintf(errmsg, "aiming failure for light source \"%s\"",
228     sp->so->oname);
229     error(WARNING, errmsg); /* issue warning */
230 greg 1.1 }
231    
232    
233 greg 1.4 static int
234     cntcmp(sc1, sc2) /* contribution compare (descending) */
235 greg 1.9 register CNTPTR *sc1, *sc2;
236 greg 1.4 {
237     if (sc1->brt > sc2->brt)
238     return(-1);
239     if (sc1->brt < sc2->brt)
240     return(1);
241     return(0);
242     }
243    
244    
245     direct(r, f, p) /* add direct component */
246     RAY *r; /* ray that hit surface */
247     int (*f)(); /* direct component coefficient function */
248     char *p; /* data for f */
249     {
250 greg 1.12 extern double pow();
251 greg 1.4 register int sn;
252 greg 1.12 int nshadcheck, ncnts;
253 greg 1.29 int nhits;
254 greg 1.34 double dom, prob, ourthresh, hwt;
255 greg 1.4 RAY sr;
256 greg 1.25 /* NOTE: srccnt and cntord global so no recursion */
257 greg 1.22 if (nsources <= 0)
258 greg 1.25 return; /* no sources?! */
259 greg 1.12 /* compute number to check */
260     nshadcheck = pow((double)nsources, shadcert) + .5;
261 greg 1.8 /* modify threshold */
262     ourthresh = shadthresh / r->rweight;
263 greg 1.4 /* potential contributions */
264     for (sn = 0; sn < nsources; sn++) {
265 greg 1.9 cntord[sn].sno = sn;
266     cntord[sn].brt = 0.0;
267 greg 1.4 /* get source ray */
268 greg 1.34 if ((dom = srcray(&sr, r, sn)) == 0.0)
269 greg 1.4 continue;
270     VCOPY(srccnt[sn].dir, sr.rdir);
271     /* compute coefficient */
272 greg 1.34 (*f)(srccnt[sn].coef, p, srccnt[sn].dir, dom);
273     cntord[sn].brt = bright(srccnt[sn].coef);
274 greg 1.15 if (cntord[sn].brt <= 0.0)
275 greg 1.4 continue;
276 greg 1.35 /* compute potential */
277     sr.revf = srcvalue;
278     rayvalue(&sr);
279 greg 1.34 copycolor(srccnt[sn].val, sr.rcol);
280     multcolor(srccnt[sn].val, srccnt[sn].coef);
281 greg 1.9 cntord[sn].brt = bright(srccnt[sn].val);
282 greg 1.4 }
283     /* sort contributions */
284 greg 1.9 qsort(cntord, nsources, sizeof(CNTPTR), cntcmp);
285 greg 1.13 { /* find last */
286     register int l, m;
287    
288     sn = 0; ncnts = l = nsources;
289     while ((m = (sn + ncnts) >> 1) != l) {
290     if (cntord[m].brt > 0.0)
291     sn = m;
292     else
293     ncnts = m;
294     l = m;
295     }
296     }
297 greg 1.12 /* accumulate tail */
298     for (sn = ncnts-1; sn > 0; sn--)
299     cntord[sn-1].brt += cntord[sn].brt;
300 greg 1.10 /* test for shadows */
301 greg 1.29 nhits = 0;
302 greg 1.12 for (sn = 0; sn < ncnts; sn++) {
303 greg 1.10 /* check threshold */
304 greg 1.12 if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
305 greg 1.27 cntord[sn].brt-cntord[sn+nshadcheck].brt)
306     < ourthresh*bright(r->rcol))
307 greg 1.4 break;
308     /* get statistics */
309 greg 1.9 source[cntord[sn].sno].ntests++;
310 greg 1.4 /* test for hit */
311     rayorigin(&sr, r, SHADOW, 1.0);
312 greg 1.9 VCOPY(sr.rdir, srccnt[cntord[sn].sno].dir);
313 greg 1.19 sr.rsrc = cntord[sn].sno;
314 greg 1.4 if (localhit(&sr, &thescene) &&
315 greg 1.33 ( sr.ro != source[cntord[sn].sno].so ||
316     source[cntord[sn].sno].sflags & SFOLLOW )) {
317     /* follow entire path */
318 greg 1.19 raycont(&sr);
319 greg 1.5 if (bright(sr.rcol) <= FTINY)
320 greg 1.4 continue; /* missed! */
321 greg 1.34 copycolor(srccnt[cntord[sn].sno].val, sr.rcol);
322     multcolor(srccnt[cntord[sn].sno].val,
323     srccnt[cntord[sn].sno].coef);
324 greg 1.4 }
325     /* add contribution if hit */
326 greg 1.9 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
327 greg 1.29 nhits++;
328 greg 1.9 source[cntord[sn].sno].nhits++;
329 greg 1.4 }
330 greg 1.29 /* surface hit rate */
331     if (sn > 0)
332     hwt = (double)nhits / (double)sn;
333     else
334     hwt = 0.5;
335 greg 1.20 #ifdef DEBUG
336 greg 1.12 sprintf(errmsg, "%d tested, %d untested, %f hit rate\n",
337     sn, ncnts-sn, hwt);
338     eputs(errmsg);
339 greg 1.4 #endif
340     /* add in untested sources */
341 greg 1.12 for ( ; sn < ncnts; sn++) {
342 greg 1.9 prob = hwt * (double)source[cntord[sn].sno].nhits /
343     (double)source[cntord[sn].sno].ntests;
344     scalecolor(srccnt[cntord[sn].sno].val, prob);
345     addcolor(r->rcol, srccnt[cntord[sn].sno].val);
346 greg 1.1 }
347     }