ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
Revision: 1.2
Committed: Thu Jun 20 09:37:38 1991 UTC (32 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.1: +13 -24 lines
Log Message:
minor fixes

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 for (i = 0; i < 3; i++)
115 ourspot.aim[i] = ocent[i] - nsloc[i];
116 if ((d1 = normalize(ourspot.aim)) == 0.)
117 return(NULL); /* at source!! */
118 if (sp->sflags & SPROX && d1 > sp->sl.prox)
119 return(NULL); /* too far away */
120 ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
121 ourspot.flen = 0.;
122 if (sp->sflags & SSPOT) {
123 copystruct(&theirspot, sp->sl.s);
124 multv3(theirspot.aim, sp->sl.s->aim, pm);
125 if (!commonspot(&ourspot, &theirspot, nsloc))
126 return(NULL); /* no overlap */
127 ourspot.flen = theirspot.flen;
128 }
129 if (sp->sflags & SFLAT) { /* check for behind source */
130 multv3(nsnorm, sp->snorm, pm);
131 if (checkspot(&ourspot, nsnorm) < 0)
132 return(NULL);
133 }
134 }
135 /* everything is OK, make source */
136 if ((newsrc = newsource()) == NULL)
137 goto memerr;
138 newsrc->sflags = sp->sflags | (SVIRTUAL|SSPOT|SFOLLOW);
139 VCOPY(newsrc->sloc, nsloc);
140 if (newsrc->sflags & SFLAT)
141 VCOPY(newsrc->snorm, nsnorm);
142 newsrc->ss = sp->ss; newsrc->ss2 = sp->ss2;
143 if ((newsrc->sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
144 goto memerr;
145 copystruct(newsrc->sl.s, &ourspot);
146 if (newsrc->sflags & SPROX)
147 newsrc->sl.prox = sp->sl.prox;
148 newsrc->sa.svnext = sp - source;
149 return(newsrc);
150 memerr:
151 error(SYSTEM, "out of memory in makevsrc");
152 }
153
154
155 commonspot(sp1, sp2, org) /* set sp1 to intersection of sp1 and sp2 */
156 register SPOT *sp1, *sp2;
157 FVECT org;
158 {
159 FVECT cent;
160 double rad2, cos1, cos2;
161
162 cos1 = 1. - sp1->siz/(2.*PI);
163 cos2 = 1. - sp2->siz/(2.*PI);
164 if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
165 return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
166 sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
167 /* compute and check disks */
168 rad2 = intercircle(cent, sp1->aim, sp2->aim,
169 1./(cos1*cos1) - 1., 1./(cos2*cos2) - 1.);
170 if (rad2 <= FTINY || normalize(cent) == 0.)
171 return(0);
172 VCOPY(sp1->aim, cent);
173 sp1->siz = 2.*PI*(1. - 1./sqrt(1.+rad2));
174 return(1);
175 }
176
177
178 commonbeam(sp1, sp2, dir) /* set sp1 to intersection of sp1 and sp2 */
179 register SPOT *sp1, *sp2;
180 FVECT dir;
181 {
182 FVECT cent, c1, c2;
183 double rad2, d;
184 register int i;
185 /* move centers to common plane */
186 d = DOT(sp1->aim, dir);
187 for (i = 0; i < 3; i++)
188 c1[i] = sp1->aim[i] - d*dir[i];
189 d = DOT(sp2->aim, dir);
190 for (i = 0; i < 3; i++)
191 c2[i] = sp2->aim[i] - d*dir[i];
192 /* compute overlap */
193 rad2 = intercircle(cent, c1, c2, sp1->siz/PI, sp2->siz/PI);
194 if (rad2 <= FTINY)
195 return(0);
196 VCOPY(sp1->aim, cent);
197 sp1->siz = PI*rad2;
198 return(1);
199 }
200
201
202 checkspot(sp, nrm) /* check spotlight for behind source */
203 register SPOT *sp;
204 FVECT nrm;
205 {
206 double d, d1;
207
208 d = DOT(sp->aim, nrm);
209 if (d > FTINY) /* center in front? */
210 return(0);
211 /* else check horizon */
212 d1 = 1. - sp->siz/(2.*PI);
213 return(1.-FTINY-d*d > d1*d1);
214 }
215
216
217 mirrorproj(m, nv, offs) /* get mirror projection for surface */
218 register MAT4 m;
219 FVECT nv;
220 double offs;
221 {
222 register int i, j;
223 /* assign matrix */
224 setident4(m);
225 for (i = 0; i < 3; i++)
226 for (j = 0; j < 3; j++)
227 m[i][j] -= 2.*nv[i]*nv[j];
228 for (j = 0; j < 3; j++)
229 m[3][j] = 2.*offs*nv[j];
230 }
231
232
233 double
234 intercircle(cc, c1, c2, r1s, r2s) /* intersect two circles */
235 FVECT cc; /* midpoint (return value) */
236 FVECT c1, c2; /* circle centers */
237 double r1s, r2s; /* radii squared */
238 {
239 double a2, d2, l;
240 FVECT disp;
241 register int i;
242
243 for (i = 0; i < 3; i++)
244 disp[i] = c2[i] - c1[i];
245 d2 = DOT(disp,disp);
246 /* circle within overlap? */
247 if (r1s < r2s) {
248 if (r2s >= r1s + d2) {
249 VCOPY(cc, c1);
250 return(r1s);
251 }
252 } else {
253 if (r1s >= r2s + d2) {
254 VCOPY(cc, c2);
255 return(r2s);
256 }
257 }
258 a2 = .25*(2.*(r1s+r2s) - d2 - (r2s-r1s)*(r2s-r1s)/d2);
259 /* no overlap? */
260 if (a2 <= 0.)
261 return(0.);
262 /* overlap, compute center */
263 l = sqrt((r1s - a2)/d2);
264 for (i = 0; i < 3; i++)
265 cc[i] = c1[i] + l*disp[i];
266 return(a2);
267 }
268
269
270 /*
271 * The following routines depend on the supported OBJECTS:
272 */
273
274
275 double
276 getmaxdisk(ocent, op) /* get object center and squared radius */
277 FVECT ocent;
278 register OBJREC *op;
279 {
280 double maxrad2;
281
282 switch (op->otype) {
283 case OBJ_FACE:
284 {
285 double d2;
286 register int i, j;
287 register FACE *f = getface(op);
288
289 for (i = 0; i < 3; i++) {
290 ocent[i] = 0.;
291 for (j = 0; j < f->nv; j++)
292 ocent[i] += VERTEX(f,j)[i];
293 ocent[i] /= (double)f->nv;
294 }
295 maxrad2 = 0.;
296 for (j = 0; j < f->nv; j++) {
297 d2 = dist2(VERTEX(f,j), ocent);
298 if (d2 > maxrad2)
299 maxrad2 = d2;
300 }
301 }
302 return(maxrad2);
303 case OBJ_RING:
304 {
305 register CONE *co = getcone(op, 0);
306
307 VCOPY(ocent, CO_P0(co));
308 maxrad2 = CO_R1(co);
309 maxrad2 *= maxrad2;
310 }
311 return(maxrad2);
312 }
313 objerror(op, USER, "illegal material");
314 }
315
316
317 double
318 getplaneq(nvec, op) /* get plane equation for object */
319 FVECT nvec;
320 OBJREC *op;
321 {
322 register FACE *fo;
323 register CONE *co;
324
325 switch (op->otype) {
326 case OBJ_FACE:
327 fo = getface(op);
328 VCOPY(nvec, fo->norm);
329 return(fo->offset);
330 case OBJ_RING:
331 co = getcone(op, 0);
332 VCOPY(nvec, co->ad);
333 return(DOT(nvec, CO_P0(co)));
334 }
335 objerror(op, USER, "illegal material");
336 }
337
338
339 /*
340 * The following routines depend on the supported MATERIALS:
341 */
342
343
344 vproject(o, s, n) /* create projected source(s) if they exist */
345 OBJREC *o;
346 SRCREC *s;
347 int n;
348 {
349 SRCREC *ns;
350 FVECT norm;
351 double offset;
352 MAT4 proj;
353 /* get surface normal and offset */
354 offset = getplaneq(norm, o);
355 switch (objptr(o->omod)->otype) {
356 case MAT_MIRROR: /* mirror source */
357 if (DOT(s->sloc, norm) <= (s->sflags & SDISTANT ?
358 FTINY : offset+FTINY))
359 return; /* behind mirror */
360 mirrorproj(proj, norm, offset);
361 if ((ns = makevsrc(o, s, proj)) != NULL)
362 addvirtuals(ns, n);
363 break;
364 }
365 }
366
367
368 vsrcrelay(rn, rv) /* relay virtual source ray */
369 register RAY *rn, *rv;
370 {
371 int snext;
372 register int i;
373 /* source we're aiming for here */
374 snext = source[rv->rsrc].sa.svnext;
375 /* compute relayed ray direction */
376 switch (objptr(rv->ro->omod)->otype) {
377 case MAT_MIRROR: /* mirror: singular reflection */
378 rayorigin(rn, rv, REFLECTED, 1.);
379 /* ignore textures */
380 for (i = 0; i < 3; i++)
381 rn->rdir[i] = rv->rdir[i] + 2.*rv->rod*rv->ron[i];
382 break;
383 #ifdef DEBUG
384 default:
385 error(CONSISTENCY, "inappropriate material in vsrcrelay");
386 #endif
387 }
388 rn->rsrc = snext;
389 }
390
391
392 m_mirror(m, r) /* shade mirrored ray */
393 register OBJREC *m;
394 register RAY *r;
395 {
396 COLOR mcolor;
397 RAY nr;
398 register int i;
399
400 if (m->oargs.nfargs != 3 || m->oargs.nsargs > 1)
401 objerror(m, USER, "bad number of arguments");
402 if (r->rsrc >= 0) { /* aiming for somebody */
403 if (source[r->rsrc].so != r->ro)
404 return; /* but not us */
405 } else if (m->oargs.nsargs > 0) { /* else call substitute? */
406 rayshade(r, modifier(m->oargs.sarg[0]));
407 return;
408 }
409 if (r->rod < 0.) /* back is black */
410 return;
411 /* get modifiers */
412 raytexture(r, m->omod);
413 /* assign material color */
414 setcolor(mcolor, m->oargs.farg[0],
415 m->oargs.farg[1],
416 m->oargs.farg[2]);
417 multcolor(mcolor, r->pcol);
418 /* compute reflected ray */
419 if (r->rsrc >= 0) /* relayed light source */
420 vsrcrelay(&nr, r);
421 else { /* ordinary reflection */
422 FVECT pnorm;
423 double pdot;
424
425 if (rayorigin(&nr, r, REFLECTED, bright(mcolor)) < 0)
426 return;
427 pdot = raynormal(pnorm, r); /* use textures */
428 for (i = 0; i < 3; i++)
429 nr.rdir[i] = r->rdir[i] + 2.*pdot*pnorm[i];
430 }
431 rayvalue(&nr);
432 multcolor(nr.rcol, mcolor);
433 addcolor(r->rcol, nr.rcol);
434 }