ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcobstr.c
Revision: 2.20
Committed: Fri Apr 5 01:10:26 2024 UTC (4 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.19: +2 -2 lines
Log Message:
fix: Improved tracking of reflected vs. transmitted rays for antimatter

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: srcobstr.c,v 2.19 2017/02/22 03:16:20 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 "rtotypes.h"
15
16 #include "source.h"
17
18 #if SHADCACHE /* preemptive shadow checking */
19
20 #ifndef MAX2SHADE
21 #define MAX2SHADE 200 /* limit # of sources to precheck */
22 #endif
23
24 #define ABS(x) ((x)>0 ? (x) : -(x))
25
26
27 OBJECT * antimodlist = NULL; /* set of clipped materials */
28
29
30 static int /* cast source ray to first blocker */
31 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 rayorigin(&rt, PRIMARY, NULL, NULL);
39 /* check for intersection */
40 while (localhit(&rt, &thescene)) {
41 RAY rt1 = rt; /* pretend we were aimed at source */
42 rt1.crtype |= rt1.rtype = RSHADOW;
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 /* record blocker */
51 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 }
59
60
61 void /* initialize occlusion cache */
62 initobscache(int sn)
63 {
64 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
71 if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
72 return; /* don't cache these */
73 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 #if (MAX2SHADE >= 0)
118 if (sn >= MAX2SHADE) /* limit on prechecking */
119 return;
120 #endif
121 /* 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 d = 1. - 2./SHADCACHE*(j+.5);
158 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 srcobstructp(RAY *r)
189 {
190 static RNUMBER lastrno = ~0;
191 static OBJECT noobs;
192 static OBJECT *lastobjp;
193 SRCREC *srcp;
194 int ondx;
195
196 noobs = OVOID;
197 if (r->rno == lastrno)
198 return lastobjp; /* just recall last pointer */
199 DCHECK(r->rsrc < 0, CONSISTENCY,
200 "srcobstructp() called with unaimed ray");
201 lastrno = r->rno;
202 lastobjp = &noobs;
203 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 int ax=0, ax1=1, ax2=2;
211 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 if ((ondx < 0) | (ondx >= 4*SHADCACHE*SHADCACHE))
225 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 (1. - sd[2]/sd0m));
247 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 (1. - sd[2]/sd1m));
256 ondx += (int)(SHADCACHE*(.5-FTINY) *
257 (1. + sd[0]/sd1m));
258 }
259 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*3 +
260 (SHADCACHE&1)*SHADCACHE*4), CONSISTENCY,
261 "flat source cache index out of bounds");
262 } 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 DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*6), CONSISTENCY,
280 "radial source cache index out of bounds");
281 }
282 /* return cache pointer */
283 return(lastobjp = &srcp->obscache->obs[ondx]);
284 }
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 int /* record a source blocker */
298 srcblocker(RAY *r)
299 {
300 OBJREC *m;
301
302 if (r->robj == OVOID || objptr(r->robj) != r->ro ||
303 isvolume(r->ro->otype))
304 return(0); /* don't record complex blockers */
305 if (r->rsrc < 0 || source[r->rsrc].so == r->ro)
306 return(0); /* just a mistake, that's all */
307 if (antimodlist != NULL && inset(antimodlist, r->ro->omod))
308 return(0); /* could be clipped */
309 m = findmaterial(r->ro);
310 if (m == NULL)
311 return(0); /* no material?! */
312 if (!isopaque(m->otype))
313 return(0); /* material not a reliable blocker */
314 *srcobstructp(r) = r->robj; /* else record obstructor */
315 return(1);
316 }
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 op = objptr(obs); /* check blocker intersection */
328 if (!(*ofun[op->otype].funp)(op, r))
329 return(0);
330 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 }
338
339
340 void /* record potentially clipped materials */
341 markclip(OBJREC *m)
342 {
343 OBJECT *set2add, *oldset;
344
345 if (m == NULL) { /* starting over */
346 if (antimodlist != NULL)
347 free((void *)antimodlist);
348 antimodlist = NULL;
349 return;
350 }
351 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 #endif /* SHADCACHE */