ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 2.3
Committed: Sun Apr 12 10:05:32 1992 UTC (32 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +4 -1 lines
Log Message:
tightened up test for no contributing sources

File Contents

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