ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.42
Committed: Mon Aug 12 08:20:49 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.41: +4 -1 lines
Log Message:
fixed source tracing

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 #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] = source[sn].sl.s->aim[i] - sr->rorg[i];
168 d = DOT(sr->rdir,vd);
169 if (d <= FTINY)
170 return(0.0);
171 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 return(0.0);
180 /* check proximity */
181 if (source[sn].sflags & SPROX &&
182 d > source[sn].sl.prox)
183 return(0.0);
184 /* compute dot product */
185 if (source[sn].sflags & SFLAT)
186 ddot /= d;
187 else
188 ddot = 1.0;
189 /* check angle */
190 if (source[sn].sflags & SSPOT) {
191 if (source[sn].sl.s->siz < 2.0*PI *
192 (1.0 + DOT(source[sn].sl.s->aim,sr->rdir)))
193 return(0.0);
194 d += source[sn].sl.s->flen; /* adjust length */
195 }
196 /* compute domega */
197 return(ddot*source[sn].ss2/(d*d));
198 }
199
200
201 srcvalue(r) /* punch ray to source and compute value */
202 RAY *r;
203 {
204 register SRCREC *sp;
205
206 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 }
214 /* 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 }
222 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 }
231
232
233 static int
234 cntcmp(sc1, sc2) /* contribution compare (descending) */
235 register CNTPTR *sc1, *sc2;
236 {
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 extern int (*trace)();
251 extern double pow();
252 register int sn;
253 int nshadcheck, ncnts;
254 int nhits;
255 double dom, prob, ourthresh, hwt;
256 RAY sr;
257 /* NOTE: srccnt and cntord global so no recursion */
258 if (nsources <= 0)
259 return; /* no sources?! */
260 /* compute number to check */
261 nshadcheck = pow((double)nsources, shadcert) + .5;
262 /* modify threshold */
263 ourthresh = shadthresh / r->rweight;
264 /* potential contributions */
265 for (sn = 0; sn < nsources; sn++) {
266 cntord[sn].sno = sn;
267 cntord[sn].brt = 0.0;
268 /* get source ray */
269 if ((dom = srcray(&sr, r, sn)) == 0.0)
270 continue;
271 VCOPY(srccnt[sn].dir, sr.rdir);
272 /* compute coefficient */
273 (*f)(srccnt[sn].coef, p, srccnt[sn].dir, dom);
274 cntord[sn].brt = bright(srccnt[sn].coef);
275 if (cntord[sn].brt <= 0.0)
276 continue;
277 /* compute potential */
278 sr.revf = srcvalue;
279 rayvalue(&sr);
280 copycolor(srccnt[sn].val, sr.rcol);
281 multcolor(srccnt[sn].val, srccnt[sn].coef);
282 cntord[sn].brt = bright(srccnt[sn].val);
283 }
284 /* sort contributions */
285 qsort(cntord, nsources, sizeof(CNTPTR), cntcmp);
286 { /* find last */
287 register int l, m;
288
289 sn = 0; ncnts = l = nsources;
290 while ((m = (sn + ncnts) >> 1) != l) {
291 if (cntord[m].brt > 0.0)
292 sn = m;
293 else
294 ncnts = m;
295 l = m;
296 }
297 }
298 /* accumulate tail */
299 for (sn = ncnts-1; sn > 0; sn--)
300 cntord[sn-1].brt += cntord[sn].brt;
301 /* test for shadows */
302 nhits = 0;
303 for (sn = 0; sn < ncnts; sn++) {
304 /* check threshold */
305 if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
306 cntord[sn].brt-cntord[sn+nshadcheck].brt)
307 < ourthresh*bright(r->rcol))
308 break;
309 /* get statistics */
310 source[cntord[sn].sno].ntests++;
311 /* test for hit */
312 rayorigin(&sr, r, SHADOW, 1.0);
313 VCOPY(sr.rdir, srccnt[cntord[sn].sno].dir);
314 sr.rsrc = cntord[sn].sno;
315 if (localhit(&sr, &thescene) &&
316 ( sr.ro != source[cntord[sn].sno].so ||
317 source[cntord[sn].sno].sflags & SFOLLOW )) {
318 /* follow entire path */
319 raycont(&sr);
320 if (trace != NULL)
321 (*trace)(&sr); /* trace execution */
322 if (bright(sr.rcol) <= FTINY)
323 continue; /* missed! */
324 copycolor(srccnt[cntord[sn].sno].val, sr.rcol);
325 multcolor(srccnt[cntord[sn].sno].val,
326 srccnt[cntord[sn].sno].coef);
327 }
328 /* add contribution if hit */
329 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
330 nhits++;
331 source[cntord[sn].sno].nhits++;
332 }
333 /* surface hit rate */
334 if (sn > 0)
335 hwt = (double)nhits / (double)sn;
336 else
337 hwt = 0.5;
338 #ifdef DEBUG
339 sprintf(errmsg, "%d tested, %d untested, %f hit rate\n",
340 sn, ncnts-sn, hwt);
341 eputs(errmsg);
342 #endif
343 /* add in untested sources */
344 for ( ; sn < ncnts; sn++) {
345 prob = hwt * (double)source[cntord[sn].sno].nhits /
346 (double)source[cntord[sn].sno].ntests;
347 scalecolor(srccnt[cntord[sn].sno].val, prob);
348 addcolor(r->rcol, srccnt[cntord[sn].sno].val);
349 }
350 }