ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcobstr.c
Revision: 2.13
Committed: Wed Jul 25 04:12:36 2007 UTC (16 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.12: +39 -1 lines
Log Message:
Fixed bug in shadow cache related to antimatter holes

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.13 static const char RCSid[] = "$Id: srcobstr.c,v 2.12 2005/04/19 01:15:07 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Source occlusion caching routines
6     */
7    
8     #include "ray.h"
9    
10     #include "otypes.h"
11    
12     #include "otspecial.h"
13    
14     #include "source.h"
15    
16     #define ABS(x) ((x)>0 ? (x) : -(x))
17    
18    
19     #if SHADCACHE /* preemptive shadow checking */
20    
21    
22 greg 2.13 OBJECT * antimodlist = NULL; /* set of clipped materials */
23    
24    
25 greg 2.7 static int /* cast source ray to first blocker */
26 greg 2.1 castshadow(int sn, FVECT rorg, FVECT rdir)
27     {
28     RAY rt;
29    
30     VCOPY(rt.rorg, rorg);
31     VCOPY(rt.rdir, rdir);
32     rt.rmax = 0;
33 greg 2.12 rayorigin(&rt, PRIMARY, NULL, NULL);
34 greg 2.7 /* check for intersection */
35     while (localhit(&rt, &thescene)) {
36     RAY rt1 = rt; /* pretend we were aimed at source */
37     rt1.crtype |= rt1.rtype = SHADOW;
38     rt1.rdir[0] = -rt.rdir[0];
39     rt1.rdir[1] = -rt.rdir[1];
40     rt1.rdir[2] = -rt.rdir[2];
41     rt1.rod = -rt.rod;
42     VSUB(rt1.rorg, rt.rop, rt.rdir);
43     rt1.rot = 1.;
44     rt1.rsrc = sn;
45 greg 2.1 /* record blocker */
46 greg 2.7 if (srcblocker(&rt1))
47     return(1);
48     /* move past failed blocker */
49     VSUM(rt.rorg, rt.rop, rt.rdir, FTINY);
50     rayclear(&rt); /* & try again... */
51     }
52     return(0); /* found no blockers */
53 greg 2.1 }
54    
55    
56 greg 2.8 void /* initialize occlusion cache */
57 greg 2.1 initobscache(int sn)
58     {
59     register SRCREC *srcp = &source[sn];
60     int cachelen;
61     FVECT rorg, rdir;
62     RREAL d;
63     int i, j, k;
64     int ax, ax1, ax2;
65    
66 greg 2.8 if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
67     return; /* don't cache these */
68 greg 2.1 if (srcp->sflags & SDISTANT)
69     cachelen = 4*SHADCACHE*SHADCACHE;
70     else if (srcp->sflags & SFLAT)
71     cachelen = SHADCACHE*SHADCACHE*3 + (SHADCACHE&1)*SHADCACHE*4;
72     else /* spherical distribution */
73     cachelen = SHADCACHE*SHADCACHE*6;
74     /* allocate cache */
75     srcp->obscache = (OBSCACHE *)malloc(sizeof(OBSCACHE) +
76     sizeof(OBJECT)*(cachelen-1));
77     if (srcp->obscache == NULL)
78     error(SYSTEM, "out of memory in initobscache()");
79     /* set parameters */
80     if (srcp->sflags & SDISTANT) {
81     RREAL amax = 0;
82     for (ax1 = 3; ax1--; )
83     if (ABS(srcp->sloc[ax1]) > amax) {
84     amax = ABS(srcp->sloc[ax1]);
85     ax = ax1;
86     }
87     srcp->obscache->p.d.ax = ax;
88     ax1 = (ax+1)%3;
89     ax2 = (ax+2)%3;
90     VCOPY(srcp->obscache->p.d.o, thescene.cuorg);
91     if (srcp->sloc[ax] > 0)
92     srcp->obscache->p.d.o[ax] += thescene.cusize;
93     if (srcp->sloc[ax1] < 0)
94     srcp->obscache->p.d.o[ax1] += thescene.cusize *
95     srcp->sloc[ax1] / amax;
96     if (srcp->sloc[ax2] < 0)
97     srcp->obscache->p.d.o[ax2] += thescene.cusize *
98     srcp->sloc[ax2] / amax;
99     srcp->obscache->p.d.e1 = 1. / (thescene.cusize*(1. +
100     fabs(srcp->sloc[ax1])/amax));
101     srcp->obscache->p.d.e2 = 1. / (thescene.cusize*(1. +
102     fabs(srcp->sloc[ax2])/amax));
103     } else if (srcp->sflags & SFLAT) {
104     VCOPY(srcp->obscache->p.f.u, srcp->ss[SU]);
105     normalize(srcp->obscache->p.f.u);
106     fcross(srcp->obscache->p.f.v,
107     srcp->snorm, srcp->obscache->p.f.u);
108     }
109     /* clear cache */
110     for (i = cachelen; i--; )
111     srcp->obscache->obs[i] = OVOID;
112     /* cast shadow rays */
113     if (srcp->sflags & SDISTANT) {
114     for (k = 3; k--; )
115     rdir[k] = -srcp->sloc[k];
116     for (i = 2*SHADCACHE; i--; )
117     for (j = 2*SHADCACHE; j--; ) {
118     VCOPY(rorg, srcp->obscache->p.d.o);
119     rorg[ax1] += (i+.5) /
120     (2*SHADCACHE*srcp->obscache->p.d.e1);
121     rorg[ax2] += (j+.5) /
122     (2*SHADCACHE*srcp->obscache->p.d.e2);
123     castshadow(sn, rorg, rdir);
124     }
125     } else if (srcp->sflags & SFLAT) {
126     d = 0.01*srcp->srad;
127     VSUM(rorg, srcp->sloc, srcp->snorm, d);
128     for (i = SHADCACHE; i--; )
129     for (j = SHADCACHE; j--; ) {
130     d = 2./SHADCACHE*(i+.5) - 1.;
131     VSUM(rdir, srcp->snorm,
132     srcp->obscache->p.f.u, d);
133     d = 2./SHADCACHE*(j+.5) - 1.;
134     VSUM(rdir, rdir, srcp->obscache->p.f.v, d);
135     normalize(rdir);
136     castshadow(sn, rorg, rdir);
137     }
138     for (k = 2; k--; )
139     for (i = SHADCACHE; i--; )
140     for (j = SHADCACHE>>1; j--; ) {
141     d = 2./SHADCACHE*(i+.5) - 1.;
142     if (k)
143     VSUM(rdir, srcp->obscache->p.f.u,
144     srcp->obscache->p.f.v, d);
145     else
146     VSUM(rdir, srcp->obscache->p.f.v,
147     srcp->obscache->p.f.u, d);
148 greg 2.3 d = 1. - 2./SHADCACHE*(j+.5);
149 greg 2.1 VSUM(rdir, rdir, srcp->snorm, d);
150     normalize(rdir);
151     castshadow(sn, rorg, rdir);
152     d = 2.*DOT(rdir, srcp->snorm);
153     rdir[0] = d*srcp->snorm[0] - rdir[0];
154     rdir[1] = d*srcp->snorm[1] - rdir[1];
155     rdir[2] = d*srcp->snorm[2] - rdir[2];
156     castshadow(sn, rorg, rdir);
157     }
158     } else /* spherical distribution */
159     for (k = 6; k--; ) {
160     ax = k%3;
161     ax1 = (k+1)%3;
162     ax2 = (k+2)%3;
163     for (i = SHADCACHE; i--; )
164     for (j = SHADCACHE; j--; ) {
165     rdir[0]=rdir[1]=rdir[2] = 0.;
166     rdir[ax] = k<3 ? 1. : -1.;
167     rdir[ax1] = 2./SHADCACHE*(i+.5) - 1.;
168     rdir[ax2] = 2./SHADCACHE*(j+.5) - 1.;
169     normalize(rdir);
170     d = 1.05*srcp->srad;
171     VSUM(rorg, srcp->sloc, rdir, d);
172     castshadow(sn, rorg, rdir);
173     }
174     }
175     }
176    
177    
178     static OBJECT * /* return occluder cache entry */
179     srcobstructp(register RAY *r)
180     {
181 greg 2.6 static unsigned long lastrno = ~0;
182 greg 2.1 static OBJECT noobs;
183 greg 2.6 static OBJECT *lastobjp;
184 greg 2.1 SRCREC *srcp;
185     int ondx;
186    
187 greg 2.6 noobs = OVOID;
188     if (r->rno == lastrno)
189     return lastobjp; /* just recall last pointer */
190 greg 2.1 DCHECK(r->rsrc < 0, CONSISTENCY,
191     "srcobstructp() called with unaimed ray");
192 greg 2.6 lastrno = r->rno;
193     lastobjp = &noobs;
194 greg 2.1 srcp = &source[r->rsrc];
195     if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
196     return(&noobs); /* don't cache these */
197     if (srcp->obscache == NULL) /* initialize cache */
198     initobscache(r->rsrc);
199     /* compute cache index */
200     if (srcp->sflags & SDISTANT) {
201     int ax, ax1, ax2;
202     double t;
203     ax = srcp->obscache->p.d.ax;
204     if ((ax1 = ax+1) >= 3) ax1 -= 3;
205     if ((ax2 = ax+2) >= 3) ax2 -= 3;
206     t = (srcp->obscache->p.d.o[ax] - r->rorg[ax]) / srcp->sloc[ax];
207     if (t <= FTINY)
208     return(&noobs); /* could happen if ray is outside */
209     ondx = 2*SHADCACHE*(int)(2*SHADCACHE*srcp->obscache->p.d.e1 *
210     (r->rorg[ax1] + t*srcp->sloc[ax1] -
211     srcp->obscache->p.d.o[ax1]));
212     ondx += (int)(2*SHADCACHE*srcp->obscache->p.d.e2 *
213     (r->rorg[ax2] + t*srcp->sloc[ax2] -
214     srcp->obscache->p.d.o[ax2]));
215 schorsch 2.4 if ((ondx < 0) | (ondx >= 4*SHADCACHE*SHADCACHE))
216 greg 2.1 return(&noobs); /* could happen if ray is outside */
217     } else if (srcp->sflags & SFLAT) {
218     FVECT sd;
219     RREAL sd0m, sd1m;
220     sd[0] = -DOT(r->rdir, srcp->obscache->p.f.u);
221     sd[1] = -DOT(r->rdir, srcp->obscache->p.f.v);
222     sd[2] = -DOT(r->rdir, srcp->snorm);
223     if (sd[2] < 0)
224     return(&noobs); /* shouldn't happen */
225     sd0m = ABS(sd[0]);
226     sd1m = ABS(sd[1]);
227     if (sd[2] >= sd0m && sd[2] >= sd1m) {
228     ondx = SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
229     (1. + sd[0]/sd[2]));
230     ondx += (int)(SHADCACHE*(.5-FTINY) *
231     (1. + sd[1]/sd[2]));
232     } else if (sd0m >= sd1m) {
233     ondx = SHADCACHE*SHADCACHE;
234     if (sd[0] < 0)
235     ondx += ((SHADCACHE+1)>>1)*SHADCACHE;
236     ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
237 greg 2.3 (1. - sd[2]/sd0m));
238 greg 2.1 ondx += (int)(SHADCACHE*(.5-FTINY) *
239     (1. + sd[1]/sd0m));
240     } else /* sd1m > sd0m */ {
241     ondx = SHADCACHE*SHADCACHE +
242     ((SHADCACHE+1)>>1)*SHADCACHE*2;
243     if (sd[1] < 0)
244     ondx += ((SHADCACHE+1)>>1)*SHADCACHE;
245     ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
246 greg 2.3 (1. - sd[2]/sd1m));
247 greg 2.1 ondx += (int)(SHADCACHE*(.5-FTINY) *
248     (1. + sd[0]/sd1m));
249     }
250 greg 2.6 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*3 +
251     (SHADCACHE&1)*SHADCACHE*4), CONSISTENCY,
252 greg 2.3 "flat source cache index out of bounds");
253 greg 2.1 } else /* spherical distribution */ {
254     int ax, ax1, ax2;
255     RREAL amax = 0;
256     for (ax1 = 3; ax1--; )
257     if (ABS(r->rdir[ax1]) > amax) {
258     amax = ABS(r->rdir[ax1]);
259     ax = ax1;
260     }
261     if ((ax1 = ax+1) >= 3) ax1 -= 3;
262     if ((ax2 = ax+2) >= 3) ax2 -= 3;
263     ondx = 2*SHADCACHE*SHADCACHE * ax;
264     if (r->rdir[ax] < 0)
265     ondx += SHADCACHE*SHADCACHE;
266     ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
267     (1. + r->rdir[ax1]/amax));
268     ondx += (int)(SHADCACHE*(.5-FTINY) *
269     (1. + r->rdir[ax2]/amax));
270 greg 2.6 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*6), CONSISTENCY,
271 greg 2.3 "radial source cache index out of bounds");
272 greg 2.1 }
273     /* return cache pointer */
274 greg 2.6 return(lastobjp = &srcp->obscache->obs[ondx]);
275 greg 2.1 }
276    
277    
278     void /* free obstruction cache */
279     freeobscache(SRCREC *srcp)
280     {
281     if (srcp->obscache == NULL)
282     return;
283     free((void *)srcp->obscache);
284     srcp->obscache = NULL;
285     }
286    
287    
288 greg 2.7 int /* record a source blocker */
289 greg 2.1 srcblocker(register RAY *r)
290     {
291     OBJREC *m;
292    
293     if (r->robj == OVOID || objptr(r->robj) != r->ro ||
294     isvolume(r->ro->otype))
295 greg 2.7 return(0); /* don't record complex blockers */
296 greg 2.11 if (r->rsrc < 0 || source[r->rsrc].so == r->ro)
297     return(0); /* just a mistake, that's all */
298 greg 2.13 if (antimodlist != NULL && inset(antimodlist, r->ro->omod))
299     return(0); /* could be clipped */
300 greg 2.1 m = findmaterial(r->ro);
301     if (m == NULL)
302 greg 2.7 return(0); /* no material?! */
303 greg 2.5 if (!isopaque(m->otype))
304 greg 2.7 return(0); /* material not a reliable blocker */
305 greg 2.1 *srcobstructp(r) = r->robj; /* else record obstructor */
306 greg 2.7 return(1);
307 greg 2.1 }
308    
309    
310     int /* check ray against cached blocker */
311     srcblocked(RAY *r)
312     {
313     OBJECT obs = *srcobstructp(r);
314     OBJREC *op;
315    
316     if (obs == OVOID)
317     return(0);
318 greg 2.10 op = objptr(obs); /* check blocker intersection */
319 greg 2.9 if (!(*ofun[op->otype].funp)(op, r))
320     return(0);
321 greg 2.10 if (source[r->rsrc].sflags & SDISTANT)
322     return(1);
323     op = source[r->rsrc].so; /* check source intersection */
324     if (!(*ofun[op->otype].funp)(op, r))
325     return(1);
326     rayclear(r);
327     return(0); /* source in front */
328 greg 2.1 }
329    
330    
331 greg 2.13 void /* record potentially clipped materials */
332     markclip(OBJREC *m)
333     {
334     OBJECT *set2add, *oldset;
335    
336     m_clip(m, NULL); /* initialize modifier list */
337     if ((set2add = (OBJECT *)m->os) == NULL || !set2add[0])
338     return;
339    
340     if (antimodlist == NULL) { /* start of list */
341     antimodlist = setsave(set2add);
342     return;
343     }
344     /* else add to previous list */
345     oldset = antimodlist;
346     antimodlist = (OBJECT *)malloc((oldset[0]+set2add[0]+1)*sizeof(OBJECT));
347     if (antimodlist == NULL)
348     error(SYSTEM, "out of memory in markclip");
349     setunion(antimodlist, oldset, set2add);
350     free((void *)oldset);
351     }
352    
353    
354     #else /* SHADCACHE */
355    
356    
357     void /* no-op also avoids linker warning */
358     markclip(OBJREC *m)
359     {
360     (void)m;
361     }
362    
363    
364 greg 2.1 #endif /* SHADCACHE */