ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/raytrace.c
Revision: 1.1
Committed: Thu Feb 2 10:41:34 1989 UTC (35 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# Content
1 /* Copyright (c) 1986 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * raytrace.c - routines for tracing and shading rays.
9 *
10 * 8/7/85
11 */
12
13 #include "ray.h"
14
15 #include "octree.h"
16
17 #include "otypes.h"
18
19 extern CUBE thescene; /* our scene */
20 extern int maxdepth; /* maximum recursion depth */
21 extern double minweight; /* minimum ray weight */
22
23 long nrays = 0L; /* number of rays traced */
24
25 #define MAXLOOP 32 /* modifier loop detection */
26
27 #define RAYHIT (-1) /* return value for intercepted ray */
28
29
30 rayorigin(r, ro, rt, rw) /* start new ray from old one */
31 register RAY *r, *ro;
32 int rt;
33 double rw;
34 {
35 if ((r->parent = ro) == NULL) { /* primary ray */
36 r->rlvl = 0;
37 r->rweight = rw;
38 r->crtype = r->rtype = rt;
39 r->rsrc = -1;
40 r->clipset = NULL;
41 } else { /* spawned ray */
42 r->rlvl = ro->rlvl;
43 if (rt & RAYREFL) {
44 r->rlvl++;
45 r->rsrc = -1;
46 r->clipset = ro->clipset;
47 } else {
48 r->rsrc = ro->rsrc;
49 r->clipset = ro->newcset;
50 }
51 r->rweight = ro->rweight * rw;
52 r->crtype = ro->crtype | (r->rtype = rt);
53 VCOPY(r->rorg, ro->rop);
54 }
55 r->rno = nrays;
56 r->newcset = r->clipset;
57 r->ro = NULL;
58 r->rot = FHUGE;
59 r->ros = 1.0; setident4(r->rox);
60 r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
61 setcolor(r->pcol, 1.0, 1.0, 1.0);
62 setcolor(r->rcol, 0.0, 0.0, 0.0);
63 return(r->rlvl <= maxdepth && r->rweight >= minweight ? 0 : -1);
64 }
65
66
67 rayvalue(r) /* compute a ray's value */
68 register RAY *r;
69 {
70 extern int (*trace)();
71
72 if (localhit(r, &thescene))
73 if (r->clipset != NULL && inset(r->clipset, r->ro->omod))
74 raytrans(r); /* object is clipped */
75 else
76 rayshade(r, r->ro->omod);
77 else if (sourcehit(r))
78 rayshade(r, r->ro->omod);
79
80 if (trace != NULL)
81 (*trace)(r); /* trace execution */
82 }
83
84
85 raytrans(r) /* transmit ray as is */
86 RAY *r;
87 {
88 RAY tr;
89
90 if (rayorigin(&tr, r, TRANS, 1.0) == 0) {
91 VCOPY(tr.rdir, r->rdir);
92 rayvalue(&tr);
93 copycolor(r->rcol, tr.rcol);
94 }
95 }
96
97
98 rayshade(r, mod) /* shade ray r with material mod */
99 register RAY *r;
100 int mod;
101 {
102 static int depth = 0;
103 register OBJREC *m;
104 /* check for infinite loop */
105 if (depth++ >= MAXLOOP)
106 objerror(r->ro, USER, "material loop");
107 for ( ; mod != OVOID; mod = m->omod) {
108 m = objptr(mod);
109 if (!ismodifier(m->otype)) {
110 sprintf(errmsg, "illegal modifier \"%s\"", m->oname);
111 error(USER, errmsg);
112 }
113 (*ofun[m->otype].funp)(m, r); /* execute function */
114 m->lastrno = r->rno;
115 if (ismaterial(m->otype)) { /* materials call raytexture */
116 depth--;
117 return; /* we're done */
118 }
119 }
120 objerror(r->ro, USER, "material not found");
121 }
122
123
124 raytexture(r, mod) /* get material modifiers */
125 RAY *r;
126 int mod;
127 {
128 static int depth = 0;
129 register OBJREC *m;
130 /* check for infinite loop */
131 if (depth++ >= MAXLOOP)
132 objerror(r->ro, USER, "modifier loop");
133 /* execute textures and patterns */
134 for ( ; mod != OVOID; mod = m->omod) {
135 m = objptr(mod);
136 if (!istexture(m->otype)) {
137 sprintf(errmsg, "illegal modifier \"%s\"", m->oname);
138 error(USER, errmsg);
139 }
140 (*ofun[m->otype].funp)(m, r);
141 m->lastrno = r->rno;
142 }
143 depth--; /* end here */
144 }
145
146
147 raymixture(r, fore, back, coef) /* mix modifiers */
148 register RAY *r;
149 OBJECT fore, back;
150 double coef;
151 {
152 FVECT curpert, forepert, backpert;
153 COLOR curpcol, forepcol, backpcol;
154 register int i;
155 /* clip coefficient */
156 if (coef > 1.0)
157 coef = 1.0;
158 else if (coef < 0.0)
159 coef = 0.0;
160 /* save current mods */
161 VCOPY(curpert, r->pert);
162 copycolor(curpcol, r->pcol);
163 /* compute new mods */
164 /* foreground */
165 r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
166 setcolor(r->pcol, 1.0, 1.0, 1.0);
167 if (fore != OVOID && coef > FTINY)
168 raytexture(r, fore);
169 VCOPY(forepert, r->pert);
170 copycolor(forepcol, r->pcol);
171 /* background */
172 r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
173 setcolor(r->pcol, 1.0, 1.0, 1.0);
174 if (back != OVOID && coef < 1.0-FTINY)
175 raytexture(r, back);
176 VCOPY(backpert, r->pert);
177 copycolor(backpcol, r->pcol);
178 /* sum perturbations */
179 for (i = 0; i < 3; i++)
180 r->pert[i] = curpert[i] + coef*forepert[i] +
181 (1.0-coef)*backpert[i];
182 /* multiply colors */
183 setcolor(r->pcol, coef*colval(forepcol,RED) +
184 (1.0-coef)*colval(backpcol,RED),
185 coef*colval(forepcol,GRN) +
186 (1.0-coef)*colval(backpcol,GRN),
187 coef*colval(forepcol,BLU) +
188 (1.0-coef)*colval(backpcol,BLU));
189 multcolor(r->pcol, curpcol);
190 }
191
192
193 double
194 raynormal(norm, r) /* compute perturbed normal for ray */
195 FVECT norm;
196 register RAY *r;
197 {
198 double newdot;
199 register int i;
200
201 /* The perturbation is added to the surface normal to obtain
202 * the new normal. If the new normal would affect the surface
203 * orientation wrt. the ray, a correction is made. The method is
204 * still fraught with problems since reflected rays and similar
205 * directions calculated from the surface normal may spawn rays behind
206 * the surface. The only solution is to curb textures at high
207 * incidence (Rdot << 1).
208 */
209
210 for (i = 0; i < 3; i++)
211 norm[i] = r->ron[i] + r->pert[i];
212
213 if (normalize(norm) == 0.0) {
214 objerror(r->ro, WARNING, "illegal normal perturbation");
215 VCOPY(norm, r->ron);
216 return(r->rod);
217 }
218 newdot = -DOT(norm, r->rdir);
219 if ((newdot > 0.0) != (r->rod > 0.0)) { /* fix orientation */
220 for (i = 0; i < 3; i++)
221 norm[i] += 2.0*newdot*r->rdir[i];
222 newdot = -newdot;
223 }
224 return(newdot);
225 }
226
227
228 flipsurface(r) /* reverse surface orientation */
229 register RAY *r;
230 {
231 r->rod = -r->rod;
232 r->ron[0] = -r->ron[0];
233 r->ron[1] = -r->ron[1];
234 r->ron[2] = -r->ron[2];
235 r->pert[0] = -r->pert[0];
236 r->pert[1] = -r->pert[1];
237 r->pert[2] = -r->pert[2];
238 }
239
240
241 localhit(r, scene) /* check for hit in the octree */
242 register RAY *r;
243 register CUBE *scene;
244 {
245 FVECT curpos; /* current cube position */
246 int mpos, mneg; /* sign flags */
247 double t, dt;
248 register int i;
249
250 nrays++; /* increment trace counter */
251
252 mpos = mneg = 0;
253 for (i = 0; i < 3; i++) {
254 curpos[i] = r->rorg[i];
255 if (r->rdir[i] > FTINY)
256 mpos |= 1 << i;
257 else if (r->rdir[i] < -FTINY)
258 mneg |= 1 << i;
259 }
260 t = 0.0;
261 if (!incube(scene, curpos)) {
262 /* find distance to entry */
263 for (i = 0; i < 3; i++) {
264 /* plane in our direction */
265 if (mpos & 1<<i)
266 dt = scene->cuorg[i];
267 else if (mneg & 1<<i)
268 dt = scene->cuorg[i] + scene->cusize;
269 else
270 continue;
271 /* distance to the plane */
272 dt = (dt - r->rorg[i])/r->rdir[i];
273 if (dt > t)
274 t = dt; /* farthest face is the one */
275 }
276 t += FTINY; /* fudge to get inside cube */
277 /* advance position */
278 for (i = 0; i < 3; i++)
279 curpos[i] += r->rdir[i]*t;
280
281 if (!incube(scene, curpos)) /* non-intersecting ray */
282 return(0);
283 }
284 return(raymove(curpos, mpos, mneg, r, scene) == RAYHIT);
285 }
286
287
288 static int
289 raymove(pos, plus, minus, r, cu) /* check for hit as we move */
290 FVECT pos; /* modified */
291 int plus, minus; /* direction indicators to speed tests */
292 register RAY *r;
293 register CUBE *cu;
294 {
295 int ax;
296 double dt, t;
297 register int sgn;
298
299 if (istree(cu->cutree)) { /* recurse on subcubes */
300 CUBE cukid;
301 register int br;
302
303 cukid.cusize = cu->cusize * 0.5; /* find subcube */
304 VCOPY(cukid.cuorg, cu->cuorg);
305 br = 0;
306 if (pos[0] >= cukid.cuorg[0]+cukid.cusize) {
307 cukid.cuorg[0] += cukid.cusize;
308 br |= 1;
309 }
310 if (pos[1] >= cukid.cuorg[1]+cukid.cusize) {
311 cukid.cuorg[1] += cukid.cusize;
312 br |= 2;
313 }
314 if (pos[2] >= cukid.cuorg[2]+cukid.cusize) {
315 cukid.cuorg[2] += cukid.cusize;
316 br |= 4;
317 }
318 for ( ; ; ) {
319 cukid.cutree = octkid(cu->cutree, br);
320 if ((ax = raymove(pos,plus,minus,r,&cukid)) == RAYHIT)
321 return(RAYHIT);
322 sgn = 1 << ax;
323 if (sgn & minus) /* negative axis? */
324 if (sgn & br) {
325 cukid.cuorg[ax] -= cukid.cusize;
326 br &= ~sgn;
327 } else
328 return(ax); /* underflow */
329 else
330 if (sgn & br)
331 return(ax); /* overflow */
332 else {
333 cukid.cuorg[ax] += cukid.cusize;
334 br |= sgn;
335 }
336 }
337 /*NOTREACHED*/
338 }
339 if (isfull(cu->cutree) && checkhit(r, cu))
340 return(RAYHIT);
341 /* advance to next cube */
342 sgn = plus | minus;
343 if (sgn&1) {
344 dt = plus&1 ? cu->cuorg[0] + cu->cusize : cu->cuorg[0];
345 t = (dt - pos[0])/r->rdir[0];
346 ax = 0;
347 } else
348 t = FHUGE;
349 if (sgn&2) {
350 dt = plus&2 ? cu->cuorg[1] + cu->cusize : cu->cuorg[1];
351 dt = (dt - pos[1])/r->rdir[1];
352 if (dt < t) {
353 t = dt;
354 ax = 1;
355 }
356 }
357 if (sgn&4) {
358 dt = plus&4 ? cu->cuorg[2] + cu->cusize : cu->cuorg[2];
359 dt = (dt - pos[2])/r->rdir[2];
360 if (dt < t) {
361 t = dt;
362 ax = 2;
363 }
364 }
365 pos[0] += r->rdir[0]*t;
366 pos[1] += r->rdir[1]*t;
367 pos[2] += r->rdir[2]*t;
368 return(ax);
369 }
370
371
372 static
373 checkhit(r, cu) /* check for hit in full cube */
374 register RAY *r;
375 CUBE *cu;
376 {
377 OBJECT oset[MAXSET+1];
378 register OBJREC *o;
379 register int i;
380
381 objset(oset, cu->cutree);
382 for (i = oset[0]; i > 0; i--) {
383 o = objptr(oset[i]);
384 if (o->lastrno == r->rno) /* checked already? */
385 continue;
386 (*ofun[o->otype].funp)(o, r);
387 o->lastrno = r->rno;
388 }
389 if (r->ro == NULL)
390 return(0); /* no scores yet */
391
392 return(incube(cu, r->rop)); /* hit OK if in current cube */
393 }