ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
Revision: 2.7
Committed: Sat Feb 22 02:07:29 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +65 -9 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Routines for simulating virtual light sources
6 * Thus far, we only support planar mirrors.
7 *
8 * External symbols declared in source.h
9 */
10
11 /* ====================================================================
12 * The Radiance Software License, Version 1.0
13 *
14 * Copyright (c) 1990 - 2002 The Regents of the University of California,
15 * through Lawrence Berkeley National Laboratory. All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 *
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 *
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in
26 * the documentation and/or other materials provided with the
27 * distribution.
28 *
29 * 3. The end-user documentation included with the redistribution,
30 * if any, must include the following acknowledgment:
31 * "This product includes Radiance software
32 * (http://radsite.lbl.gov/)
33 * developed by the Lawrence Berkeley National Laboratory
34 * (http://www.lbl.gov/)."
35 * Alternately, this acknowledgment may appear in the software itself,
36 * if and wherever such third-party acknowledgments normally appear.
37 *
38 * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
39 * and "The Regents of the University of California" must
40 * not be used to endorse or promote products derived from this
41 * software without prior written permission. For written
42 * permission, please contact [email protected].
43 *
44 * 5. Products derived from this software may not be called "Radiance",
45 * nor may "Radiance" appear in their name, without prior written
46 * permission of Lawrence Berkeley National Laboratory.
47 *
48 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
49 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51 * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
52 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
54 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
55 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
56 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
57 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
58 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 * ====================================================================
61 *
62 * This software consists of voluntary contributions made by many
63 * individuals on behalf of Lawrence Berkeley National Laboratory. For more
64 * information on Lawrence Berkeley National Laboratory, please see
65 * <http://www.lbl.gov/>.
66 */
67
68 #include "ray.h"
69
70 #include "otypes.h"
71
72 #include "source.h"
73
74 #include "random.h"
75
76 #define MINSAMPLES 16 /* minimum number of pretest samples */
77 #define STESTMAX 32 /* maximum seeks per sample */
78
79
80 static OBJECT *vobject; /* virtual source objects */
81 static int nvobjects = 0; /* number of virtual source objects */
82
83
84 void
85 markvirtuals() /* find and mark virtual sources */
86 {
87 register OBJREC *o;
88 register int i;
89 /* check number of direct relays */
90 if (directrelay <= 0)
91 return;
92 /* find virtual source objects */
93 for (i = 0; i < nobjects; i++) {
94 o = objptr(i);
95 if (!issurface(o->otype) || o->omod == OVOID)
96 continue;
97 if (!isvlight(vsmaterial(o)->otype))
98 continue;
99 if (sfun[o->otype].of == NULL ||
100 sfun[o->otype].of->getpleq == NULL) {
101 objerror(o,WARNING,"secondary sources not supported");
102 continue;
103 }
104 if (nvobjects == 0)
105 vobject = (OBJECT *)malloc(sizeof(OBJECT));
106 else
107 vobject = (OBJECT *)realloc((char *)vobject,
108 (unsigned)(nvobjects+1)*sizeof(OBJECT));
109 if (vobject == NULL)
110 error(SYSTEM, "out of memory in addvirtuals");
111 vobject[nvobjects++] = i;
112 }
113 if (nvobjects == 0)
114 return;
115 #ifdef DEBUG
116 fprintf(stderr, "found %d virtual source objects\n", nvobjects);
117 #endif
118 /* append virtual sources */
119 for (i = nsources; i-- > 0; )
120 addvirtuals(i, directrelay);
121 /* done with our object list */
122 free((void *)vobject);
123 nvobjects = 0;
124 }
125
126
127 void
128 addvirtuals(sn, nr) /* add virtuals associated with source */
129 int sn;
130 int nr;
131 {
132 register int i;
133 /* check relay limit first */
134 if (nr <= 0)
135 return;
136 if (source[sn].sflags & SSKIP)
137 return;
138 /* check each virtual object for projection */
139 for (i = 0; i < nvobjects; i++)
140 /* vproject() calls us recursively */
141 vproject(objptr(vobject[i]), sn, nr-1);
142 }
143
144
145 void
146 vproject(o, sn, n) /* create projected source(s) if they exist */
147 OBJREC *o;
148 int sn;
149 int n;
150 {
151 register int i;
152 register VSMATERIAL *vsmat;
153 MAT4 proj;
154 int ns;
155
156 if (o == source[sn].so) /* objects cannot project themselves */
157 return;
158 /* get virtual source material */
159 vsmat = sfun[vsmaterial(o)->otype].mf;
160 /* project virtual sources */
161 for (i = 0; i < vsmat->nproj; i++)
162 if ((*vsmat->vproj)(proj, o, &source[sn], i))
163 if ((ns = makevsrc(o, sn, proj)) >= 0) {
164 source[ns].sa.sv.pn = i;
165 #ifdef DEBUG
166 virtverb(ns, stderr);
167 #endif
168 addvirtuals(ns, n);
169 }
170 }
171
172
173 OBJREC *
174 vsmaterial(o) /* get virtual source material pointer */
175 OBJREC *o;
176 {
177 register int i;
178 register OBJREC *m;
179
180 i = o->omod;
181 m = objptr(i);
182 if (m->otype != MAT_ILLUM || m->oargs.nsargs < 1 ||
183 !strcmp(m->oargs.sarg[0], VOIDID) ||
184 (i = lastmod(objndx(m), m->oargs.sarg[0])) == OVOID)
185 return(m); /* direct modifier */
186 return(objptr(i)); /* illum alternate */
187 }
188
189
190 int
191 makevsrc(op, sn, pm) /* make virtual source if reasonable */
192 OBJREC *op;
193 register int sn;
194 MAT4 pm;
195 {
196 FVECT nsloc, nsnorm, ocent, v;
197 double maxrad2, d;
198 int nsflags;
199 SPOT theirspot, ourspot;
200 register int i;
201
202 nsflags = source[sn].sflags | (SVIRTUAL|SSPOT|SFOLLOW);
203 /* get object center and max. radius */
204 maxrad2 = getdisk(ocent, op, sn);
205 if (maxrad2 <= FTINY) /* too small? */
206 return(-1);
207 /* get location and spot */
208 if (source[sn].sflags & SDISTANT) { /* distant source */
209 if (source[sn].sflags & SPROX)
210 return(-1); /* should never get here! */
211 multv3(nsloc, source[sn].sloc, pm);
212 normalize(nsloc);
213 VCOPY(ourspot.aim, ocent);
214 ourspot.siz = PI*maxrad2;
215 ourspot.flen = -1.;
216 if (source[sn].sflags & SSPOT) {
217 multp3(theirspot.aim, source[sn].sl.s->aim, pm);
218 /* adjust for source size */
219 d = sqrt(dist2(ourspot.aim, theirspot.aim));
220 d = sqrt(source[sn].sl.s->siz/PI) + d*source[sn].srad;
221 theirspot.siz = PI*d*d;
222 ourspot.flen = theirspot.flen = source[sn].sl.s->flen;
223 d = ourspot.siz;
224 if (!commonbeam(&ourspot, &theirspot, nsloc))
225 return(-1); /* no overlap */
226 if (ourspot.siz < d-FTINY) { /* it shrunk */
227 d = beamdisk(v, op, &ourspot, nsloc);
228 if (d <= FTINY)
229 return(-1);
230 if (d < maxrad2) {
231 maxrad2 = d;
232 VCOPY(ocent, v);
233 }
234 }
235 }
236 } else { /* local source */
237 multp3(nsloc, source[sn].sloc, pm);
238 for (i = 0; i < 3; i++)
239 ourspot.aim[i] = ocent[i] - nsloc[i];
240 if ((d = normalize(ourspot.aim)) == 0.)
241 return(-1); /* at source!! */
242 if (source[sn].sflags & SPROX && d > source[sn].sl.prox)
243 return(-1); /* too far away */
244 ourspot.flen = 0.;
245 /* adjust for source size */
246 d = (sqrt(maxrad2) + source[sn].srad) / d;
247 if (d < 1.-FTINY)
248 ourspot.siz = 2.*PI*(1. - sqrt(1.-d*d));
249 else
250 nsflags &= ~SSPOT;
251 if (source[sn].sflags & SSPOT) {
252 copystruct(&theirspot, source[sn].sl.s);
253 multv3(theirspot.aim, source[sn].sl.s->aim, pm);
254 normalize(theirspot.aim);
255 if (nsflags & SSPOT) {
256 ourspot.flen = theirspot.flen;
257 d = ourspot.siz;
258 if (!commonspot(&ourspot, &theirspot, nsloc))
259 return(-1); /* no overlap */
260 } else {
261 nsflags |= SSPOT;
262 copystruct(&ourspot, &theirspot);
263 d = 2.*ourspot.siz;
264 }
265 if (ourspot.siz < d-FTINY) { /* it shrunk */
266 d = spotdisk(v, op, &ourspot, nsloc);
267 if (d <= FTINY)
268 return(-1);
269 if (d < maxrad2) {
270 maxrad2 = d;
271 VCOPY(ocent, v);
272 }
273 }
274 }
275 if (source[sn].sflags & SFLAT) { /* behind source? */
276 multv3(nsnorm, source[sn].snorm, pm);
277 normalize(nsnorm);
278 if (nsflags & SSPOT && !checkspot(&ourspot, nsnorm))
279 return(-1);
280 }
281 }
282 /* pretest visibility */
283 nsflags = vstestvis(nsflags, op, ocent, maxrad2, sn);
284 if (nsflags & SSKIP)
285 return(-1); /* obstructed */
286 /* it all checks out, so make it */
287 if ((i = newsource()) < 0)
288 goto memerr;
289 source[i].sflags = nsflags;
290 VCOPY(source[i].sloc, nsloc);
291 multv3(source[i].ss[SU], source[sn].ss[SU], pm);
292 multv3(source[i].ss[SV], source[sn].ss[SV], pm);
293 if (nsflags & SFLAT)
294 VCOPY(source[i].snorm, nsnorm);
295 else
296 multv3(source[i].ss[SW], source[sn].ss[SW], pm);
297 source[i].srad = source[sn].srad;
298 source[i].ss2 = source[sn].ss2;
299 if (nsflags & SSPOT) {
300 if ((source[i].sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
301 goto memerr;
302 copystruct(source[i].sl.s, &ourspot);
303 }
304 if (nsflags & SPROX)
305 source[i].sl.prox = source[sn].sl.prox;
306 source[i].sa.sv.sn = sn;
307 source[i].so = op;
308 return(i);
309 memerr:
310 error(SYSTEM, "out of memory in makevsrc");
311 }
312
313
314 double
315 getdisk(oc, op, sn) /* get visible object disk */
316 FVECT oc;
317 OBJREC *op;
318 register int sn;
319 {
320 double rad2, roffs, offs, d, rd, rdoto;
321 FVECT rnrm, nrm;
322 /* first, use object getdisk function */
323 rad2 = getmaxdisk(oc, op);
324 if (!(source[sn].sflags & SVIRTUAL))
325 return(rad2); /* all done for normal source */
326 /* check for correct side of relay surface */
327 roffs = getplaneq(rnrm, source[sn].so);
328 rd = DOT(rnrm, source[sn].sloc); /* source projection */
329 if (!(source[sn].sflags & SDISTANT))
330 rd -= roffs;
331 d = DOT(rnrm, oc) - roffs; /* disk distance to relay plane */
332 if ((d > 0.) ^ (rd > 0.))
333 return(rad2); /* OK if opposite sides */
334 if (d*d >= rad2)
335 return(0.); /* no relay is possible */
336 /* we need a closer look */
337 offs = getplaneq(nrm, op);
338 rdoto = DOT(rnrm, nrm);
339 if (d*d >= rad2*(1.-rdoto*rdoto))
340 return(0.); /* disk entirely on projection side */
341 /* should shrink disk but I'm lazy */
342 return(rad2);
343 }
344
345
346 int
347 vstestvis(f, o, oc, or2, sn) /* pretest source visibility */
348 int f; /* virtual source flags */
349 OBJREC *o; /* relay object */
350 FVECT oc; /* relay object center */
351 double or2; /* relay object radius squared */
352 register int sn; /* target source number */
353 {
354 RAY sr;
355 FVECT onorm;
356 FVECT offsdir;
357 SRCINDEX si;
358 double or, d;
359 int stestlim, ssn;
360 int nhit, nok;
361 register int i, n;
362 /* return if pretesting disabled */
363 if (vspretest <= 0)
364 return(f);
365 /* get surface normal */
366 getplaneq(onorm, o);
367 /* set number of rays to sample */
368 if (source[sn].sflags & SDISTANT) {
369 /* 32. == heuristic constant */
370 n = 32.*or2/(thescene.cusize*thescene.cusize)*vspretest + .5;
371 } else {
372 for (i = 0; i < 3; i++)
373 offsdir[i] = source[sn].sloc[i] - oc[i];
374 d = DOT(offsdir,offsdir);
375 if (d <= FTINY)
376 n = 2.*PI * vspretest + .5;
377 else
378 n = 2.*PI * (1.-sqrt(1./(1.+or2/d)))*vspretest + .5;
379 }
380 if (n < MINSAMPLES) n = MINSAMPLES;
381 #ifdef DEBUG
382 fprintf(stderr, "pretesting source %d in object %s with %d rays\n",
383 sn, o->oname, n);
384 #endif
385 /* sample */
386 or = sqrt(or2);
387 stestlim = n*STESTMAX;
388 ssn = 0;
389 nhit = nok = 0;
390 initsrcindex(&si);
391 while (n-- > 0) {
392 /* get sample point */
393 do {
394 if (ssn >= stestlim) {
395 #ifdef DEBUG
396 fprintf(stderr, "\ttoo hard to hit\n");
397 #endif
398 return(f); /* too small a target! */
399 }
400 multisamp(offsdir, 3, urand(sn*931+5827+ssn));
401 for (i = 0; i < 3; i++)
402 offsdir[i] = or*(1. - 2.*offsdir[i]);
403 ssn++;
404 d = 1. - DOT(offsdir, onorm);
405 for (i = 0; i < 3; i++) {
406 sr.rorg[i] = oc[i] + offsdir[i] + d*onorm[i];
407 sr.rdir[i] = -onorm[i];
408 }
409 sr.rmax = 0.0;
410 rayorigin(&sr, NULL, PRIMARY, 1.0);
411 } while (!(*ofun[o->otype].funp)(o, &sr));
412 /* check against source */
413 VCOPY(sr.rorg, sr.rop); /* starting from intersection */
414 samplendx++;
415 if (si.sp >= si.np-1 ||
416 !srcray(&sr, NULL, &si) || sr.rsrc != sn) {
417 si.sn = sn-1; /* reset index to our source */
418 si.np = 0;
419 if (!srcray(&sr, NULL, &si) || sr.rsrc != sn)
420 continue; /* can't get there from here */
421 }
422 sr.revf = srcvalue;
423 rayvalue(&sr); /* check sample validity */
424 if (bright(sr.rcol) <= FTINY)
425 continue;
426 nok++; /* got sample; check obstructions */
427 rayclear(&sr);
428 sr.revf = raytrace;
429 rayvalue(&sr);
430 if (bright(sr.rcol) > FTINY)
431 nhit++;
432 if (nhit > 0 && nhit < nok) {
433 #ifdef DEBUG
434 fprintf(stderr, "\tpartially occluded\n");
435 #endif
436 return(f); /* need to shadow test */
437 }
438 }
439 if (nhit == 0) {
440 #ifdef DEBUG
441 fprintf(stderr, "\t0%% hit rate\n");
442 #endif
443 return(f | SSKIP); /* 0% hit rate: totally occluded */
444 }
445 #ifdef DEBUG
446 fprintf(stderr, "\t100%% hit rate\n");
447 #endif
448 return(f & ~SFOLLOW); /* 100% hit rate: no occlusion */
449 }
450
451
452 #ifdef DEBUG
453 void
454 virtverb(sn, fp) /* print verbose description of virtual source */
455 register int sn;
456 FILE *fp;
457 {
458 register int i;
459
460 fprintf(fp, "%s virtual source %d in %s %s\n",
461 source[sn].sflags & SDISTANT ? "distant" : "local",
462 sn, ofun[source[sn].so->otype].funame,
463 source[sn].so->oname);
464 fprintf(fp, "\tat (%f,%f,%f)\n",
465 source[sn].sloc[0], source[sn].sloc[1], source[sn].sloc[2]);
466 fprintf(fp, "\tlinked to source %d (%s)\n",
467 source[sn].sa.sv.sn, source[source[sn].sa.sv.sn].so->oname);
468 if (source[sn].sflags & SFOLLOW)
469 fprintf(fp, "\talways followed\n");
470 else
471 fprintf(fp, "\tnever followed\n");
472 if (!(source[sn].sflags & SSPOT))
473 return;
474 fprintf(fp, "\twith spot aim (%f,%f,%f) and size %f\n",
475 source[sn].sl.s->aim[0], source[sn].sl.s->aim[1],
476 source[sn].sl.s->aim[2], source[sn].sl.s->siz);
477 }
478 #endif