ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcobstr.c
Revision: 2.10
Committed: Fri Sep 10 17:08:36 2004 UTC (19 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6
Changes since 2.9: +9 -8 lines
Log Message:
Fixed bug in last fix -- distant sources weren't working

File Contents

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