ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.40
Committed: Tue Jul 30 18:23:41 1991 UTC (32 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.39: +18 -18 lines
Log Message:
fixed improper creation and testing of spots

File Contents

# Content
1 /* Copyright (c) 1990 Regents of the University of California */
2
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 #include "octree.h"
16
17 #include "otypes.h"
18
19 #include "source.h"
20
21 #include "random.h"
22
23 /*
24 * Structures used by direct()
25 */
26
27 typedef struct {
28 FVECT dir; /* source direction */
29 COLOR coef; /* material coefficient */
30 COLOR val; /* contribution */
31 } CONTRIB; /* direct contribution */
32
33 typedef struct {
34 int sno; /* source number */
35 float brt; /* brightness (for comparison) */
36 } CNTPTR; /* contribution pointer */
37
38 static CONTRIB *srccnt; /* source contributions in direct() */
39 static CNTPTR *cntord; /* source ordering in direct() */
40
41
42 marksources() /* find and mark source objects */
43 {
44 int i;
45 register OBJREC *o, *m;
46 register int ns;
47 /* initialize dispatch table */
48 initstypes();
49 /* find direct sources */
50 for (i = 0; i < nobjects; i++) {
51
52 o = objptr(i);
53
54 if (!issurface(o->otype) || o->omod == OVOID)
55 continue;
56
57 m = objptr(o->omod);
58
59 if (!islight(m->otype))
60 continue;
61
62 if (m->oargs.nfargs != (m->otype == MAT_GLOW ? 4 :
63 m->otype == MAT_SPOT ? 7 : 3))
64 objerror(m, USER, "bad # arguments");
65
66 if (m->otype == MAT_GLOW &&
67 o->otype != OBJ_SOURCE &&
68 m->oargs.farg[3] <= FTINY)
69 continue; /* don't bother */
70
71 if (sfun[o->otype].of == NULL ||
72 sfun[o->otype].of->setsrc == NULL)
73 objerror(o, USER, "illegal material");
74
75 if ((ns = newsource()) < 0)
76 goto memerr;
77
78 setsource(&source[ns], o);
79
80 if (m->otype == MAT_GLOW) {
81 source[ns].sflags |= SPROX;
82 source[ns].sl.prox = m->oargs.farg[3];
83 if (o->otype == OBJ_SOURCE)
84 source[ns].sflags |= SSKIP;
85 } else if (m->otype == MAT_SPOT) {
86 source[ns].sflags |= SSPOT;
87 if ((source[ns].sl.s = makespot(m)) == NULL)
88 goto memerr;
89 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 }
96 }
97 if (nsources <= 0) {
98 error(WARNING, "no light sources found");
99 return;
100 }
101 markvirtuals(); /* find and add virtual sources */
102 srccnt = (CONTRIB *)malloc(nsources*sizeof(CONTRIB));
103 cntord = (CNTPTR *)malloc(nsources*sizeof(CNTPTR));
104 if (srccnt == NULL || cntord == NULL)
105 goto memerr;
106 return;
107 memerr:
108 error(SYSTEM, "out of memory in marksources");
109 }
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 if (source[sn].sflags & SSKIP)
124 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 if (source[sn].sflags & SDISTANT) {
131 /* constant direction */
132 VCOPY(sr->rdir, source[sn].sloc);
133 } else { /* compute direction */
134 for (i = 0; i < 3; i++)
135 sr->rdir[i] = source[sn].sloc[i] - sr->rorg[i];
136
137 if (source[sn].sflags & SFLAT &&
138 (ddot = -DOT(sr->rdir, source[sn].snorm)) <= FTINY)
139 return(0.0); /* behind surface! */
140 }
141 if (dstrsrc > FTINY) {
142 /* distribute source direction */
143 dimlist[ndims++] = sn;
144 for (i = 0; i < 3; i++) {
145 dimlist[ndims] = i + 8831;
146 vd[i] = dstrsrc * source[sn].ss *
147 (1.0 - 2.0*urand(urind(ilhash(dimlist,ndims+1),samplendx)));
148 }
149 ndims--;
150 if (source[sn].sflags & SFLAT) { /* project offset */
151 d = DOT(vd, source[sn].snorm);
152 for (i = 0; i < 3; i++)
153 vd[i] -= d * source[sn].snorm[i];
154 }
155 for (i = 0; i < 3; i++) /* offset source direction */
156 sr->rdir[i] += vd[i];
157 /* normalize */
158 d = normalize(sr->rdir);
159
160 } else if (!(source[sn].sflags & SDISTANT))
161 /* normalize direction */
162 d = normalize(sr->rdir);
163
164 if (source[sn].sflags & SDISTANT) {
165 if (source[sn].sflags & SSPOT) { /* check location */
166 for (i = 0; i < 3; i++)
167 vd[i] = sr->rorg[i] - source[sn].sl.s->aim[i];
168 d = DOT(sr->rdir,vd);
169 d = DOT(vd,vd) - d*d;
170 if (PI*d > source[sn].sl.s->siz)
171 return(0.0);
172 }
173 return(source[sn].ss2); /* domega constant */
174 }
175 /* check direction */
176 if (d == 0.0)
177 return(0.0);
178 /* check proximity */
179 if (source[sn].sflags & SPROX &&
180 d > source[sn].sl.prox)
181 return(0.0);
182 /* compute dot product */
183 if (source[sn].sflags & SFLAT)
184 ddot /= d;
185 else
186 ddot = 1.0;
187 /* check angle */
188 if (source[sn].sflags & SSPOT) {
189 if (source[sn].sl.s->siz < 2.0*PI *
190 (1.0 + DOT(source[sn].sl.s->aim,sr->rdir)))
191 return(0.0);
192 d += source[sn].sl.s->flen; /* adjust length */
193 }
194 /* compute domega */
195 return(ddot*source[sn].ss2/(d*d));
196 }
197
198
199 srcvalue(r) /* punch ray to source and compute value */
200 RAY *r;
201 {
202 register SRCREC *sp;
203
204 sp = &source[r->rsrc];
205 if (sp->sflags & SVIRTUAL) { /* virtual source */
206 /* check intersection */
207 if (!(*ofun[sp->so->otype].funp)(sp->so, r))
208 return;
209 raycont(r); /* compute contribution */
210 return;
211 }
212 /* compute intersection */
213 if (sp->sflags & SDISTANT ? sourcehit(r) :
214 (*ofun[sp->so->otype].funp)(sp->so, r)) {
215 if (sp->sa.success >= 0)
216 sp->sa.success++;
217 raycont(r); /* compute contribution */
218 return;
219 }
220 if (sp->sa.success < 0)
221 return; /* bitched already */
222 sp->sa.success -= AIMREQT;
223 if (sp->sa.success >= 0)
224 return; /* leniency */
225 sprintf(errmsg, "aiming failure for light source \"%s\"",
226 sp->so->oname);
227 error(WARNING, errmsg); /* issue warning */
228 }
229
230
231 static int
232 cntcmp(sc1, sc2) /* contribution compare (descending) */
233 register CNTPTR *sc1, *sc2;
234 {
235 if (sc1->brt > sc2->brt)
236 return(-1);
237 if (sc1->brt < sc2->brt)
238 return(1);
239 return(0);
240 }
241
242
243 direct(r, f, p) /* add direct component */
244 RAY *r; /* ray that hit surface */
245 int (*f)(); /* direct component coefficient function */
246 char *p; /* data for f */
247 {
248 extern double pow();
249 register int sn;
250 int nshadcheck, ncnts;
251 int nhits;
252 double dom, prob, ourthresh, hwt;
253 RAY sr;
254 /* NOTE: srccnt and cntord global so no recursion */
255 if (nsources <= 0)
256 return; /* no sources?! */
257 /* compute number to check */
258 nshadcheck = pow((double)nsources, shadcert) + .5;
259 /* modify threshold */
260 ourthresh = shadthresh / r->rweight;
261 /* potential contributions */
262 for (sn = 0; sn < nsources; sn++) {
263 cntord[sn].sno = sn;
264 cntord[sn].brt = 0.0;
265 /* get source ray */
266 if ((dom = srcray(&sr, r, sn)) == 0.0)
267 continue;
268 VCOPY(srccnt[sn].dir, sr.rdir);
269 /* compute coefficient */
270 (*f)(srccnt[sn].coef, p, srccnt[sn].dir, dom);
271 cntord[sn].brt = bright(srccnt[sn].coef);
272 if (cntord[sn].brt <= 0.0)
273 continue;
274 /* compute potential */
275 sr.revf = srcvalue;
276 rayvalue(&sr);
277 copycolor(srccnt[sn].val, sr.rcol);
278 multcolor(srccnt[sn].val, srccnt[sn].coef);
279 cntord[sn].brt = bright(srccnt[sn].val);
280 }
281 /* sort contributions */
282 qsort(cntord, nsources, sizeof(CNTPTR), cntcmp);
283 { /* find last */
284 register int l, m;
285
286 sn = 0; ncnts = l = nsources;
287 while ((m = (sn + ncnts) >> 1) != l) {
288 if (cntord[m].brt > 0.0)
289 sn = m;
290 else
291 ncnts = m;
292 l = m;
293 }
294 }
295 /* accumulate tail */
296 for (sn = ncnts-1; sn > 0; sn--)
297 cntord[sn-1].brt += cntord[sn].brt;
298 /* test for shadows */
299 nhits = 0;
300 for (sn = 0; sn < ncnts; sn++) {
301 /* check threshold */
302 if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
303 cntord[sn].brt-cntord[sn+nshadcheck].brt)
304 < ourthresh*bright(r->rcol))
305 break;
306 /* get statistics */
307 source[cntord[sn].sno].ntests++;
308 /* test for hit */
309 rayorigin(&sr, r, SHADOW, 1.0);
310 VCOPY(sr.rdir, srccnt[cntord[sn].sno].dir);
311 sr.rsrc = cntord[sn].sno;
312 if (localhit(&sr, &thescene) &&
313 ( sr.ro != source[cntord[sn].sno].so ||
314 source[cntord[sn].sno].sflags & SFOLLOW )) {
315 /* follow entire path */
316 raycont(&sr);
317 if (bright(sr.rcol) <= FTINY)
318 continue; /* missed! */
319 copycolor(srccnt[cntord[sn].sno].val, sr.rcol);
320 multcolor(srccnt[cntord[sn].sno].val,
321 srccnt[cntord[sn].sno].coef);
322 }
323 /* add contribution if hit */
324 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
325 nhits++;
326 source[cntord[sn].sno].nhits++;
327 }
328 /* surface hit rate */
329 if (sn > 0)
330 hwt = (double)nhits / (double)sn;
331 else
332 hwt = 0.5;
333 #ifdef DEBUG
334 sprintf(errmsg, "%d tested, %d untested, %f hit rate\n",
335 sn, ncnts-sn, hwt);
336 eputs(errmsg);
337 #endif
338 /* add in untested sources */
339 for ( ; sn < ncnts; sn++) {
340 prob = hwt * (double)source[cntord[sn].sno].nhits /
341 (double)source[cntord[sn].sno].ntests;
342 scalecolor(srccnt[cntord[sn].sno].val, prob);
343 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
344 }
345 }