ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
Revision: 1.7
Committed: Mon Jun 24 16:10:59 1991 UTC (32 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.6: +75 -99 lines
Log Message:
added virtual source visibility pretesting

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.7 #include "octree.h"
15    
16 greg 1.3 #include "otypes.h"
17    
18 greg 1.1 #include "source.h"
19    
20 greg 1.7 #include "random.h"
21 greg 1.1
22    
23 greg 1.7 #define DISKTFRAC 0.25 /* disk area pretest fraction */
24    
25     double getdisk();
26    
27 greg 1.1 static OBJECT *vobject; /* virtual source objects */
28     static int nvobjects = 0; /* number of virtual source objects */
29    
30    
31     markvirtuals() /* find and mark virtual sources */
32     {
33     register OBJREC *o;
34     register int i;
35     /* check number of direct relays */
36     if (directrelay <= 0)
37     return;
38     /* find virtual source objects */
39     for (i = 0; i < nobjects; i++) {
40     o = objptr(i);
41 greg 1.3 if (!issurface(o->otype) || o->omod == OVOID)
42 greg 1.1 continue;
43     if (!isvlight(objptr(o->omod)->otype))
44     continue;
45 greg 1.3 if (sfun[o->otype].of == NULL ||
46     sfun[o->otype].of->getpleq == NULL)
47     objerror(o, USER, "illegal material");
48 greg 1.1 if (nvobjects == 0)
49     vobject = (OBJECT *)malloc(sizeof(OBJECT));
50     else
51     vobject = (OBJECT *)realloc((char *)vobject,
52     (unsigned)(nvobjects+1)*sizeof(OBJECT));
53     if (vobject == NULL)
54     error(SYSTEM, "out of memory in addvirtuals");
55     vobject[nvobjects++] = i;
56     }
57     if (nvobjects == 0)
58     return;
59 greg 1.4 #ifdef DEBUG
60     fprintf(stderr, "found %d virtual source objects\n", nvobjects);
61     #endif
62 greg 1.1 /* append virtual sources */
63     for (i = nsources; i-- > 0; )
64 greg 1.7 addvirtuals(i, directrelay);
65 greg 1.1 /* done with our object list */
66     free((char *)vobject);
67     nvobjects = 0;
68     }
69    
70    
71 greg 1.4 addvirtuals(sn, nr) /* add virtuals associated with source */
72     int sn;
73 greg 1.1 int nr;
74     {
75     register int i;
76     /* check relay limit first */
77     if (nr <= 0)
78     return;
79 greg 1.7 if (source[sn].sflags & SSKIP)
80     return;
81 greg 1.1 /* check each virtual object for projection */
82     for (i = 0; i < nvobjects; i++)
83 greg 1.3 /* vproject() calls us recursively */
84 greg 1.4 vproject(objptr(vobject[i]), sn, nr-1);
85 greg 1.1 }
86    
87    
88 greg 1.4 vproject(o, sn, n) /* create projected source(s) if they exist */
89 greg 1.3 OBJREC *o;
90 greg 1.4 int sn;
91 greg 1.3 int n;
92     {
93     register int i;
94     register VSMATERIAL *vsmat;
95     MAT4 proj;
96 greg 1.4 int ns;
97    
98     if (o == source[sn].so) /* objects cannot project themselves */
99     return;
100 greg 1.3 /* get virtual source material */
101     vsmat = sfun[objptr(o->omod)->otype].mf;
102     /* project virtual sources */
103     for (i = 0; i < vsmat->nproj; i++)
104 greg 1.4 if ((*vsmat->vproj)(proj, o, &source[sn], i))
105     if ((ns = makevsrc(o, sn, proj)) >= 0) {
106     #ifdef DEBUG
107 greg 1.6 virtverb(ns, stderr);
108 greg 1.4 #endif
109 greg 1.3 addvirtuals(ns, n);
110 greg 1.4 }
111 greg 1.3 }
112    
113    
114 greg 1.4 int
115     makevsrc(op, sn, pm) /* make virtual source if reasonable */
116 greg 1.1 OBJREC *op;
117 greg 1.4 register int sn;
118 greg 1.1 MAT4 pm;
119     {
120 greg 1.6 FVECT nsloc, nsnorm, ocent;
121     double maxrad2;
122 greg 1.3 int nsflags;
123     double d1;
124 greg 1.1 SPOT theirspot, ourspot;
125     register int i;
126 greg 1.3
127 greg 1.6 nsflags = source[sn].sflags | (SVIRTUAL|SSPOT|SFOLLOW);
128 greg 1.1 /* get object center and max. radius */
129 greg 1.6 maxrad2 = getdisk(ocent, op, sn);
130     if (maxrad2 <= FTINY) /* too small? */
131     return(-1);
132 greg 1.1 /* get location and spot */
133 greg 1.4 if (source[sn].sflags & SDISTANT) { /* distant source */
134     if (source[sn].sflags & SPROX)
135 greg 1.5 return(-1); /* should never get here! */
136 greg 1.4 multv3(nsloc, source[sn].sloc, pm);
137 greg 1.6 VCOPY(ourspot.aim, ocent);
138     ourspot.siz = PI*maxrad2;
139     ourspot.flen = 0.;
140 greg 1.4 if (source[sn].sflags & SSPOT) {
141     copystruct(&theirspot, source[sn].sl.s);
142     multp3(theirspot.aim, source[sn].sl.s->aim, pm);
143 greg 1.6 if (!commonbeam(&ourspot, &theirspot, nsloc))
144 greg 1.5 return(-1); /* no overlap */
145 greg 1.1 }
146     } else { /* local source */
147 greg 1.4 multp3(nsloc, source[sn].sloc, pm);
148 greg 1.6 for (i = 0; i < 3; i++)
149     ourspot.aim[i] = ocent[i] - nsloc[i];
150     if ((d1 = normalize(ourspot.aim)) == 0.)
151     return(-1); /* at source!! */
152     if (source[sn].sflags & SPROX && d1 > source[sn].sl.prox)
153     return(-1); /* too far away */
154     ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
155     ourspot.flen = 0.;
156 greg 1.4 if (source[sn].sflags & SSPOT) {
157     copystruct(&theirspot, source[sn].sl.s);
158     multv3(theirspot.aim, source[sn].sl.s->aim, pm);
159 greg 1.6 if (!commonspot(&ourspot, &theirspot, nsloc))
160     return(-1); /* no overlap */
161     ourspot.flen = theirspot.flen;
162 greg 1.1 }
163 greg 1.4 if (source[sn].sflags & SFLAT) { /* behind source? */
164     multv3(nsnorm, source[sn].snorm, pm);
165 greg 1.6 if (checkspot(&ourspot, nsnorm) < 0)
166 greg 1.5 return(-1);
167 greg 1.1 }
168     }
169 greg 1.7 /* pretest visibility */
170     nsflags = vstestvis(nsflags, op, ocent, maxrad2, sn);
171     if (nsflags & SSKIP)
172     return(-1); /* obstructed */
173     /* it all checks out, so make it */
174 greg 1.6 if ((i = newsource()) < 0)
175 greg 1.1 goto memerr;
176 greg 1.6 source[i].sflags = nsflags;
177     VCOPY(source[i].sloc, nsloc);
178 greg 1.3 if (nsflags & SFLAT)
179 greg 1.6 VCOPY(source[i].snorm, nsnorm);
180     source[i].ss = source[sn].ss; source[i].ss2 = source[sn].ss2;
181     if ((source[i].sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
182     goto memerr;
183     copystruct(source[i].sl.s, &ourspot);
184 greg 1.3 if (nsflags & SPROX)
185 greg 1.6 source[i].sl.prox = source[sn].sl.prox;
186     source[i].sa.svnext = sn;
187     source[i].so = op;
188     return(i);
189 greg 1.1 memerr:
190     error(SYSTEM, "out of memory in makevsrc");
191     }
192    
193    
194 greg 1.6 double
195     getdisk(oc, op, sn) /* get visible object disk */
196     FVECT oc;
197     OBJREC *op;
198     register int sn;
199     {
200     double rad2, roffs, offs, d, rd, rdoto;
201     FVECT rnrm, nrm;
202     /* first, use object getdisk function */
203     rad2 = (*sfun[op->otype].of->getdisk)(oc, op);
204     if (!(source[sn].sflags & SVIRTUAL))
205     return(rad2); /* all done for normal source */
206     /* check for correct side of relay surface */
207     roffs = (*sfun[source[sn].so->otype].of->getpleq)(rnrm, source[sn].so);
208     rd = DOT(rnrm, source[sn].sloc); /* source projection */
209     if (!(source[sn].sflags & SDISTANT))
210     rd -= roffs;
211     d = DOT(rnrm, oc) - roffs; /* disk distance to relay plane */
212     if ((d > 0.) ^ (rd > 0.))
213     return(rad2); /* OK if opposite sides */
214     if (d*d >= rad2)
215     return(.0); /* no relay is possible */
216     /* we need a closer look */
217     offs = (*sfun[op->otype].of->getpleq)(nrm, op);
218     rdoto = DOT(rnrm, nrm);
219     if (d*d >= rad2*(1.-rdoto*rdoto))
220     return(0.); /* disk entirely on projection side */
221     /* should shrink disk but I'm lazy */
222     return(rad2);
223     }
224    
225    
226 greg 1.7 int
227     vstestvis(f, o, oc, or2, sn) /* pretest source visibility */
228     int f; /* virtual source flags */
229     OBJREC *o; /* relay object */
230     FVECT oc; /* relay object center */
231     double or2; /* relay object radius squared */
232     register int sn; /* target source number */
233 greg 1.1 {
234 greg 1.7 RAY sr;
235     FVECT onorm;
236     FVECT offsdir;
237     double or, d;
238     int nok, nhit;
239     register int i, n;
240     /* return if pretesting disabled */
241     if (vspretest <= 0)
242     return(f);
243     /* get surface normal */
244     (*sfun[o->otype].of->getpleq)(onorm, o);
245     /* set number of rays to sample */
246     if (source[sn].sflags & SDISTANT)
247     n = (2./3.*PI*PI)*or2/(thescene.cusize*thescene.cusize)*
248     vspretest + .5;
249     else
250     n = or2/dist2(oc,source[sn].sloc)*vspretest + .5;
251     if (n < 1) n = 1;
252     /* limit tests to central region */
253     or = DISKTFRAC*sqrt(or2);
254     /* sample */
255     nhit = nok = 0;
256     while (n-- > 0) {
257     samplendx++;
258     /*
259     * We're being real sloppy with our sample locations here.
260     */
261     for (i = 0; i < 3; i++)
262     offsdir[i] = or*(1. - 2.*urand(931*i+5821+n));
263     d = DOT(offsdir,onorm);
264     for (i = 0; i < 3; i++)
265     sr.rorg[i] = oc[i] + (1.-d)*offsdir[i];
266     /* check against source */
267     if (srcray(&sr, NULL, sn) == 0.0)
268     continue;
269     sr.revf = srcvalue;
270     rayvalue(&sr);
271     if (bright(sr.rcol) <= FTINY)
272     continue;
273     nok++;
274     /* check against obstructions */
275     srcray(&sr, NULL, sn);
276     rayvalue(&sr);
277     if (bright(sr.rcol) <= FTINY)
278     continue;
279     nhit++;
280 greg 1.1 }
281 greg 1.7 /* interpret results */
282     if (nhit == 0)
283     return(f | SSKIP); /* 0% hit rate: totally occluded */
284     if (nhit == nok)
285     return(f & ~SFOLLOW); /* 100% hit rate: no occlusion */
286     return(f); /* no comment */
287 greg 1.1 }
288 greg 1.7
289 greg 1.4
290     #ifdef DEBUG
291 greg 1.6 virtverb(sn, fp) /* print verbose description of virtual source */
292     register int sn;
293 greg 1.4 FILE *fp;
294     {
295     register int i;
296    
297     fprintf(fp, "%s virtual source %d in %s %s\n",
298 greg 1.6 source[sn].sflags & SDISTANT ? "distant" : "local",
299     sn, ofun[source[sn].so->otype].funame,
300     source[sn].so->oname);
301 greg 1.4 fprintf(fp, "\tat (%f,%f,%f)\n",
302 greg 1.6 source[sn].sloc[0], source[sn].sloc[1], source[sn].sloc[2]);
303 greg 1.4 fprintf(fp, "\tlinked to source %d (%s)\n",
304 greg 1.6 source[sn].sa.svnext, source[source[sn].sa.svnext].so->oname);
305     if (source[sn].sflags & SFOLLOW)
306 greg 1.4 fprintf(fp, "\talways followed\n");
307     else
308     fprintf(fp, "\tnever followed\n");
309 greg 1.6 if (!(source[sn].sflags & SSPOT))
310 greg 1.4 return;
311     fprintf(fp, "\twith spot aim (%f,%f,%f) and size %f\n",
312 greg 1.6 source[sn].sl.s->aim[0], source[sn].sl.s->aim[1],
313     source[sn].sl.s->aim[2], source[sn].sl.s->siz);
314 greg 1.4 }
315     #endif