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

# 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 * Routines for simulating virtual light sources
9 * Thus far, we only support planar mirrors.
10 */
11
12 #include "ray.h"
13
14 #include "otypes.h"
15
16 #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 if (!issurface(o->otype) || o->omod == OVOID)
36 continue;
37 if (!isvlight(objptr(o->omod)->otype))
38 continue;
39 if (sfun[o->otype].of == NULL ||
40 sfun[o->otype].of->getpleq == NULL)
41 objerror(o, USER, "illegal material");
42 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 #ifdef DEBUG
54 fprintf(stderr, "found %d virtual source objects\n", nvobjects);
55 #endif
56 /* append virtual sources */
57 for (i = nsources; i-- > 0; )
58 if (!(source[i].sflags & SSKIP))
59 addvirtuals(i, directrelay);
60 /* done with our object list */
61 free((char *)vobject);
62 nvobjects = 0;
63 }
64
65
66 addvirtuals(sn, nr) /* add virtuals associated with source */
67 int sn;
68 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 /* vproject() calls us recursively */
77 vproject(objptr(vobject[i]), sn, nr-1);
78 }
79
80
81 vproject(o, sn, n) /* create projected source(s) if they exist */
82 OBJREC *o;
83 int sn;
84 int n;
85 {
86 register int i;
87 register VSMATERIAL *vsmat;
88 MAT4 proj;
89 int ns;
90
91 if (o == source[sn].so) /* objects cannot project themselves */
92 return;
93 /* 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 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 addvirtuals(ns, n);
103 }
104 }
105
106
107 int
108 makevsrc(op, sn, pm) /* make virtual source if reasonable */
109 OBJREC *op;
110 register int sn;
111 MAT4 pm;
112 {
113 register int nsn;
114 FVECT nsloc, ocent, nsnorm;
115 int nsflags;
116 double maxrad2;
117 double d1;
118 SPOT theirspot, ourspot;
119 register int i;
120
121 nsflags = (source[sn].sflags|(SVIRTUAL|SFOLLOW)) & ~SSPOT;
122 /* get object center and max. radius */
123 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 /* get location and spot */
130 if (source[sn].sflags & SDISTANT) { /* distant source */
131 if (source[sn].sflags & SPROX)
132 return(NULL); /* should never get here! */
133 multv3(nsloc, source[sn].sloc, pm);
134 if (nsflags & SSPOT) {
135 VCOPY(ourspot.aim, ocent);
136 ourspot.siz = PI*maxrad2;
137 ourspot.flen = 0.;
138 }
139 if (source[sn].sflags & SSPOT) {
140 copystruct(&theirspot, source[sn].sl.s);
141 multp3(theirspot.aim, source[sn].sl.s->aim, pm);
142 if (nsflags & SSPOT &&
143 !commonbeam(&ourspot, &theirspot, nsloc))
144 return(NULL); /* no overlap */
145 }
146 } else { /* local source */
147 multp3(nsloc, source[sn].sloc, pm);
148 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 if (source[sn].sflags & SPROX &&
154 d1 > source[sn].sl.prox)
155 return(NULL); /* too far away */
156 ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
157 ourspot.flen = 0.;
158 } else if (source[sn].sflags & SPROX) {
159 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 if (d1 < 0.) d1 = -d1;
165 if (d1 > source[sn].sl.prox)
166 return(NULL); /* too far away */
167 }
168 if (source[sn].sflags & SSPOT) {
169 copystruct(&theirspot, source[sn].sl.s);
170 multv3(theirspot.aim, source[sn].sl.s->aim, pm);
171 if (nsflags & SSPOT) {
172 if (!commonspot(&ourspot, &theirspot, nsloc))
173 return(NULL); /* no overlap */
174 ourspot.flen = theirspot.flen;
175 }
176 }
177 if (source[sn].sflags & SFLAT) { /* behind source? */
178 multv3(nsnorm, source[sn].snorm, pm);
179 if (nsflags & SSPOT && checkspot(&ourspot, nsnorm) < 0)
180 return(NULL);
181 }
182 }
183 /* everything is OK, make source */
184 if ((nsn = newsource()) < 0)
185 goto memerr;
186 source[nsn].sflags = nsflags;
187 VCOPY(source[nsn].sloc, nsloc);
188 if (nsflags & SFLAT)
189 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 goto memerr;
194 if (nsflags & SSPOT)
195 copystruct(source[nsn].sl.s, &ourspot);
196 else
197 copystruct(source[nsn].sl.s, &theirspot);
198 source[nsn].sflags |= SSPOT;
199 }
200 if (nsflags & SPROX)
201 source[nsn].sl.prox = source[sn].sl.prox;
202 source[nsn].sa.svnext = sn;
203 source[nsn].so = op;
204 return(nsn);
205 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 double rad2, cos1, cos2;
216
217 cos1 = 1. - sp1->siz/(2.*PI);
218 cos2 = 1. - sp2->siz/(2.*PI);
219 if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
220 return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
221 sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
222 /* compute and check disks */
223 rad2 = intercircle(cent, sp1->aim, sp2->aim,
224 1./(cos1*cos1) - 1., 1./(cos2*cos2) - 1.);
225 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 c1[i] = sp1->aim[i] - d*dir[i];
244 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 /* overlap, compute center */
302 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
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