ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/source.c
Revision: 1.36
Committed: Thu Jun 20 16:36:41 1991 UTC (33 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.35: +9 -9 lines
Log Message:
bug fixes and enhancements

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