ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcsupp.c
Revision: 2.12
Committed: Wed Dec 31 01:50:02 2003 UTC (20 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +5 -2 lines
Log Message:
Created a source occluder cache to accelerate shadow testing.

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.12 static const char RCSid[] = "$Id: srcsupp.c,v 2.11 2003/04/23 00:52:34 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * Support routines for source objects and materials
6 greg 2.9 *
7     * External symbols declared in source.h
8     */
9    
10 greg 2.10 #include "copyright.h"
11 greg 1.1
12     #include "ray.h"
13    
14     #include "otypes.h"
15    
16     #include "source.h"
17    
18     #include "cone.h"
19    
20     #include "face.h"
21    
22 greg 2.12 #define SRCINC 8 /* realloc increment for array */
23 greg 1.1
24     SRCREC *source = NULL; /* our list of sources */
25     int nsources = 0; /* the number of sources */
26    
27     SRCFUNC sfun[NUMOTYPE]; /* source dispatch table */
28    
29    
30 greg 2.9 void
31 greg 1.1 initstypes() /* initialize source dispatch table */
32     {
33 greg 1.9 extern VSMATERIAL mirror_vs, direct1_vs, direct2_vs;
34 greg 1.14 static SOBJECT fsobj = {fsetsrc, flatpart, fgetplaneq, fgetmaxdisk};
35     static SOBJECT ssobj = {ssetsrc, nopart};
36     static SOBJECT sphsobj = {sphsetsrc, nopart};
37     static SOBJECT cylsobj = {cylsetsrc, cylpart};
38     static SOBJECT rsobj = {rsetsrc, flatpart, rgetplaneq, rgetmaxdisk};
39 greg 1.1
40     sfun[MAT_MIRROR].mf = &mirror_vs;
41 greg 1.9 sfun[MAT_DIRECT1].mf = &direct1_vs;
42     sfun[MAT_DIRECT2].mf = &direct2_vs;
43 greg 1.1 sfun[OBJ_FACE].of = &fsobj;
44     sfun[OBJ_SOURCE].of = &ssobj;
45     sfun[OBJ_SPHERE].of = &sphsobj;
46 greg 1.14 sfun[OBJ_CYLINDER].of = &cylsobj;
47 greg 1.1 sfun[OBJ_RING].of = &rsobj;
48     }
49    
50    
51 greg 1.2 int
52 greg 1.1 newsource() /* allocate new source in our array */
53     {
54     if (nsources == 0)
55 greg 1.13 source = (SRCREC *)malloc(SRCINC*sizeof(SRCREC));
56     else if (nsources%SRCINC == 0)
57 greg 2.11 source = (SRCREC *)realloc((void *)source,
58 greg 1.13 (unsigned)(nsources+SRCINC)*sizeof(SRCREC));
59 greg 1.1 if (source == NULL)
60 greg 1.2 return(-1);
61 greg 1.1 source[nsources].sflags = 0;
62     source[nsources].nhits = 1;
63     source[nsources].ntests = 2; /* initial hit probability = 1/2 */
64 greg 2.12 #if SHADCACHE
65     source[nsources].obscache = NULL;
66     #endif
67 greg 1.2 return(nsources++);
68 greg 1.1 }
69    
70    
71 greg 2.9 void
72 greg 1.14 setflatss(src) /* set sampling for a flat source */
73     register SRCREC *src;
74     {
75     double mult;
76     register int i;
77    
78     src->ss[SV][0] = src->ss[SV][1] = src->ss[SV][2] = 0.0;
79     for (i = 0; i < 3; i++)
80     if (src->snorm[i] < 0.6 && src->snorm[i] > -0.6)
81     break;
82     src->ss[SV][i] = 1.0;
83     fcross(src->ss[SU], src->ss[SV], src->snorm);
84     mult = .5 * sqrt( src->ss2 / DOT(src->ss[SU],src->ss[SU]) );
85     for (i = 0; i < 3; i++)
86     src->ss[SU][i] *= mult;
87     fcross(src->ss[SV], src->snorm, src->ss[SU]);
88     }
89    
90    
91 greg 2.9 void
92 greg 1.1 fsetsrc(src, so) /* set a face as a source */
93     register SRCREC *src;
94     OBJREC *so;
95     {
96     register FACE *f;
97     register int i, j;
98 greg 1.14 double d;
99 greg 1.1
100     src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
101     src->so = so;
102     /* get the face */
103     f = getface(so);
104     /* find the center */
105     for (j = 0; j < 3; j++) {
106     src->sloc[j] = 0.0;
107     for (i = 0; i < f->nv; i++)
108     src->sloc[j] += VERTEX(f,i)[j];
109     src->sloc[j] /= (double)f->nv;
110     }
111     if (!inface(src->sloc, f))
112     objerror(so, USER, "cannot hit center");
113     src->sflags |= SFLAT;
114     VCOPY(src->snorm, f->norm);
115     src->ss2 = f->area;
116 greg 1.14 /* find maximum radius */
117     src->srad = 0.;
118     for (i = 0; i < f->nv; i++) {
119     d = dist2(VERTEX(f,i), src->sloc);
120     if (d > src->srad)
121     src->srad = d;
122     }
123     src->srad = sqrt(src->srad);
124     /* compute size vectors */
125 greg 2.7 if (f->nv == 4) /* parallelogram case */
126 greg 1.14 for (j = 0; j < 3; j++) {
127     src->ss[SU][j] = .5*(VERTEX(f,1)[j]-VERTEX(f,0)[j]);
128     src->ss[SV][j] = .5*(VERTEX(f,3)[j]-VERTEX(f,0)[j]);
129     }
130     else
131     setflatss(src);
132 greg 1.1 }
133    
134    
135 greg 2.9 void
136 greg 1.1 ssetsrc(src, so) /* set a source as a source */
137     register SRCREC *src;
138     register OBJREC *so;
139     {
140     double theta;
141    
142     src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
143     src->so = so;
144     if (so->oargs.nfargs != 4)
145     objerror(so, USER, "bad arguments");
146     src->sflags |= SDISTANT;
147     VCOPY(src->sloc, so->oargs.farg);
148     if (normalize(src->sloc) == 0.0)
149     objerror(so, USER, "zero direction");
150     theta = PI/180.0/2.0 * so->oargs.farg[3];
151     if (theta <= FTINY)
152     objerror(so, USER, "zero size");
153     src->ss2 = 2.0*PI * (1.0 - cos(theta));
154 greg 1.14 /* the following is approximate */
155     src->srad = sqrt(src->ss2/PI);
156     VCOPY(src->snorm, src->sloc);
157     setflatss(src); /* hey, whatever works */
158     src->ss[SW][0] = src->ss[SW][1] = src->ss[SW][2] = 0.0;
159 greg 1.1 }
160    
161    
162 greg 2.9 void
163 greg 1.1 sphsetsrc(src, so) /* set a sphere as a source */
164     register SRCREC *src;
165     register OBJREC *so;
166     {
167 greg 1.14 register int i;
168    
169 greg 1.1 src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
170     src->so = so;
171     if (so->oargs.nfargs != 4)
172     objerror(so, USER, "bad # arguments");
173     if (so->oargs.farg[3] <= FTINY)
174     objerror(so, USER, "illegal radius");
175     VCOPY(src->sloc, so->oargs.farg);
176 greg 1.14 src->srad = so->oargs.farg[3];
177     src->ss2 = PI * src->srad * src->srad;
178     for (i = 0; i < 3; i++)
179     src->ss[SU][i] = src->ss[SV][i] = src->ss[SW][i] = 0.0;
180     for (i = 0; i < 3; i++)
181 greg 1.15 src->ss[i][i] = .7236 * so->oargs.farg[3];
182 greg 1.1 }
183    
184    
185 greg 2.9 void
186 greg 1.1 rsetsrc(src, so) /* set a ring (disk) as a source */
187     register SRCREC *src;
188     OBJREC *so;
189     {
190     register CONE *co;
191    
192     src->sa.success = 2*AIMREQT-1; /* bitch on second failure */
193     src->so = so;
194     /* get the ring */
195     co = getcone(so, 0);
196     VCOPY(src->sloc, CO_P0(co));
197     if (CO_R0(co) > 0.0)
198     objerror(so, USER, "cannot hit center");
199     src->sflags |= SFLAT;
200     VCOPY(src->snorm, co->ad);
201 greg 1.14 src->srad = CO_R1(co);
202     src->ss2 = PI * src->srad * src->srad;
203     setflatss(src);
204     }
205    
206    
207 greg 2.9 void
208 greg 1.14 cylsetsrc(src, so) /* set a cylinder as a source */
209     register SRCREC *src;
210     OBJREC *so;
211     {
212     register CONE *co;
213     register int i;
214    
215     src->sa.success = 4*AIMREQT-1; /* bitch on fourth failure */
216     src->so = so;
217     /* get the cylinder */
218     co = getcone(so, 0);
219     if (CO_R0(co) > .2*co->al) /* heuristic constraint */
220     objerror(so, WARNING, "source aspect too small");
221 greg 1.15 src->sflags |= SCYL;
222 greg 1.14 for (i = 0; i < 3; i++)
223     src->sloc[i] = .5 * (CO_P1(co)[i] + CO_P0(co)[i]);
224 greg 1.15 src->srad = .5*co->al;
225 greg 1.14 src->ss2 = 2.*CO_R0(co)*co->al;
226     /* set sampling vectors */
227     for (i = 0; i < 3; i++)
228     src->ss[SU][i] = .5 * co->al * co->ad[i];
229     src->ss[SV][0] = src->ss[SV][1] = src->ss[SV][2] = 0.0;
230     for (i = 0; i < 3; i++)
231     if (co->ad[i] < 0.6 && co->ad[i] > -0.6)
232     break;
233     src->ss[SV][i] = 1.0;
234     fcross(src->ss[SW], src->ss[SV], co->ad);
235     normalize(src->ss[SW]);
236     for (i = 0; i < 3; i++)
237 greg 1.15 src->ss[SW][i] *= .8559 * CO_R0(co);
238 greg 1.14 fcross(src->ss[SV], src->ss[SW], co->ad);
239 greg 1.1 }
240    
241    
242     SPOT *
243     makespot(m) /* make a spotlight */
244     register OBJREC *m;
245     {
246     register SPOT *ns;
247    
248 greg 2.5 if ((ns = (SPOT *)m->os) != NULL)
249     return(ns);
250 greg 1.1 if ((ns = (SPOT *)malloc(sizeof(SPOT))) == NULL)
251     return(NULL);
252     ns->siz = 2.0*PI * (1.0 - cos(PI/180.0/2.0 * m->oargs.farg[3]));
253     VCOPY(ns->aim, m->oargs.farg+4);
254     if ((ns->flen = normalize(ns->aim)) == 0.0)
255     objerror(m, USER, "zero focus vector");
256 greg 2.5 m->os = (char *)ns;
257 greg 1.1 return(ns);
258     }
259    
260    
261 greg 2.9 int
262 greg 2.8 spotout(r, s) /* check if we're outside spot region */
263 greg 2.5 register RAY *r;
264     register SPOT *s;
265     {
266     double d;
267     FVECT vd;
268    
269     if (s == NULL)
270     return(0);
271 greg 2.8 if (s->flen < -FTINY) { /* distant source */
272 greg 2.5 vd[0] = s->aim[0] - r->rorg[0];
273     vd[1] = s->aim[1] - r->rorg[1];
274     vd[2] = s->aim[2] - r->rorg[2];
275     d = DOT(r->rdir,vd);
276     /* wrong side?
277     if (d <= FTINY)
278     return(1); */
279     d = DOT(vd,vd) - d*d;
280     if (PI*d > s->siz)
281     return(1); /* out */
282     return(0); /* OK */
283     }
284     /* local source */
285     if (s->siz < 2.0*PI * (1.0 + DOT(s->aim,r->rdir)))
286     return(1); /* out */
287     return(0); /* OK */
288     }
289    
290    
291 greg 1.1 double
292     fgetmaxdisk(ocent, op) /* get center and squared radius of face */
293     FVECT ocent;
294     OBJREC *op;
295     {
296     double maxrad2;
297 greg 1.5 double d;
298 greg 1.1 register int i, j;
299     register FACE *f;
300    
301     f = getface(op);
302 greg 1.5 if (f->area == 0.)
303     return(0.);
304 greg 1.1 for (i = 0; i < 3; i++) {
305     ocent[i] = 0.;
306     for (j = 0; j < f->nv; j++)
307     ocent[i] += VERTEX(f,j)[i];
308     ocent[i] /= (double)f->nv;
309     }
310 greg 1.5 d = DOT(ocent,f->norm);
311     for (i = 0; i < 3; i++)
312     ocent[i] += (f->offset - d)*f->norm[i];
313 greg 1.1 maxrad2 = 0.;
314     for (j = 0; j < f->nv; j++) {
315 greg 1.5 d = dist2(VERTEX(f,j), ocent);
316     if (d > maxrad2)
317     maxrad2 = d;
318 greg 1.1 }
319     return(maxrad2);
320     }
321    
322    
323     double
324     rgetmaxdisk(ocent, op) /* get center and squared radius of ring */
325     FVECT ocent;
326     OBJREC *op;
327     {
328     register CONE *co;
329    
330     co = getcone(op, 0);
331     VCOPY(ocent, CO_P0(co));
332     return(CO_R1(co)*CO_R1(co));
333     }
334    
335    
336     double
337     fgetplaneq(nvec, op) /* get plane equation for face */
338     FVECT nvec;
339     OBJREC *op;
340     {
341     register FACE *fo;
342    
343     fo = getface(op);
344     VCOPY(nvec, fo->norm);
345     return(fo->offset);
346     }
347    
348    
349     double
350     rgetplaneq(nvec, op) /* get plane equation for ring */
351     FVECT nvec;
352     OBJREC *op;
353     {
354     register CONE *co;
355    
356     co = getcone(op, 0);
357     VCOPY(nvec, co->ad);
358     return(DOT(nvec, CO_P0(co)));
359 greg 1.4 }
360    
361    
362 greg 2.9 int
363 greg 1.4 commonspot(sp1, sp2, org) /* set sp1 to intersection of sp1 and sp2 */
364     register SPOT *sp1, *sp2;
365     FVECT org;
366     {
367     FVECT cent;
368     double rad2, cos1, cos2;
369    
370     cos1 = 1. - sp1->siz/(2.*PI);
371     cos2 = 1. - sp2->siz/(2.*PI);
372     if (sp2->siz >= 2.*PI-FTINY) /* BIG, just check overlap */
373     return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
374     sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
375     /* compute and check disks */
376     rad2 = intercircle(cent, sp1->aim, sp2->aim,
377     1./(cos1*cos1) - 1., 1./(cos2*cos2) - 1.);
378     if (rad2 <= FTINY || normalize(cent) == 0.)
379     return(0);
380     VCOPY(sp1->aim, cent);
381     sp1->siz = 2.*PI*(1. - 1./sqrt(1.+rad2));
382     return(1);
383     }
384    
385    
386 greg 2.9 int
387 greg 1.4 commonbeam(sp1, sp2, dir) /* set sp1 to intersection of sp1 and sp2 */
388     register SPOT *sp1, *sp2;
389     FVECT dir;
390     {
391     FVECT cent, c1, c2;
392     double rad2, d;
393     register int i;
394     /* move centers to common plane */
395     d = DOT(sp1->aim, dir);
396     for (i = 0; i < 3; i++)
397     c1[i] = sp1->aim[i] - d*dir[i];
398     d = DOT(sp2->aim, dir);
399     for (i = 0; i < 3; i++)
400     c2[i] = sp2->aim[i] - d*dir[i];
401     /* compute overlap */
402     rad2 = intercircle(cent, c1, c2, sp1->siz/PI, sp2->siz/PI);
403     if (rad2 <= FTINY)
404     return(0);
405     VCOPY(sp1->aim, cent);
406     sp1->siz = PI*rad2;
407     return(1);
408     }
409    
410    
411 greg 2.9 int
412 greg 1.4 checkspot(sp, nrm) /* check spotlight for behind source */
413     register SPOT *sp; /* spotlight */
414     FVECT nrm; /* source surface normal */
415     {
416     double d, d1;
417    
418     d = DOT(sp->aim, nrm);
419     if (d > FTINY) /* center in front? */
420 greg 1.8 return(1);
421 greg 1.4 /* else check horizon */
422     d1 = 1. - sp->siz/(2.*PI);
423 greg 1.8 return(1.-FTINY-d*d < d1*d1);
424 greg 1.4 }
425    
426    
427     double
428 greg 1.6 spotdisk(oc, op, sp, pos) /* intersect spot with object op */
429     FVECT oc;
430     OBJREC *op;
431     register SPOT *sp;
432     FVECT pos;
433     {
434     FVECT onorm;
435     double offs, d, dist;
436     register int i;
437    
438     offs = getplaneq(onorm, op);
439     d = -DOT(onorm, sp->aim);
440     if (d >= -FTINY && d <= FTINY)
441     return(0.);
442     dist = (DOT(pos, onorm) - offs)/d;
443     if (dist < 0.)
444     return(0.);
445     for (i = 0; i < 3; i++)
446     oc[i] = pos[i] + dist*sp->aim[i];
447     return(sp->siz*dist*dist/PI/(d*d));
448     }
449    
450    
451     double
452     beamdisk(oc, op, sp, dir) /* intersect beam with object op */
453     FVECT oc;
454     OBJREC *op;
455     register SPOT *sp;
456     FVECT dir;
457     {
458     FVECT onorm;
459     double offs, d, dist;
460     register int i;
461    
462     offs = getplaneq(onorm, op);
463     d = -DOT(onorm, dir);
464     if (d >= -FTINY && d <= FTINY)
465     return(0.);
466     dist = (DOT(sp->aim, onorm) - offs)/d;
467     for (i = 0; i < 3; i++)
468     oc[i] = sp->aim[i] + dist*dir[i];
469     return(sp->siz/PI/(d*d));
470     }
471    
472    
473     double
474 greg 1.4 intercircle(cc, c1, c2, r1s, r2s) /* intersect two circles */
475     FVECT cc; /* midpoint (return value) */
476     FVECT c1, c2; /* circle centers */
477     double r1s, r2s; /* radii squared */
478     {
479     double a2, d2, l;
480     FVECT disp;
481     register int i;
482    
483     for (i = 0; i < 3; i++)
484     disp[i] = c2[i] - c1[i];
485     d2 = DOT(disp,disp);
486     /* circle within overlap? */
487     if (r1s < r2s) {
488     if (r2s >= r1s + d2) {
489     VCOPY(cc, c1);
490     return(r1s);
491     }
492     } else {
493     if (r1s >= r2s + d2) {
494     VCOPY(cc, c2);
495     return(r2s);
496     }
497     }
498     a2 = .25*(2.*(r1s+r2s) - d2 - (r2s-r1s)*(r2s-r1s)/d2);
499     /* no overlap? */
500     if (a2 <= 0.)
501     return(0.);
502     /* overlap, compute center */
503     l = sqrt((r1s - a2)/d2);
504     for (i = 0; i < 3; i++)
505     cc[i] = c1[i] + l*disp[i];
506     return(a2);
507 greg 1.1 }