ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
Revision: 1.1
Committed: Wed Jun 19 16:36:14 1991 UTC (32 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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 "source.h"
15
16 #include "otypes.h"
17
18 #include "cone.h"
19
20 #include "face.h"
21
22 extern int directrelay; /* maximum number of source relays */
23
24 double getplaneq();
25 double getmaxdisk();
26 double intercircle();
27 SRCREC *makevsrc();
28
29 static OBJECT *vobject; /* virtual source objects */
30 static int nvobjects = 0; /* number of virtual source objects */
31
32
33 markvirtuals() /* find and mark virtual sources */
34 {
35 register OBJREC *o;
36 register int i;
37 /* check number of direct relays */
38 if (directrelay <= 0)
39 return;
40 /* find virtual source objects */
41 for (i = 0; i < nobjects; i++) {
42 o = objptr(i);
43 if (o->omod == OVOID)
44 continue;
45 if (!isvlight(objptr(o->omod)->otype))
46 continue;
47 if (nvobjects == 0)
48 vobject = (OBJECT *)malloc(sizeof(OBJECT));
49 else
50 vobject = (OBJECT *)realloc((char *)vobject,
51 (unsigned)(nvobjects+1)*sizeof(OBJECT));
52 if (vobject == NULL)
53 error(SYSTEM, "out of memory in addvirtuals");
54 vobject[nvobjects++] = i;
55 }
56 if (nvobjects == 0)
57 return;
58 /* append virtual sources */
59 for (i = nsources; i-- > 0; )
60 if (!(source[i].sflags & SSKIP))
61 addvirtuals(&source[i], directrelay);
62 /* done with our object list */
63 free((char *)vobject);
64 nvobjects = 0;
65 }
66
67
68 addvirtuals(sr, nr) /* add virtual sources associated with sr */
69 SRCREC *sr;
70 int nr;
71 {
72 register int i;
73 /* check relay limit first */
74 if (nr <= 0)
75 return;
76 /* check each virtual object for projection */
77 for (i = 0; i < nvobjects; i++)
78 vproject(objptr(i), sr, nr-1); /* calls us recursively */
79 }
80
81
82 SRCREC *
83 makevsrc(op, sp, pm) /* make virtual source if reasonable */
84 OBJREC *op;
85 register SRCREC *sp;
86 MAT4 pm;
87 {
88 register SRCREC *newsrc;
89 FVECT nsloc, ocent, nsnorm;
90 double maxrad2;
91 double d1, d2;
92 SPOT theirspot, ourspot;
93 register int i;
94 /* get object center and max. radius */
95 maxrad2 = getmaxdisk(ocent, op);
96 if (maxrad2 <= FTINY) /* too small? */
97 return(NULL);
98 /* get location and spot */
99 if (sp->sflags & SDISTANT) { /* distant source */
100 if (sp->sflags & SPROX)
101 return(NULL); /* should never get here! */
102 multv3(nsloc, sp->sloc, pm);
103 VCOPY(ourspot.aim, ocent);
104 ourspot.siz = PI*maxrad2;
105 ourspot.flen = 0.;
106 if (sp->sflags & SSPOT) {
107 copystruct(&theirspot, sp->sl.s);
108 multp3(theirspot.aim, sp->sl.s->aim, pm);
109 if (!commonbeam(&ourspot, &theirspot, nsloc))
110 return(NULL); /* no overlap */
111 }
112 } else { /* local source */
113 multp3(nsloc, sp->sloc, pm);
114 if (sp->sflags & SPROX) {
115 d2 = 0.;
116 for (i = 0; i < 3; i++) {
117 d1 = ocent[i] - nsloc[i];
118 d2 += d1*d1;
119 }
120 if (d2 > sp->sl.prox*sp->sl.prox)
121 return(NULL); /* too far away */
122 }
123 for (i = 0; i < 3; i++)
124 ourspot.aim[i] = ocent[i] - nsloc[i];
125 if ((d1 = normalize(ourspot.aim)) == 0.)
126 return(NULL); /* at source!! */
127 ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
128 ourspot.flen = 0.;
129 if (sp->sflags & SSPOT) {
130 copystruct(&theirspot, sp->sl.s);
131 multv3(theirspot.aim, sp->sl.s->aim, pm);
132 if (!commonspot(&ourspot, &theirspot, nsloc))
133 return(NULL); /* no overlap */
134 ourspot.flen = theirspot.flen;
135 }
136 if (sp->sflags & SFLAT) { /* check for behind source */
137 multv3(nsnorm, sp->snorm, pm);
138 if (checkspot(&ourspot, nsnorm) < 0)
139 return(NULL);
140 }
141 }
142 /* everything is OK, make source */
143 if ((newsrc = newsource()) == NULL)
144 goto memerr;
145 newsrc->sflags = sp->sflags | (SVIRTUAL|SSPOT|SFOLLOW);
146 VCOPY(newsrc->sloc, nsloc);
147 if (newsrc->sflags & SFLAT)
148 VCOPY(newsrc->snorm, nsnorm);
149 newsrc->ss = sp->ss; newsrc->ss2 = sp->ss2;
150 if ((newsrc->sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
151 goto memerr;
152 copystruct(newsrc->sl.s, &ourspot);
153 if (newsrc->sflags & SPROX)
154 newsrc->sl.prox = sp->sl.prox;
155 newsrc->sa.svnext = sp - source;
156 return(newsrc);
157 memerr:
158 error(SYSTEM, "out of memory in makevsrc");
159 }
160
161
162 commonspot(sp1, sp2, org) /* set sp1 to intersection of sp1 and sp2 */
163 register SPOT *sp1, *sp2;
164 FVECT org;
165 {
166 FVECT cent;
167 double rad2, d1r2, d2r2;
168
169 d1r2 = 1. - sp1->siz/(2.*PI);
170 d2r2 = 1. - sp2->siz/(2.*PI);
171 if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
172 return(DOT(sp1->aim,sp2->aim) >= d1r2*d2r2 -
173 sqrt((1.-d1r2*d1r2)*(1.-d2r2*d2r2)));
174 /* compute and check disks */
175 d1r2 = 1./(d1r2*d1r2) - 1.;
176 d2r2 = 1./(d2r2*d2r2) - 1.;
177 rad2 = intercircle(cent, sp1->aim, sp2->aim, d1r2, d2r2);
178 if (rad2 <= FTINY || normalize(cent) == 0.)
179 return(0);
180 VCOPY(sp1->aim, cent);
181 sp1->siz = 2.*PI*(1. - 1./sqrt(1.+rad2));
182 return(1);
183 }
184
185
186 commonbeam(sp1, sp2, dir) /* set sp1 to intersection of sp1 and sp2 */
187 register SPOT *sp1, *sp2;
188 FVECT dir;
189 {
190 FVECT cent, c1, c2;
191 double rad2, d;
192 register int i;
193 /* move centers to common plane */
194 d = DOT(sp1->aim, dir);
195 for (i = 0; i < 3; i++)
196 c1[i] = sp2->aim[i] - d*dir[i];
197 d = DOT(sp2->aim, dir);
198 for (i = 0; i < 3; i++)
199 c2[i] = sp2->aim[i] - d*dir[i];
200 /* compute overlap */
201 rad2 = intercircle(cent, c1, c2, sp1->siz/PI, sp2->siz/PI);
202 if (rad2 <= FTINY)
203 return(0);
204 VCOPY(sp1->aim, cent);
205 sp1->siz = PI*rad2;
206 return(1);
207 }
208
209
210 checkspot(sp, nrm) /* check spotlight for behind source */
211 register SPOT *sp;
212 FVECT nrm;
213 {
214 double d, d1;
215
216 d = DOT(sp->aim, nrm);
217 if (d > FTINY) /* center in front? */
218 return(0);
219 /* else check horizon */
220 d1 = 1. - sp->siz/(2.*PI);
221 return(1.-FTINY-d*d > d1*d1);
222 }
223
224
225 mirrorproj(m, nv, offs) /* get mirror projection for surface */
226 register MAT4 m;
227 FVECT nv;
228 double offs;
229 {
230 register int i, j;
231 /* assign matrix */
232 setident4(m);
233 for (i = 0; i < 3; i++)
234 for (j = 0; j < 3; j++)
235 m[i][j] -= 2.*nv[i]*nv[j];
236 for (j = 0; j < 3; j++)
237 m[3][j] = 2.*offs*nv[j];
238 }
239
240
241 double
242 intercircle(cc, c1, c2, r1s, r2s) /* intersect two circles */
243 FVECT cc; /* midpoint (return value) */
244 FVECT c1, c2; /* circle centers */
245 double r1s, r2s; /* radii squared */
246 {
247 double a2, d2, l;
248 FVECT disp;
249 register int i;
250
251 for (i = 0; i < 3; i++)
252 disp[i] = c2[i] - c1[i];
253 d2 = DOT(disp,disp);
254 /* circle within overlap? */
255 if (r1s < r2s) {
256 if (r2s >= r1s + d2) {
257 VCOPY(cc, c1);
258 return(r1s);
259 }
260 } else {
261 if (r1s >= r2s + d2) {
262 VCOPY(cc, c2);
263 return(r2s);
264 }
265 }
266 a2 = .25*(2.*(r1s+r2s) - d2 - (r2s-r1s)*(r2s-r1s)/d2);
267 /* no overlap? */
268 if (a2 <= 0.)
269 return(0.);
270 l = sqrt((r1s - a2)/d2);
271 for (i = 0; i < 3; i++)
272 cc[i] = c1[i] + l*disp[i];
273 return(a2);
274 }
275
276
277 /*
278 * The following routines depend on the supported OBJECTS:
279 */
280
281
282 double
283 getmaxdisk(ocent, op) /* get object center and squared radius */
284 FVECT ocent;
285 register OBJREC *op;
286 {
287 double maxrad2;
288
289 switch (op->otype) {
290 case OBJ_FACE:
291 {
292 double d1, d2;
293 register int i, j;
294 register FACE *f = getface(op);
295
296 for (i = 0; i < 3; i++) {
297 ocent[i] = 0.;
298 for (j = 0; j < f->nv; j++)
299 ocent[i] += VERTEX(f,j)[i];
300 ocent[i] /= (double)f->nv;
301 }
302 maxrad2 = 0.;
303 for (j = 0; j < f->nv; j++) {
304 d2 = 0.;
305 for (i = 0; i < 3; i++) {
306 d1 = VERTEX(f,j)[i] - ocent[i];
307 d2 += d1*d1;
308 }
309 if (d2 > maxrad2)
310 maxrad2 = d2;
311 }
312 }
313 return(maxrad2);
314 case OBJ_RING:
315 {
316 register CONE *co = getcone(op, 0);
317
318 VCOPY(ocent, CO_P0(co));
319 maxrad2 = CO_R1(co);
320 maxrad2 *= maxrad2;
321 }
322 return(maxrad2);
323 }
324 objerror(op, USER, "illegal material");
325 }
326
327
328 double
329 getplaneq(nvec, op) /* get plane equation for object */
330 FVECT nvec;
331 OBJREC *op;
332 {
333 register FACE *fo;
334 register CONE *co;
335
336 switch (op->otype) {
337 case OBJ_FACE:
338 fo = getface(op);
339 VCOPY(nvec, fo->norm);
340 return(fo->offset);
341 case OBJ_RING:
342 co = getcone(op, 0);
343 VCOPY(nvec, co->ad);
344 return(DOT(nvec, CO_P0(co)));
345 }
346 objerror(op, USER, "illegal material");
347 }
348
349
350 /*
351 * The following routines depend on the supported MATERIALS:
352 */
353
354
355 vproject(o, s, n) /* create projected source(s) if they exist */
356 OBJREC *o;
357 SRCREC *s;
358 int n;
359 {
360 SRCREC *ns;
361 FVECT norm;
362 double offset;
363 MAT4 proj;
364 /* get surface normal and offset */
365 offset = getplaneq(norm, o);
366 switch (objptr(o->omod)->otype) {
367 case MAT_MIRROR: /* mirror source */
368 if (DOT(s->sloc, norm) <= (s->sflags & SDISTANT ?
369 FTINY : offset+FTINY))
370 return; /* behind mirror */
371 mirrorproj(proj, norm, offset);
372 if ((ns = makevsrc(o, s, proj)) != NULL)
373 addvirtuals(ns, n);
374 break;
375 }
376 }
377
378
379 vsrcrelay(rn, rv) /* relay virtual source ray */
380 register RAY *rn, *rv;
381 {
382 int snext;
383 register int i;
384 /* source we're aiming for here */
385 snext = source[rv->rsrc].sa.svnext;
386 /* compute relayed ray direction */
387 switch (objptr(rv->ro->omod)->otype) {
388 case MAT_MIRROR: /* mirror: singular reflection */
389 rayorigin(rn, rv, REFLECTED, 1.);
390 /* ignore textures */
391 for (i = 0; i < 3; i++)
392 rn->rdir[i] = rv->rdir[i] + 2.*rv->rod*rv->ron[i];
393 break;
394 #ifdef DEBUG
395 default:
396 error(CONSISTENCY, "inappropriate material in vsrcrelay");
397 #endif
398 }
399 rn->rsrc = snext;
400 }
401
402
403 m_mirror(m, r) /* shade mirrored ray */
404 register OBJREC *m;
405 register RAY *r;
406 {
407 COLOR mcolor;
408 RAY nr;
409 register int i;
410
411 if (m->oargs.nfargs != 3 || m->oargs.nsargs > 1)
412 objerror(m, USER, "bad number of arguments");
413 if (r->rsrc >= 0) { /* aiming for somebody */
414 if (source[r->rsrc].so != r->ro)
415 return; /* but not us */
416 } else if (m->oargs.nsargs > 0) { /* else call substitute? */
417 rayshade(r, modifier(m->oargs.sarg[0]));
418 return;
419 }
420 if (r->rod < 0.) /* back is black */
421 return;
422 /* get modifiers */
423 raytexture(r, m->omod);
424 /* assign material color */
425 setcolor(mcolor, m->oargs.farg[0],
426 m->oargs.farg[1],
427 m->oargs.farg[2]);
428 multcolor(mcolor, r->pcol);
429 /* compute reflected ray */
430 if (r->rsrc >= 0) /* relayed light source */
431 vsrcrelay(&nr, r);
432 else { /* ordinary reflection */
433 FVECT pnorm;
434 double pdot;
435
436 if (rayorigin(&nr, r, REFLECTED, bright(mcolor)) < 0)
437 return;
438 pdot = raynormal(pnorm, r); /* use textures */
439 for (i = 0; i < 3; i++)
440 nr.rdir[i] = r->rdir[i] + 2.*pdot*pnorm[i];
441 }
442 rayvalue(&nr);
443 multcolor(nr.rcol, mcolor);
444 addcolor(r->rcol, nr.rcol);
445 }