1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "echo.h" |
25 |
|
|
#include "privateEcho.h" |
26 |
|
|
|
27 |
|
|
/* |
28 |
|
|
** TODO: do whatever possible to minimize the amount of work |
29 |
|
|
** needed for shadow rays |
30 |
|
|
*/ |
31 |
|
|
|
32 |
|
|
int _echoVerbose = 0; |
33 |
|
|
|
34 |
|
|
/* |
35 |
|
|
** ALL of the intersection functions are responsible for setting |
36 |
|
|
** 1) intx->norm to a NORMALIZED direction |
37 |
|
|
** 2) intx->t |
38 |
|
|
** 3) intx->obj |
39 |
|
|
** Specifically, these things must be set for non-shadow rays. Setting |
40 |
|
|
** them for shadow rays is optional. Setting intx->u and intx->v texture |
41 |
|
|
** coords is always optional. |
42 |
|
|
** |
43 |
|
|
** Setting intx->pos and intx->view (normalized) is done by echoRayIntx |
44 |
|
|
*/ |
45 |
|
|
|
46 |
|
|
int |
47 |
|
|
_echoRayIntx_Noop(RAYINTX_ARGS(Object)) { |
48 |
|
|
|
49 |
|
|
AIR_UNUSED(intx); |
50 |
|
|
AIR_UNUSED(ray); |
51 |
|
|
AIR_UNUSED(obj); |
52 |
|
|
AIR_UNUSED(parm); |
53 |
|
|
AIR_UNUSED(tstate); |
54 |
|
|
return 0; |
55 |
|
|
} |
56 |
|
|
|
57 |
|
|
int |
58 |
|
|
_echoRayIntx_CubeSurf(echoPos_t *tP, int *axP, int *dirP, |
59 |
|
|
echoPos_t xmin, echoPos_t xmax, |
60 |
|
|
echoPos_t ymin, echoPos_t ymax, |
61 |
|
|
echoPos_t zmin, echoPos_t zmax, |
62 |
|
|
echoRay *ray) { |
63 |
|
|
echoPos_t txmin, tymin, tzmin, txmax, tymax, tzmax, |
64 |
|
|
dx, dy, dz, ox, oy, oz, tmin, tmax; |
65 |
|
|
int axmin, axmax, sgn[3]; |
66 |
|
|
|
67 |
|
|
ELL_3V_GET(dx, dy, dz, ray->dir); |
68 |
|
|
ELL_3V_GET(ox, oy, oz, ray->from); |
69 |
|
|
if (dx >= 0) { txmin = (xmin - ox)/dx; txmax = (xmax - ox)/dx; sgn[0] = -1; } |
70 |
|
|
else { txmin = (xmax - ox)/dx; txmax = (xmin - ox)/dx; sgn[0] = 1; } |
71 |
|
|
if (dy >= 0) { tymin = (ymin - oy)/dy; tymax = (ymax - oy)/dy; sgn[1] = -1; } |
72 |
|
|
else { tymin = (ymax - oy)/dy; tymax = (ymin - oy)/dy; sgn[1] = 1; } |
73 |
|
|
if (dz >= 0) { tzmin = (zmin - oz)/dz; tzmax = (zmax - oz)/dz; sgn[2] = -1; } |
74 |
|
|
else { tzmin = (zmax - oz)/dz; tzmax = (zmin - oz)/dz; sgn[2] = 1; } |
75 |
|
|
if (txmin > tymin) { tmin = txmin; axmin = 0; } |
76 |
|
|
else { tmin = tymin; axmin = 1; } |
77 |
|
|
if (tzmin > tmin) { tmin = tzmin; axmin = 2; } |
78 |
|
|
if (txmax < tymax) { tmax = txmax; axmax = 0; } |
79 |
|
|
else { tmax = tymax; axmax = 1; } |
80 |
|
|
if (tzmax < tmax) { tmax = tzmax; axmax = 2; } |
81 |
|
|
if (tmin >= tmax) |
82 |
|
|
return AIR_FALSE; |
83 |
|
|
*tP = tmin; |
84 |
|
|
*axP = axmin; |
85 |
|
|
*dirP = sgn[axmin]; |
86 |
|
|
if (!AIR_IN_CL(ray->neer, tmin, ray->faar)) { |
87 |
|
|
*tP = tmax; |
88 |
|
|
*axP = axmax; |
89 |
|
|
*dirP = -sgn[axmax]; |
90 |
|
|
if (!AIR_IN_CL(ray->neer, tmax, ray->faar)) { |
91 |
|
|
return AIR_FALSE; |
92 |
|
|
} |
93 |
|
|
} |
94 |
|
|
return AIR_TRUE; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
int |
98 |
|
|
_echoRayIntx_CubeSolid(echoPos_t *tminP, echoPos_t *tmaxP, |
99 |
|
|
echoPos_t xmin, echoPos_t xmax, |
100 |
|
|
echoPos_t ymin, echoPos_t ymax, |
101 |
|
|
echoPos_t zmin, echoPos_t zmax, |
102 |
|
|
echoRay *ray) { |
103 |
|
|
echoPos_t txmin, tymin, tzmin, txmax, tymax, tzmax, |
104 |
|
|
dx, dy, dz, ox, oy, oz, tmin, tmax; |
105 |
|
|
|
106 |
|
|
ELL_3V_GET(dx, dy, dz, ray->dir); |
107 |
|
|
ELL_3V_GET(ox, oy, oz, ray->from); |
108 |
|
|
if (dx >= 0) { txmin = (xmin - ox)/dx; txmax = (xmax - ox)/dx; } |
109 |
|
|
else { txmin = (xmax - ox)/dx; txmax = (xmin - ox)/dx; } |
110 |
|
|
if (dy >= 0) { tymin = (ymin - oy)/dy; tymax = (ymax - oy)/dy; } |
111 |
|
|
else { tymin = (ymax - oy)/dy; tymax = (ymin - oy)/dy; } |
112 |
|
|
if (dz >= 0) { tzmin = (zmin - oz)/dz; tzmax = (zmax - oz)/dz; } |
113 |
|
|
else { tzmin = (zmax - oz)/dz; tzmax = (zmin - oz)/dz; } |
114 |
|
|
if (txmin > tymin) tmin = txmin; |
115 |
|
|
else tmin = tymin; |
116 |
|
|
if (tzmin > tmin) tmin = tzmin; |
117 |
|
|
if (txmax < tymax) tmax = txmax; |
118 |
|
|
else tmax = tymax; |
119 |
|
|
if (tzmax < tmax) tmax = tzmax; |
120 |
|
|
if (tmin >= tmax) |
121 |
|
|
return AIR_FALSE; |
122 |
|
|
|
123 |
|
|
if ( ray->faar < tmin || ray->neer > tmax ) |
124 |
|
|
return AIR_FALSE; |
125 |
|
|
|
126 |
|
|
*tminP = AIR_MAX(tmin, ray->neer); |
127 |
|
|
*tmaxP = AIR_MIN(tmax, ray->faar); |
128 |
|
|
return AIR_TRUE; |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
int |
132 |
|
|
_echoRayIntx_Sphere(RAYINTX_ARGS(Sphere)) { |
133 |
|
|
echoPos_t t, A, B, C, r[3], dscr, pos[3], tmp; |
134 |
|
|
|
135 |
|
|
AIR_UNUSED(parm); |
136 |
|
|
AIR_UNUSED(tstate); |
137 |
|
|
ELL_3V_SUB(r, ray->from, obj->pos); |
138 |
|
|
A = ELL_3V_DOT(ray->dir, ray->dir); |
139 |
|
|
B = 2*ELL_3V_DOT(ray->dir, r); |
140 |
|
|
C = ELL_3V_DOT(r, r) - obj->rad*obj->rad; |
141 |
|
|
dscr = B*B - 4*A*C; |
142 |
|
|
if (dscr <= 0) { |
143 |
|
|
/* grazes or misses (most common case) */ |
144 |
|
|
return AIR_FALSE; |
145 |
|
|
} |
146 |
|
|
/* else */ |
147 |
|
|
dscr = sqrt(dscr); |
148 |
|
|
t = (-B - dscr)/(2*A); |
149 |
|
|
if (!AIR_IN_CL(ray->neer, t, ray->faar)) { |
150 |
|
|
t = (-B + dscr)/(2*A); |
151 |
|
|
if (!AIR_IN_CL(ray->neer, t, ray->faar)) { |
152 |
|
|
return AIR_FALSE; |
153 |
|
|
} |
154 |
|
|
} |
155 |
|
|
/* else one of the intxs is in [neer,faar] segment */ |
156 |
|
|
intx->t = t; |
157 |
|
|
ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir); |
158 |
|
|
ELL_3V_SUB(intx->norm, pos, obj->pos); |
159 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
160 |
|
|
intx->obj = OBJECT(obj); |
161 |
|
|
/* does NOT set u, v */ |
162 |
|
|
return AIR_TRUE; |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
void |
166 |
|
|
_echoRayIntxUV_Sphere(echoIntx *intx) { |
167 |
|
|
echoPos_t u, v; |
168 |
|
|
|
169 |
|
|
if (intx->norm[0] || intx->norm[1]) { |
170 |
|
|
u = atan2(intx->norm[1], intx->norm[0]); |
171 |
|
|
intx->u = AIR_AFFINE(-AIR_PI, u, AIR_PI, 0.0, 1.0); |
172 |
|
|
v = -asin(intx->norm[2]); |
173 |
|
|
intx->v = AIR_AFFINE(-AIR_PI/2, v, AIR_PI/2, 0.0, 1.0); |
174 |
|
|
} |
175 |
|
|
else { |
176 |
|
|
intx->u = 0; |
177 |
|
|
/* this is valid because if we're here, then intx->norm[2] |
178 |
|
|
is either 1.0 or -1.0 */ |
179 |
|
|
intx->v = AIR_AFFINE(1.0, intx->norm[2], -1.0, 0.0, 1.0); |
180 |
|
|
} |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
int |
184 |
|
|
_echoRayIntx_Cylinder(RAYINTX_ARGS(Cylinder)) { |
185 |
|
|
echoPos_t A, B, C, aa, bb, cc, dd, ee, ff, dscr, cylt1, cylt2, t, tmax, |
186 |
|
|
twot[2], cylp1, cylp2, pos[3], tmp; |
187 |
|
|
int tidx, radi0, radi1, twocap[2], cap; |
188 |
|
|
|
189 |
|
|
AIR_UNUSED(parm); |
190 |
|
|
AIR_UNUSED(tstate); |
191 |
|
|
|
192 |
|
|
if (!_echoRayIntx_CubeSolid(&t, &tmax, |
193 |
|
|
-1-ECHO_EPSILON, 1+ECHO_EPSILON, |
194 |
|
|
-1-ECHO_EPSILON, 1+ECHO_EPSILON, |
195 |
|
|
-1-ECHO_EPSILON, 1+ECHO_EPSILON, ray)) { |
196 |
|
|
return AIR_FALSE; |
197 |
|
|
} |
198 |
|
|
switch(obj->axis) { |
199 |
|
|
case 0: |
200 |
|
|
radi0 = 1; radi1 = 2; |
201 |
|
|
break; |
202 |
|
|
case 1: |
203 |
|
|
radi0 = 0; radi1 = 2; |
204 |
|
|
break; |
205 |
|
|
case 2: default: |
206 |
|
|
radi0 = 0; radi1 = 1; |
207 |
|
|
break; |
208 |
|
|
} |
209 |
|
|
aa = ray->dir[radi0]; |
210 |
|
|
bb = ray->dir[radi1]; |
211 |
|
|
ee = ray->dir[obj->axis]; |
212 |
|
|
cc = ray->from[radi0]; |
213 |
|
|
dd = ray->from[radi1]; |
214 |
|
|
ff = ray->from[obj->axis]; |
215 |
|
|
A = aa*aa + bb*bb; |
216 |
|
|
B = 2*(aa*cc + bb*dd); |
217 |
|
|
C = cc*cc + dd*dd - 1; |
218 |
|
|
dscr = B*B - 4*A*C; |
219 |
|
|
if (dscr <= 0) { |
220 |
|
|
/* infinite ray grazes or misses the infinite cylinder (not |
221 |
|
|
bounded to [-1,1] along cylinder's axis), so therefore the ray |
222 |
|
|
grazes or misses the actual cylinder */ |
223 |
|
|
return AIR_FALSE; |
224 |
|
|
} |
225 |
|
|
/* else infinite ray intersects the infinite cylinder */ |
226 |
|
|
dscr = sqrt(dscr); |
227 |
|
|
cylt1 = (-B - dscr)/(2*A); |
228 |
|
|
cylp1 = ff + cylt1*ee; |
229 |
|
|
cylt2 = (-B + dscr)/(2*A); |
230 |
|
|
cylp2 = ff + cylt2*ee; |
231 |
|
|
if ( (cylp1 <= -1 && cylp2 <= -1) |
232 |
|
|
|| (cylp1 >= 1 && cylp2 >= 1) ) { |
233 |
|
|
/* both intersections with infinite cylinder lie on ONE side of the |
234 |
|
|
finite extent, so there can't be an intersection */ |
235 |
|
|
return AIR_FALSE; |
236 |
|
|
} |
237 |
|
|
/* else infinite ray DOES intersect finite cylinder; we have to find |
238 |
|
|
if any of the intersections are in the [neer, faar] interval */ |
239 |
|
|
tidx = 0; |
240 |
|
|
if (AIR_IN_CL(-1, cylp1, 1)) { |
241 |
|
|
twot[tidx] = cylt1; |
242 |
|
|
twocap[tidx] = 0; |
243 |
|
|
tidx++; |
244 |
|
|
} |
245 |
|
|
if (AIR_IN_CL(-1, cylp2, 1)) { |
246 |
|
|
twot[tidx] = cylt2; |
247 |
|
|
twocap[tidx] = 0; |
248 |
|
|
tidx++; |
249 |
|
|
} |
250 |
|
|
if (tidx < 2) { |
251 |
|
|
/* at least one of the two intersections is with the endcaps */ |
252 |
|
|
t = (-ff - 1)/ee; |
253 |
|
|
ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir); |
254 |
|
|
aa = pos[radi0]; bb = pos[radi1]; cc = aa*aa + bb*bb; |
255 |
|
|
if (cc <= 1) { |
256 |
|
|
twot[tidx] = t; |
257 |
|
|
twocap[tidx] = 1; |
258 |
|
|
tidx++; |
259 |
|
|
} |
260 |
|
|
if (tidx < 2) { |
261 |
|
|
/* try other endcap */ |
262 |
|
|
t = (-ff + 1)/ee; |
263 |
|
|
ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir); |
264 |
|
|
aa = pos[radi0]; bb = pos[radi1]; cc = aa*aa + bb*bb; |
265 |
|
|
if (cc <= 1) { |
266 |
|
|
twot[tidx] = t; |
267 |
|
|
twocap[tidx] = 1; |
268 |
|
|
tidx++; |
269 |
|
|
} |
270 |
|
|
} |
271 |
|
|
} |
272 |
|
|
if (!tidx) { |
273 |
|
|
return AIR_FALSE; |
274 |
|
|
} |
275 |
|
|
if (2 == tidx && twot[0] > twot[1]) { |
276 |
|
|
ELL_SWAP2(twot[0], twot[1], aa); |
277 |
|
|
ELL_SWAP2(twocap[0], twocap[1], cap); |
278 |
|
|
} |
279 |
|
|
t = twot[0]; |
280 |
|
|
cap = twocap[0]; |
281 |
|
|
if (!AIR_IN_CL(ray->neer, t, ray->faar)) { |
282 |
|
|
if (1 == tidx) { |
283 |
|
|
return AIR_FALSE; |
284 |
|
|
} |
285 |
|
|
t = twot[1]; |
286 |
|
|
cap = twocap[1]; |
287 |
|
|
if (!AIR_IN_CL(ray->neer, t, ray->faar)) { |
288 |
|
|
return AIR_FALSE; |
289 |
|
|
} |
290 |
|
|
} |
291 |
|
|
/* else one of the intxs is in [neer,faar] segment */ |
292 |
|
|
intx->t = t; |
293 |
|
|
ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir); |
294 |
|
|
switch(obj->axis) { |
295 |
|
|
case 0: |
296 |
|
|
ELL_3V_SET(intx->norm, cap*pos[0], (1-cap)*pos[1], (1-cap)*pos[2]); |
297 |
|
|
break; |
298 |
|
|
case 1: |
299 |
|
|
ELL_3V_SET(intx->norm, (1-cap)*pos[0], cap*pos[1], (1-cap)*pos[2]); |
300 |
|
|
break; |
301 |
|
|
case 2: default: |
302 |
|
|
ELL_3V_SET(intx->norm, (1-cap)*pos[0], (1-cap)*pos[1], cap*pos[2]); |
303 |
|
|
break; |
304 |
|
|
} |
305 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
306 |
|
|
intx->obj = OBJECT(obj); |
307 |
|
|
/* does NOT set u, v */ |
308 |
|
|
return AIR_TRUE; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
int |
312 |
|
|
_echoRayIntx_Cube(RAYINTX_ARGS(Cube)) { |
313 |
|
|
echoPos_t t; |
314 |
|
|
int ax, dir; |
315 |
|
|
|
316 |
|
|
AIR_UNUSED(parm); |
317 |
|
|
if (!_echoRayIntx_CubeSurf(&t, &ax, &dir, |
318 |
|
|
-1, 1, |
319 |
|
|
-1, 1, |
320 |
|
|
-1, 1, ray)) |
321 |
|
|
return AIR_FALSE; |
322 |
|
|
intx->obj = (echoObject *)obj; |
323 |
|
|
intx->t = t; |
324 |
|
|
switch(ax) { |
325 |
|
|
case 0: ELL_3V_SET(intx->norm, dir, 0, 0); break; |
326 |
|
|
case 1: ELL_3V_SET(intx->norm, 0, dir, 0); break; |
327 |
|
|
case 2: ELL_3V_SET(intx->norm, 0, 0, dir); break; |
328 |
|
|
} |
329 |
|
|
intx->face = ax + 3*(dir + 1)/2; |
330 |
|
|
if (tstate->verbose) { |
331 |
|
|
fprintf(stderr, "%s%s: ax = %d --> norm = (%g,%g,%g)\n", |
332 |
|
|
_echoDot(tstate->depth), "_echoRayIntx_Cube", ax, |
333 |
|
|
intx->norm[0], intx->norm[1], intx->norm[2]); |
334 |
|
|
} |
335 |
|
|
/* does NOT set u, v */ |
336 |
|
|
return AIR_TRUE; |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
void |
340 |
|
|
_echoRayIntxUV_Cube(echoIntx *intx) { |
341 |
|
|
echoPos_t x, y, z; |
342 |
|
|
|
343 |
|
|
ELL_3V_GET(x, y, z, intx->pos); |
344 |
|
|
switch(intx->face) { |
345 |
|
|
case 0: |
346 |
|
|
intx->u = AIR_AFFINE(-1, y, 1, 0.0, 1.0); |
347 |
|
|
intx->v = AIR_AFFINE(-1, -z, 1, 0.0, 1.0); |
348 |
|
|
break; |
349 |
|
|
case 1: |
350 |
|
|
intx->u = AIR_AFFINE(-1, -x, 1, 0.0, 1.0); |
351 |
|
|
intx->v = AIR_AFFINE(-1, -z, 1, 0.0, 1.0); |
352 |
|
|
break; |
353 |
|
|
case 2: |
354 |
|
|
intx->u = AIR_AFFINE(-1, -x, 1, 0.0, 1.0); |
355 |
|
|
intx->v = AIR_AFFINE(-1, y, 1, 0.0, 1.0); |
356 |
|
|
break; |
357 |
|
|
case 3: |
358 |
|
|
intx->u = AIR_AFFINE(-1, -y, 1, 0.0, 1.0); |
359 |
|
|
intx->v = AIR_AFFINE(-1, z, 1, 0.0, 1.0); |
360 |
|
|
break; |
361 |
|
|
case 4: |
362 |
|
|
intx->u = AIR_AFFINE(-1, x, 1, 0.0, 1.0); |
363 |
|
|
intx->v = AIR_AFFINE(-1, z, 1, 0.0, 1.0); |
364 |
|
|
break; |
365 |
|
|
case 5: |
366 |
|
|
intx->u = AIR_AFFINE(-1, x, 1, 0.0, 1.0); |
367 |
|
|
intx->v = AIR_AFFINE(-1, -y, 1, 0.0, 1.0); |
368 |
|
|
break; |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
/* |
373 |
|
|
** TRI_INTX |
374 |
|
|
** |
375 |
|
|
** given a triangle in terms of origin, edge0, edge1, this will |
376 |
|
|
** begin the intersection calculation: |
377 |
|
|
** - sets pvec, tvec, qvec (all of them if intx is not ruled out ) |
378 |
|
|
** - sets u, and rules out intx based on (u < 0.0 || u > 1.0) |
379 |
|
|
** - sets v, and rules out intx based on COND |
380 |
|
|
** - sets t, and rules out intx based on (t < neer || t > faar) |
381 |
|
|
*/ |
382 |
|
|
#define TRI_INTX(ray, origin, edge0, edge1, pvec, qvec, tvec, \ |
383 |
|
|
det, t, u, v, COND, NOPE) \ |
384 |
|
|
ELL_3V_CROSS(pvec, ray->dir, edge1); \ |
385 |
|
|
det = ELL_3V_DOT(pvec, edge0); \ |
386 |
|
|
if (det > -ECHO_EPSILON && det < ECHO_EPSILON) { \ |
387 |
|
|
NOPE; \ |
388 |
|
|
} \ |
389 |
|
|
/* now det is the reciprocal of the determinant */ \ |
390 |
|
|
det = 1.0/det; \ |
391 |
|
|
ELL_3V_SUB(tvec, ray->from, origin); \ |
392 |
|
|
u = det * ELL_3V_DOT(pvec, tvec); \ |
393 |
|
|
if (u < 0.0 || u > 1.0) { \ |
394 |
|
|
NOPE; \ |
395 |
|
|
} \ |
396 |
|
|
ELL_3V_CROSS(qvec, tvec, edge0); \ |
397 |
|
|
v = det * ELL_3V_DOT(qvec, ray->dir); \ |
398 |
|
|
if (COND) { \ |
399 |
|
|
NOPE; \ |
400 |
|
|
} \ |
401 |
|
|
t = det * ELL_3V_DOT(qvec, edge1); \ |
402 |
|
|
if (t < ray->neer || t > ray->faar) { \ |
403 |
|
|
NOPE; \ |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
int |
407 |
|
|
_echoRayIntx_Rectangle(RAYINTX_ARGS(Rectangle)) { |
408 |
|
|
echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, *edge0, *edge1, tmp; |
409 |
|
|
|
410 |
|
|
AIR_UNUSED(tstate); |
411 |
|
|
if (echoMatterLight == obj->matter |
412 |
|
|
&& (ray->shadow || !parm->renderLights)) { |
413 |
|
|
return AIR_FALSE; |
414 |
|
|
} |
415 |
|
|
edge0 = obj->edge0; |
416 |
|
|
edge1 = obj->edge1; |
417 |
|
|
TRI_INTX(ray, obj->origin, edge0, edge1, |
418 |
|
|
pvec, qvec, tvec, det, t, u, v, |
419 |
|
|
(v < 0.0 || v > 1.0), return AIR_FALSE); |
420 |
|
|
intx->t = t; |
421 |
|
|
intx->u = u; |
422 |
|
|
intx->v = v; |
423 |
|
|
ELL_3V_CROSS(intx->norm, edge0, edge1); |
424 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
425 |
|
|
intx->obj = OBJECT(obj); |
426 |
|
|
/* DOES set u, v */ |
427 |
|
|
return AIR_TRUE; |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
int |
431 |
|
|
_echoRayIntx_Triangle(RAYINTX_ARGS(Triangle)) { |
432 |
|
|
echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, edge0[3], edge1[3], tmp; |
433 |
|
|
|
434 |
|
|
AIR_UNUSED(parm); |
435 |
|
|
AIR_UNUSED(tstate); |
436 |
|
|
ELL_3V_SUB(edge0, obj->vert[1], obj->vert[0]); |
437 |
|
|
ELL_3V_SUB(edge1, obj->vert[2], obj->vert[0]); |
438 |
|
|
TRI_INTX(ray, obj->vert[0], edge0, edge1, |
439 |
|
|
pvec, qvec, tvec, det, t, u, v, |
440 |
|
|
(v < 0.0 || u + v > 1.0), return AIR_FALSE); |
441 |
|
|
intx->t = t; |
442 |
|
|
intx->u = u; |
443 |
|
|
intx->v = v; |
444 |
|
|
ELL_3V_CROSS(intx->norm, edge0, edge1); |
445 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
446 |
|
|
intx->obj = (echoObject *)obj; |
447 |
|
|
/* DOES set u, v */ |
448 |
|
|
return AIR_TRUE; |
449 |
|
|
} |
450 |
|
|
|
451 |
|
|
int |
452 |
|
|
_echoRayIntx_TriMesh(RAYINTX_ARGS(TriMesh)) { |
453 |
|
|
echoPos_t *pos, vert0[3], edge0[3], edge1[3], pvec[3], qvec[3], tvec[3], |
454 |
|
|
det, t, tmax, u, v, tmp; |
455 |
|
|
echoTriMesh *trim; |
456 |
|
|
int i, ret; |
457 |
|
|
|
458 |
|
|
AIR_UNUSED(parm); |
459 |
|
|
trim = TRIMESH(obj); |
460 |
|
|
if (!_echoRayIntx_CubeSolid(&t, &tmax, |
461 |
|
|
trim->min[0], trim->max[0], |
462 |
|
|
trim->min[1], trim->max[1], |
463 |
|
|
trim->min[2], trim->max[2], ray)) { |
464 |
|
|
if (tstate->verbose) { |
465 |
|
|
fprintf(stderr, "%s%s: trimesh bbox (%g,%g,%g) --> (%g,%g,%g) not hit\n", |
466 |
|
|
_echoDot(tstate->depth), "_echoRayIntx_TriMesh", |
467 |
|
|
trim->min[0], trim->min[1], trim->min[2], |
468 |
|
|
trim->max[0], trim->max[1], trim->max[2]); |
469 |
|
|
} |
470 |
|
|
return AIR_FALSE; |
471 |
|
|
} |
472 |
|
|
/* stupid linear search for now */ |
473 |
|
|
ret = AIR_FALSE; |
474 |
|
|
for (i=0; i<trim->numF; i++) { |
475 |
|
|
pos = trim->pos + 3*trim->vert[0 + 3*i]; |
476 |
|
|
ELL_3V_COPY(vert0, pos); |
477 |
|
|
pos = trim->pos + 3*trim->vert[1 + 3*i]; |
478 |
|
|
ELL_3V_SUB(edge0, pos, vert0); |
479 |
|
|
pos = trim->pos + 3*trim->vert[2 + 3*i]; |
480 |
|
|
ELL_3V_SUB(edge1, pos, vert0); |
481 |
|
|
TRI_INTX(ray, vert0, edge0, edge1, |
482 |
|
|
pvec, qvec, tvec, det, t, u, v, |
483 |
|
|
(v < 0.0 || u + v > 1.0), continue); |
484 |
|
|
if (ray->shadow) { |
485 |
|
|
return AIR_TRUE; |
486 |
|
|
} |
487 |
|
|
intx->t = ray->faar = t; |
488 |
|
|
ELL_3V_CROSS(intx->norm, edge0, edge1); |
489 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
490 |
|
|
intx->obj = (echoObject *)obj; |
491 |
|
|
intx->face = i; |
492 |
|
|
ret = AIR_TRUE; |
493 |
|
|
} |
494 |
|
|
/* does NOT set u, v */ |
495 |
|
|
return ret; |
496 |
|
|
} |
497 |
|
|
|
498 |
|
|
void |
499 |
|
|
_echoRayIntxUV_TriMesh(echoIntx *intx) { |
500 |
|
|
echoPos_t u, v, norm[3], len; |
501 |
|
|
echoTriMesh *trim; |
502 |
|
|
|
503 |
|
|
trim = TRIMESH(intx->obj); |
504 |
|
|
ELL_3V_SUB(norm, intx->pos, trim->meanvert); |
505 |
|
|
ELL_3V_NORM(norm, norm, len); |
506 |
|
|
if (norm[0] || norm[1]) { |
507 |
|
|
u = atan2(norm[1], norm[0]); |
508 |
|
|
intx->u = AIR_AFFINE(-AIR_PI, u, AIR_PI, 0.0, 1.0); |
509 |
|
|
v = -asin(norm[2]); |
510 |
|
|
intx->v = AIR_AFFINE(-AIR_PI/2, v, AIR_PI/2, 0.0, 1.0); |
511 |
|
|
} |
512 |
|
|
else { |
513 |
|
|
intx->u = 0; |
514 |
|
|
intx->v = AIR_AFFINE(1.0, norm[2], -1.0, 0.0, 1.0); |
515 |
|
|
} |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
int |
519 |
|
|
_echoRayIntx_AABBox(RAYINTX_ARGS(AABBox)) { |
520 |
|
|
int ret; |
521 |
|
|
echoAABBox *box; |
522 |
|
|
echoPos_t t, tmax; |
523 |
|
|
|
524 |
|
|
box = AABBOX(obj); |
525 |
|
|
if (_echoRayIntx_CubeSolid(&t, &tmax, |
526 |
|
|
box->min[0], box->max[0], |
527 |
|
|
box->min[1], box->max[1], |
528 |
|
|
box->min[2], box->max[2], ray)) { |
529 |
|
|
intx->boxhits++; |
530 |
|
|
ret = _echoRayIntx[box->obj->type](intx, ray, box->obj, parm, tstate); |
531 |
|
|
} else { |
532 |
|
|
ret = AIR_FALSE; |
533 |
|
|
} |
534 |
|
|
return ret; |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
int |
538 |
|
|
_echoRayIntx_Split(RAYINTX_ARGS(Split)) { |
539 |
|
|
char me[]="_echoRayIntx_Split"; |
540 |
|
|
echoObject *a, *b; |
541 |
|
|
echoPos_t *mina, *minb, *maxa, *maxb, t, tmax; |
542 |
|
|
int ret; |
543 |
|
|
|
544 |
|
|
if (ray->dir[obj->axis] > 0) { |
545 |
|
|
a = obj->obj0; |
546 |
|
|
mina = obj->min0; |
547 |
|
|
maxa = obj->max0; |
548 |
|
|
b = obj->obj1; |
549 |
|
|
minb = obj->min1; |
550 |
|
|
maxb = obj->max1; |
551 |
|
|
} |
552 |
|
|
else { |
553 |
|
|
a = obj->obj1; |
554 |
|
|
mina = obj->min1; |
555 |
|
|
maxa = obj->max1; |
556 |
|
|
b = obj->obj0; |
557 |
|
|
minb = obj->min0; |
558 |
|
|
maxb = obj->max0; |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
if (tstate->verbose) { |
562 |
|
|
fprintf(stderr, "%s%s: (shadow = %d):\n", |
563 |
|
|
_echoDot(tstate->depth), me, ray->shadow); |
564 |
|
|
fprintf(stderr, "%s%s: 1st: (%g,%g,%g) -- (%g,%g,%g) (obj %d)\n", |
565 |
|
|
_echoDot(tstate->depth), me, |
566 |
|
|
mina[0], mina[1], mina[2], |
567 |
|
|
maxa[0], maxa[1], maxa[2], a->type); |
568 |
|
|
fprintf(stderr, "%s%s: 2nd: (%g,%g,%g) -- (%g,%g,%g) (obj %d)\n", |
569 |
|
|
_echoDot(tstate->depth), me, |
570 |
|
|
minb[0], minb[1], minb[2], |
571 |
|
|
maxb[0], maxb[1], maxb[2], b->type); |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
ret = AIR_FALSE; |
575 |
|
|
if (_echoRayIntx_CubeSolid(&t, &tmax, |
576 |
|
|
mina[0], maxa[0], |
577 |
|
|
mina[1], maxa[1], |
578 |
|
|
mina[2], maxa[2], ray)) { |
579 |
|
|
intx->boxhits++; |
580 |
|
|
if (_echoRayIntx[a->type](intx, ray, a, parm, tstate)) { |
581 |
|
|
if (ray->shadow) { |
582 |
|
|
return AIR_TRUE; |
583 |
|
|
} |
584 |
|
|
ray->faar = intx->t; |
585 |
|
|
ret = AIR_TRUE; |
586 |
|
|
} |
587 |
|
|
} |
588 |
|
|
if (_echoRayIntx_CubeSolid(&t, &tmax, |
589 |
|
|
minb[0], maxb[0], |
590 |
|
|
minb[1], maxb[1], |
591 |
|
|
minb[2], maxb[2], ray)) { |
592 |
|
|
intx->boxhits++; |
593 |
|
|
if (_echoRayIntx[b->type](intx, ray, b, parm, tstate)) { |
594 |
|
|
ray->faar = intx->t; |
595 |
|
|
ret = AIR_TRUE; |
596 |
|
|
} |
597 |
|
|
} |
598 |
|
|
return ret; |
599 |
|
|
} |
600 |
|
|
|
601 |
|
|
int |
602 |
|
|
_echoRayIntx_List(RAYINTX_ARGS(List)) { |
603 |
|
|
unsigned int i; |
604 |
|
|
int ret; |
605 |
|
|
echoObject *kid; |
606 |
|
|
|
607 |
|
|
ret = AIR_FALSE; |
608 |
|
|
for (i=0; i<obj->objArr->len; i++) { |
609 |
|
|
kid = obj->obj[i]; |
610 |
|
|
if (_echoRayIntx[kid->type](intx, ray, kid, parm, tstate)) { |
611 |
|
|
ray->faar = intx->t; |
612 |
|
|
ret = AIR_TRUE; |
613 |
|
|
if (ray->shadow) { |
614 |
|
|
/* no point in testing any further */ |
615 |
|
|
return ret; |
616 |
|
|
} |
617 |
|
|
} |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
return ret; |
621 |
|
|
} |
622 |
|
|
|
623 |
|
|
int |
624 |
|
|
_echoRayIntx_Instance(RAYINTX_ARGS(Instance)) { |
625 |
|
|
echoPos_t a[4], b[4], tmp; |
626 |
|
|
echoRay iray; |
627 |
|
|
|
628 |
|
|
/* |
629 |
|
|
ELL_3V_COPY(iray.from, ray->from); |
630 |
|
|
ELL_3V_COPY(iray.dir, ray->dir); |
631 |
|
|
*/ |
632 |
|
|
ELL_4V_SET(a, ray->from[0], ray->from[1], ray->from[2], 1); |
633 |
|
|
ELL_4MV_MUL(b, obj->Mi, a); |
634 |
|
|
ELL_34V_HOMOG(iray.from, b); |
635 |
|
|
ELL_4V_SET(a, ray->dir[0], ray->dir[1], ray->dir[2], 0); |
636 |
|
|
ELL_4MV_MUL(b, obj->Mi, a); |
637 |
|
|
ELL_3V_COPY(iray.dir, b); |
638 |
|
|
if (tstate->verbose) { |
639 |
|
|
fprintf(stderr, "%s%s: dir (%g,%g,%g)\n%s -- Mi --> " |
640 |
|
|
"(%g,%g,%g,%g)\n%s --> (%g,%g,%g)\n", |
641 |
|
|
_echoDot(tstate->depth), "_echoRayIntx_Instance", |
642 |
|
|
a[0], a[1], a[2], _echoDot(tstate->depth), |
643 |
|
|
b[0], b[1], b[2], b[3], _echoDot(tstate->depth), |
644 |
|
|
iray.dir[0], iray.dir[1], iray.dir[2]); |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
iray.neer = ray->neer; |
648 |
|
|
iray.faar = ray->faar; |
649 |
|
|
iray.shadow = ray->shadow; |
650 |
|
|
|
651 |
|
|
if (_echoRayIntx[obj->obj->type](intx, &iray, obj->obj, parm, tstate)) { |
652 |
|
|
ELL_4V_SET(a, intx->norm[0], intx->norm[1], intx->norm[2], 0); |
653 |
|
|
ELL_4MV_TMUL(b, obj->Mi, a); |
654 |
|
|
ELL_3V_COPY(intx->norm, b); |
655 |
|
|
ELL_3V_NORM(intx->norm, intx->norm, tmp); |
656 |
|
|
if (tstate->verbose) { |
657 |
|
|
fprintf(stderr, "%s%s: hit a %d (at t=%g) with M == \n", |
658 |
|
|
_echoDot(tstate->depth), "_echoRayIntx_Instance", |
659 |
|
|
obj->obj->type, intx->t); |
660 |
|
|
ell_4m_PRINT(stderr, obj->M); |
661 |
|
|
fprintf(stderr, "%s ... (det = %f), and Mi == \n", |
662 |
|
|
_echoDot(tstate->depth), ell_4m_DET(obj->M)); |
663 |
|
|
ell_4m_PRINT(stderr, obj->Mi); |
664 |
|
|
} |
665 |
|
|
return AIR_TRUE; |
666 |
|
|
} |
667 |
|
|
/* else */ |
668 |
|
|
return AIR_FALSE; |
669 |
|
|
} |
670 |
|
|
|
671 |
|
|
void |
672 |
|
|
_echoRayIntxUV_Noop(echoIntx *intx) { |
673 |
|
|
|
674 |
|
|
AIR_UNUSED(intx); |
675 |
|
|
} |
676 |
|
|
|
677 |
|
|
/* |
678 |
|
|
** NB: the intersections with real objects need to normalize |
679 |
|
|
** intx->norm |
680 |
|
|
*/ |
681 |
|
|
_echoRayIntx_t |
682 |
|
|
_echoRayIntx[ECHO_TYPE_NUM] = { |
683 |
|
|
(_echoRayIntx_t)_echoRayIntx_Sphere, |
684 |
|
|
(_echoRayIntx_t)_echoRayIntx_Cylinder, |
685 |
|
|
(_echoRayIntx_t)_echoRayIntx_Superquad, |
686 |
|
|
(_echoRayIntx_t)_echoRayIntx_Cube, |
687 |
|
|
(_echoRayIntx_t)_echoRayIntx_Triangle, |
688 |
|
|
(_echoRayIntx_t)_echoRayIntx_Rectangle, |
689 |
|
|
(_echoRayIntx_t)_echoRayIntx_TriMesh, |
690 |
|
|
(_echoRayIntx_t)_echoRayIntx_Noop, |
691 |
|
|
(_echoRayIntx_t)_echoRayIntx_AABBox, |
692 |
|
|
(_echoRayIntx_t)_echoRayIntx_Split, |
693 |
|
|
(_echoRayIntx_t)_echoRayIntx_List, |
694 |
|
|
(_echoRayIntx_t)_echoRayIntx_Instance, |
695 |
|
|
}; |
696 |
|
|
|
697 |
|
|
_echoRayIntxUV_t |
698 |
|
|
_echoRayIntxUV[ECHO_TYPE_NUM] = { |
699 |
|
|
_echoRayIntxUV_Sphere, /* echoTypeSphere */ |
700 |
|
|
_echoRayIntxUV_Noop, /* echoTypeCylinder */ |
701 |
|
|
_echoRayIntxUV_Noop, /* sqd.c: echoTypeSuperquad */ |
702 |
|
|
_echoRayIntxUV_Cube, /* echoTypeCube */ |
703 |
|
|
_echoRayIntxUV_Noop, /* echoTypeTriangle */ |
704 |
|
|
_echoRayIntxUV_Noop, /* echoTypeRectangle */ |
705 |
|
|
_echoRayIntxUV_TriMesh, /* echoTypeTriMesh */ |
706 |
|
|
_echoRayIntxUV_Noop, /* echoTypeIsosurface */ |
707 |
|
|
_echoRayIntxUV_Noop, /* echoTypeAABBox */ |
708 |
|
|
_echoRayIntxUV_Noop, /* echoTypeSplit */ |
709 |
|
|
_echoRayIntxUV_Noop, /* echoTypeList */ |
710 |
|
|
_echoRayIntxUV_Noop /* echoTypeInstance */ |
711 |
|
|
}; |
712 |
|
|
|
713 |
|
|
int |
714 |
|
|
echoRayIntx(echoIntx *intx, echoRay *ray, echoScene *scene, |
715 |
|
|
echoRTParm *parm, echoThreadState *tstate) { |
716 |
|
|
unsigned int idx; |
717 |
|
|
int ret; |
718 |
|
|
echoObject *kid; |
719 |
|
|
echoPos_t tmp; |
720 |
|
|
|
721 |
|
|
_echoVerbose = tstate->verbose; |
722 |
|
|
|
723 |
|
|
ret = AIR_FALSE; |
724 |
|
|
for (idx=0; idx<scene->rendArr->len; idx++) { |
725 |
|
|
kid = scene->rend[idx]; |
726 |
|
|
if (_echoRayIntx[kid->type](intx, ray, kid, parm, tstate)) { |
727 |
|
|
ray->faar = intx->t; |
728 |
|
|
ret = AIR_TRUE; |
729 |
|
|
if (ray->shadow) { |
730 |
|
|
/* no point in testing any further */ |
731 |
|
|
return ret; |
732 |
|
|
} |
733 |
|
|
} |
734 |
|
|
} |
735 |
|
|
if (ret) { |
736 |
|
|
/* being here means we're not a shadow ray */ |
737 |
|
|
ELL_3V_SCALE_ADD2(intx->pos, 1, ray->from, intx->t, ray->dir); |
738 |
|
|
ELL_3V_SCALE(intx->view, -1, ray->dir); |
739 |
|
|
ELL_3V_NORM(intx->view, intx->view, tmp); |
740 |
|
|
/* this is needed for phong materials; for glass and metal, |
741 |
|
|
it is either used directly, or as a reference in fuzzification */ |
742 |
|
|
_ECHO_REFLECT(intx->refl, intx->norm, intx->view, tmp); |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
return ret; |
746 |
|
|
} |