ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
Revision: 1.4
Committed: Thu Jun 20 16:36:48 1991 UTC (32 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +82 -47 lines
Log Message:
bug fixes and enhancements

File Contents

# User Rev Content
1 greg 1.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     * Routines for simulating virtual light sources
9     * Thus far, we only support planar mirrors.
10     */
11    
12     #include "ray.h"
13    
14 greg 1.3 #include "otypes.h"
15    
16 greg 1.1 #include "source.h"
17    
18    
19     double intercircle();
20    
21     static OBJECT *vobject; /* virtual source objects */
22     static int nvobjects = 0; /* number of virtual source objects */
23    
24    
25     markvirtuals() /* find and mark virtual sources */
26     {
27     register OBJREC *o;
28     register int i;
29     /* check number of direct relays */
30     if (directrelay <= 0)
31     return;
32     /* find virtual source objects */
33     for (i = 0; i < nobjects; i++) {
34     o = objptr(i);
35 greg 1.3 if (!issurface(o->otype) || o->omod == OVOID)
36 greg 1.1 continue;
37     if (!isvlight(objptr(o->omod)->otype))
38     continue;
39 greg 1.3 if (sfun[o->otype].of == NULL ||
40     sfun[o->otype].of->getpleq == NULL)
41     objerror(o, USER, "illegal material");
42 greg 1.1 if (nvobjects == 0)
43     vobject = (OBJECT *)malloc(sizeof(OBJECT));
44     else
45     vobject = (OBJECT *)realloc((char *)vobject,
46     (unsigned)(nvobjects+1)*sizeof(OBJECT));
47     if (vobject == NULL)
48     error(SYSTEM, "out of memory in addvirtuals");
49     vobject[nvobjects++] = i;
50     }
51     if (nvobjects == 0)
52     return;
53 greg 1.4 #ifdef DEBUG
54     fprintf(stderr, "found %d virtual source objects\n", nvobjects);
55     #endif
56 greg 1.1 /* append virtual sources */
57     for (i = nsources; i-- > 0; )
58     if (!(source[i].sflags & SSKIP))
59 greg 1.4 addvirtuals(i, directrelay);
60 greg 1.1 /* done with our object list */
61     free((char *)vobject);
62     nvobjects = 0;
63     }
64    
65    
66 greg 1.4 addvirtuals(sn, nr) /* add virtuals associated with source */
67     int sn;
68 greg 1.1 int nr;
69     {
70     register int i;
71     /* check relay limit first */
72     if (nr <= 0)
73     return;
74     /* check each virtual object for projection */
75     for (i = 0; i < nvobjects; i++)
76 greg 1.3 /* vproject() calls us recursively */
77 greg 1.4 vproject(objptr(vobject[i]), sn, nr-1);
78 greg 1.1 }
79    
80    
81 greg 1.4 vproject(o, sn, n) /* create projected source(s) if they exist */
82 greg 1.3 OBJREC *o;
83 greg 1.4 int sn;
84 greg 1.3 int n;
85     {
86     register int i;
87     register VSMATERIAL *vsmat;
88     MAT4 proj;
89 greg 1.4 int ns;
90    
91     if (o == source[sn].so) /* objects cannot project themselves */
92     return;
93 greg 1.3 /* get virtual source material */
94     vsmat = sfun[objptr(o->omod)->otype].mf;
95     /* project virtual sources */
96     for (i = 0; i < vsmat->nproj; i++)
97 greg 1.4 if ((*vsmat->vproj)(proj, o, &source[sn], i))
98     if ((ns = makevsrc(o, sn, proj)) >= 0) {
99     #ifdef DEBUG
100     virtverb(&source[sn], stderr);
101     #endif
102 greg 1.3 addvirtuals(ns, n);
103 greg 1.4 }
104 greg 1.3 }
105    
106    
107 greg 1.4 int
108     makevsrc(op, sn, pm) /* make virtual source if reasonable */
109 greg 1.1 OBJREC *op;
110 greg 1.4 register int sn;
111 greg 1.1 MAT4 pm;
112     {
113 greg 1.4 register int nsn;
114 greg 1.1 FVECT nsloc, ocent, nsnorm;
115 greg 1.3 int nsflags;
116 greg 1.1 double maxrad2;
117 greg 1.3 double d1;
118 greg 1.1 SPOT theirspot, ourspot;
119     register int i;
120 greg 1.3
121 greg 1.4 nsflags = (source[sn].sflags|(SVIRTUAL|SFOLLOW)) & ~SSPOT;
122 greg 1.1 /* get object center and max. radius */
123 greg 1.3 if (sfun[op->otype].of->getdisk != NULL) {
124     maxrad2 = (*sfun[op->otype].of->getdisk)(ocent, op);
125     if (maxrad2 <= FTINY) /* too small? */
126     return(NULL);
127     nsflags |= SSPOT;
128     }
129 greg 1.1 /* get location and spot */
130 greg 1.4 if (source[sn].sflags & SDISTANT) { /* distant source */
131     if (source[sn].sflags & SPROX)
132 greg 1.1 return(NULL); /* should never get here! */
133 greg 1.4 multv3(nsloc, source[sn].sloc, pm);
134 greg 1.3 if (nsflags & SSPOT) {
135     VCOPY(ourspot.aim, ocent);
136     ourspot.siz = PI*maxrad2;
137     ourspot.flen = 0.;
138     }
139 greg 1.4 if (source[sn].sflags & SSPOT) {
140     copystruct(&theirspot, source[sn].sl.s);
141     multp3(theirspot.aim, source[sn].sl.s->aim, pm);
142 greg 1.3 if (nsflags & SSPOT &&
143     !commonbeam(&ourspot, &theirspot, nsloc))
144 greg 1.1 return(NULL); /* no overlap */
145     }
146     } else { /* local source */
147 greg 1.4 multp3(nsloc, source[sn].sloc, pm);
148 greg 1.3 if (nsflags & SSPOT) {
149     for (i = 0; i < 3; i++)
150     ourspot.aim[i] = ocent[i] - nsloc[i];
151     if ((d1 = normalize(ourspot.aim)) == 0.)
152     return(NULL); /* at source!! */
153 greg 1.4 if (source[sn].sflags & SPROX &&
154     d1 > source[sn].sl.prox)
155 greg 1.3 return(NULL); /* too far away */
156     ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
157     ourspot.flen = 0.;
158 greg 1.4 } else if (source[sn].sflags & SPROX) {
159 greg 1.3 FVECT norm;
160     double offs;
161     /* use distance from plane */
162     offs = (*sfun[op->otype].of->getpleq)(norm, op);
163     d1 = DOT(norm, nsloc) - offs;
164 greg 1.4 if (d1 < 0.) d1 = -d1;
165     if (d1 > source[sn].sl.prox)
166 greg 1.3 return(NULL); /* too far away */
167     }
168 greg 1.4 if (source[sn].sflags & SSPOT) {
169     copystruct(&theirspot, source[sn].sl.s);
170     multv3(theirspot.aim, source[sn].sl.s->aim, pm);
171 greg 1.3 if (nsflags & SSPOT) {
172     if (!commonspot(&ourspot, &theirspot, nsloc))
173     return(NULL); /* no overlap */
174     ourspot.flen = theirspot.flen;
175     }
176 greg 1.1 }
177 greg 1.4 if (source[sn].sflags & SFLAT) { /* behind source? */
178     multv3(nsnorm, source[sn].snorm, pm);
179 greg 1.3 if (nsflags & SSPOT && checkspot(&ourspot, nsnorm) < 0)
180 greg 1.1 return(NULL);
181     }
182     }
183     /* everything is OK, make source */
184 greg 1.4 if ((nsn = newsource()) < 0)
185 greg 1.1 goto memerr;
186 greg 1.4 source[nsn].sflags = nsflags;
187     VCOPY(source[nsn].sloc, nsloc);
188 greg 1.3 if (nsflags & SFLAT)
189 greg 1.4 VCOPY(source[nsn].snorm, nsnorm);
190     source[nsn].ss = source[sn].ss; source[nsn].ss2 = source[sn].ss2;
191     if ((nsflags | source[sn].sflags) & SSPOT) {
192     if ((source[nsn].sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
193 greg 1.3 goto memerr;
194     if (nsflags & SSPOT)
195 greg 1.4 copystruct(source[nsn].sl.s, &ourspot);
196 greg 1.3 else
197 greg 1.4 copystruct(source[nsn].sl.s, &theirspot);
198     source[nsn].sflags |= SSPOT;
199 greg 1.3 }
200     if (nsflags & SPROX)
201 greg 1.4 source[nsn].sl.prox = source[sn].sl.prox;
202     source[nsn].sa.svnext = sn;
203     source[nsn].so = op;
204     return(nsn);
205 greg 1.1 memerr:
206     error(SYSTEM, "out of memory in makevsrc");
207     }
208    
209    
210     commonspot(sp1, sp2, org) /* set sp1 to intersection of sp1 and sp2 */
211     register SPOT *sp1, *sp2;
212     FVECT org;
213     {
214     FVECT cent;
215 greg 1.2 double rad2, cos1, cos2;
216 greg 1.1
217 greg 1.2 cos1 = 1. - sp1->siz/(2.*PI);
218     cos2 = 1. - sp2->siz/(2.*PI);
219 greg 1.1 if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
220 greg 1.2 return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
221     sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
222 greg 1.1 /* compute and check disks */
223 greg 1.2 rad2 = intercircle(cent, sp1->aim, sp2->aim,
224     1./(cos1*cos1) - 1., 1./(cos2*cos2) - 1.);
225 greg 1.1 if (rad2 <= FTINY || normalize(cent) == 0.)
226     return(0);
227     VCOPY(sp1->aim, cent);
228     sp1->siz = 2.*PI*(1. - 1./sqrt(1.+rad2));
229     return(1);
230     }
231    
232    
233     commonbeam(sp1, sp2, dir) /* set sp1 to intersection of sp1 and sp2 */
234     register SPOT *sp1, *sp2;
235     FVECT dir;
236     {
237     FVECT cent, c1, c2;
238     double rad2, d;
239     register int i;
240     /* move centers to common plane */
241     d = DOT(sp1->aim, dir);
242     for (i = 0; i < 3; i++)
243 greg 1.2 c1[i] = sp1->aim[i] - d*dir[i];
244 greg 1.1 d = DOT(sp2->aim, dir);
245     for (i = 0; i < 3; i++)
246     c2[i] = sp2->aim[i] - d*dir[i];
247     /* compute overlap */
248     rad2 = intercircle(cent, c1, c2, sp1->siz/PI, sp2->siz/PI);
249     if (rad2 <= FTINY)
250     return(0);
251     VCOPY(sp1->aim, cent);
252     sp1->siz = PI*rad2;
253     return(1);
254     }
255    
256    
257     checkspot(sp, nrm) /* check spotlight for behind source */
258     register SPOT *sp;
259     FVECT nrm;
260     {
261     double d, d1;
262    
263     d = DOT(sp->aim, nrm);
264     if (d > FTINY) /* center in front? */
265     return(0);
266     /* else check horizon */
267     d1 = 1. - sp->siz/(2.*PI);
268     return(1.-FTINY-d*d > d1*d1);
269     }
270    
271    
272     double
273     intercircle(cc, c1, c2, r1s, r2s) /* intersect two circles */
274     FVECT cc; /* midpoint (return value) */
275     FVECT c1, c2; /* circle centers */
276     double r1s, r2s; /* radii squared */
277     {
278     double a2, d2, l;
279     FVECT disp;
280     register int i;
281    
282     for (i = 0; i < 3; i++)
283     disp[i] = c2[i] - c1[i];
284     d2 = DOT(disp,disp);
285     /* circle within overlap? */
286     if (r1s < r2s) {
287     if (r2s >= r1s + d2) {
288     VCOPY(cc, c1);
289     return(r1s);
290     }
291     } else {
292     if (r1s >= r2s + d2) {
293     VCOPY(cc, c2);
294     return(r2s);
295     }
296     }
297     a2 = .25*(2.*(r1s+r2s) - d2 - (r2s-r1s)*(r2s-r1s)/d2);
298     /* no overlap? */
299     if (a2 <= 0.)
300     return(0.);
301 greg 1.2 /* overlap, compute center */
302 greg 1.1 l = sqrt((r1s - a2)/d2);
303     for (i = 0; i < 3; i++)
304     cc[i] = c1[i] + l*disp[i];
305     return(a2);
306     }
307 greg 1.4
308    
309     #ifdef DEBUG
310     virtverb(vs, fp) /* print verbose description of virtual source */
311     register SRCREC *vs;
312     FILE *fp;
313     {
314     register int i;
315    
316     fprintf(fp, "%s virtual source %d in %s %s\n",
317     vs->sflags & SDISTANT ? "distant" : "local",
318     vs-source, ofun[vs->so->otype].funame, vs->so->oname);
319     fprintf(fp, "\tat (%f,%f,%f)\n",
320     vs->sloc[0], vs->sloc[1], vs->sloc[2]);
321     fprintf(fp, "\tlinked to source %d (%s)\n",
322     vs->sa.svnext, source[vs->sa.svnext].so->oname);
323     if (vs->sflags & SFOLLOW)
324     fprintf(fp, "\talways followed\n");
325     else
326     fprintf(fp, "\tnever followed\n");
327     if (!(vs->sflags & SSPOT))
328     return;
329     fprintf(fp, "\twith spot aim (%f,%f,%f) and size %f\n",
330     vs->sl.s->aim[0], vs->sl.s->aim[1], vs->sl.s->aim[2],
331     vs->sl.s->siz);
332     }
333     #endif