ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcobstr.c
Revision: 2.19
Committed: Wed Feb 22 03:16:20 2017 UTC (7 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad5R1, rad5R3
Changes since 2.18: +10 -3 lines
Log Message:
Added MAX2SHADE macro to limit precheck time for source obstructions.

File Contents

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