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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: srcobstr.c,v 2.12 2005/04/19 01:15:07 greg Exp $";
3 #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 OBJECT * antimodlist = NULL; /* set of clipped materials */
23
24
25 static int /* cast source ray to first blocker */
26 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 rayorigin(&rt, PRIMARY, NULL, NULL);
34 /* 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 /* record blocker */
46 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 }
54
55
56 void /* initialize occlusion cache */
57 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 if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
67 return; /* don't cache these */
68 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 d = 1. - 2./SHADCACHE*(j+.5);
149 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 static unsigned long lastrno = ~0;
182 static OBJECT noobs;
183 static OBJECT *lastobjp;
184 SRCREC *srcp;
185 int ondx;
186
187 noobs = OVOID;
188 if (r->rno == lastrno)
189 return lastobjp; /* just recall last pointer */
190 DCHECK(r->rsrc < 0, CONSISTENCY,
191 "srcobstructp() called with unaimed ray");
192 lastrno = r->rno;
193 lastobjp = &noobs;
194 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 if ((ondx < 0) | (ondx >= 4*SHADCACHE*SHADCACHE))
216 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 (1. - sd[2]/sd0m));
238 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 (1. - sd[2]/sd1m));
247 ondx += (int)(SHADCACHE*(.5-FTINY) *
248 (1. + sd[0]/sd1m));
249 }
250 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*3 +
251 (SHADCACHE&1)*SHADCACHE*4), CONSISTENCY,
252 "flat source cache index out of bounds");
253 } 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 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*6), CONSISTENCY,
271 "radial source cache index out of bounds");
272 }
273 /* return cache pointer */
274 return(lastobjp = &srcp->obscache->obs[ondx]);
275 }
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 int /* record a source blocker */
289 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 return(0); /* don't record complex blockers */
296 if (r->rsrc < 0 || source[r->rsrc].so == r->ro)
297 return(0); /* just a mistake, that's all */
298 if (antimodlist != NULL && inset(antimodlist, r->ro->omod))
299 return(0); /* could be clipped */
300 m = findmaterial(r->ro);
301 if (m == NULL)
302 return(0); /* no material?! */
303 if (!isopaque(m->otype))
304 return(0); /* material not a reliable blocker */
305 *srcobstructp(r) = r->robj; /* else record obstructor */
306 return(1);
307 }
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 op = objptr(obs); /* check blocker intersection */
319 if (!(*ofun[op->otype].funp)(op, r))
320 return(0);
321 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 }
329
330
331 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 #endif /* SHADCACHE */