|
|
|||
File indexing completed on 2026-04-09 07:48:54
0001 #pragma once 0002 0003 /** 0004 distance_leaf_phicut 0005 ----------------------- 0006 0007 :: 0008 0009 . . . . . . phi0=0.5 0010 . . . . . . | 0011 . . . . . . | 0012 . . . . . . |--> [sinPhi0,-cosPhi0] = [1,0] 0013 . . . . . . | 0014 . . . . . . | 0015 . . . . . . | 0016 . . . . . . | sd0 (x,y) 0017 . . . . . . +. . . + 0018 . . . . . . | : 0019 . . . . . . | sd1 0020 . . . . . . | : [ -sinPhi1, cosPhi1] = [0, 1] 0021 . . . . . . | : ^ 0022 . . . . . . | : | 0023 . . . . . . +------+----------+--- phi1=2 0024 . . . . . . . . . . . . . . . . . . . . . 0025 . . . . . . . . . . . . . . . . . . . . . 0026 . . . . . . . . . . . . . . . . . . . . . 0027 . . . . . . . . . . . . . . . . . . . . . 0028 . . . . . . . . . . . . . . . . . . . . . 0029 . . . . . . . . . . . . . . . . . . . . . 0030 0031 **/ 0032 0033 LEAF_FUNC 0034 float distance_leaf_phicut( const float3& pos, const quad& q0 ) 0035 { 0036 const float& cosPhi0 = q0.f.x ; 0037 const float& sinPhi0 = q0.f.y ; 0038 const float& cosPhi1 = q0.f.z ; 0039 const float& sinPhi1 = q0.f.w ; 0040 0041 // dot products with normal0 [ sinPhi0, -cosPhi0, 0.f ] 0042 float sd0 = sinPhi0*pos.x - cosPhi0*pos.y ; 0043 0044 // dot products with normal1 [ -sinPhi1, cosPhi1, 0.f ] 0045 float sd1 = -sinPhi1*pos.x + cosPhi1*pos.y ; 0046 0047 return fminf( sd0, sd1 ); 0048 } 0049 0050 0051 /** 0052 intersect_leaf_phicut 0053 ------------------------ 0054 0055 Unbounded shape that cuts phi via two half-planes "attached" to the z-axis. 0056 See phicut.py for development and testing of intersect_node_phicut 0057 The phicut planes go through the origin so the equation of the plane is:: 0058 0059 p.n = 0 0060 0061 Intersecting a ray with the plane (with normal vector n):: 0062 0063 p = o + t d parametric ray equation, o:ray_origin d:ray_direction t:distance 0064 0065 (o + t d).n = 0 0066 0067 o.n = - t d.n 0068 0069 -o.n 0070 t = ----------- 0071 d.n 0072 0073 Outwards normals of the two planes:: 0074 0075 n0 ( sin(phi0), -cos(phi0), 0 ) = ( 0, -1, 0) phi0 = 0 0076 n1 ( -sin(phi1), cos(phi1), 0 ) = ( -1, 0, 0) phi1 = 0.5 0077 0078 Vectors within the two planes:: 0079 0080 w0 ( cos(phi0), sin(phi0), 0 ) = (1, 0, 0 ) phi0 = 0 0081 w1 ( cos(phi1), sin(phi1), 0 ) = (0, 1, 0) phi1 = 0.5 0082 0083 0084 phi1=0.5 0085 Y 0086 | . . . . . . . 0087 | . . . . . . . 0088 | . . . . . . . 0089 n1--+ . . . . . . . 0090 | . . . . . . . 0091 | . . . . . . . 0092 phi=1.0 . . . .O----+-------- X phi0=0 0093 . | 0094 . n0 0095 . 0096 . 0097 . 0098 phi=1.5 0099 0100 0101 Normal incidence is no problem:: 0102 0103 Y 0104 | 0105 | 0106 | 0107 | (10,0,0) 0108 O------+---------- X 0109 | 0110 | 0111 | 0112 * 0113 normal ( 0, -1, 0) 0114 ray_origin (10, -10, 0) .normal = 10 0115 ray_direction ( 0, 1, 0) .normal = -1 0116 0117 t = -10/(-1) = 10 0118 0119 Disqualify rays with direction within the plane:: 0120 0121 normal ( 0, -1, 0) 0122 ray_origin ( 20, 0, 0) .normal 0 0123 ray_direction ( -1, 0, 0) .normal 0 0124 0125 0126 Edge vectors P, Q and radial direction vector R:: 0127 0128 P ( cosPhi0, sinPhi0, 0 ) vector within phi0 plane eg: phi0=0 (1, 0, 0) phi0=1 (-1, 0, 0) 0129 Q ( cosPhi1, sinPhi1, 0 ) vector within phi1 plane eg: phi1=0.5 (0, 1, 0) 0130 R ( d.x , d.y , 0 ) d.z is ignored, only intersected in radial direction within XY plane 0131 0132 Use conventional cross product sign convention A ^ B = (Ax By - Bx Ay ) k the products are:: 0133 0134 PQ = P ^ Q = cosPhi0*sinPhi1 - cosPhi1*sinPhi0 0135 PR = P ^ R = cosPhi0*d.y - d.x*sinPhi0 0136 QR = Q ^ R = cosPhi1*d.y - d.x*sinPhi1 0137 0138 Note that as R is not normalized the PR and QR cross products are only proportional to the sine of the angles. 0139 See CSG/tests/cross2D_angle_range_without_trig.py for exploration of 2D cross product 0140 0141 Alternative way of looking at this is with the sine of angle subtraction identity:: 0142 0143 sin(a-b) = sin(a)cos(b)-cos(a)sin(b) 0144 0145 When rays have non-zero x,y direction components the 2D cross products 0146 between the direction vectors and the phi edge vectors determines 0147 if the rays will exit the unbounded shape at infinity. 0148 0149 When rays are purely in Z direction this approach does not work as PR and QR 0150 will always be zero because d.x and d.y are zero. 0151 So in this "zpure" case the (o.x, o.y) are used instead of (d.x, d.y) 0152 Can think of vectors from origin to the (o.x, o.y) ray origin which can 0153 serve the same purpose of determining whether the ray will exit the 0154 shape at infinity or not. 0155 0156 NO 0157 . . . . . . . . . . . .| / 0158 . . . . . . . . . . . .| / 0159 . . . . . . . . . . . .| / 0160 . . . . . . . . . . . .| / 0161 . . . . . . . . . . phi0=0.5 / 0162 . . . . . . . . . . . .| / 0163 . . . . . . . . . . . .| 0 sd > 0.f 0164 . . . . . . . . . . . .| 0165 . . . . . 0 . . . . . .| 0166 . . . . ./. . . . . . .| 0167 . . . . / . . . . . . .+------------ phi1=2.0 --- X 0168 . . . ./. . . . . . . . . . . . . . . . . . . . . . . 0169 . . . / . . . . . . . . . . . . . . . . . . . . . . . 0170 . . ./. . . . . . . . . . . . . . . . . . . . . . . . 0171 . . / . . . . . . . . . . . . . . . .0------------------ YES UNBOUNDED_EXIT AT INFINITY 0172 . ./. . . . . . . . . . . . . . . .sd < 0.f . . . . . 0173 . / . . . . . . . . . . . . . . . . . . . . . . . . . 0174 ./. . . . . . . . . . . . . . . . . . . . . . . . . . 0175 / . . . . . . . . . . . . . . . . . . . . . . . . . . 0176 / 0177 YES 0178 0179 0180 0181 Clockwise rotation by phi (flipping sign):: 0182 0183 | x' | | cosPhi sinPhi | | x | 0184 | | = | | | | 0185 | y' | | -sinPhi cosPhi | | y | 0186 0187 0188 x' = cosPhi x + sinPhi y 0189 0190 y' = -sinPhi x + cosPhi y 0191 0192 0193 Within edgezone want to avoid two separate decisions as to which face gets hit 0194 otherwise numerical imprecision will result in inconsistent decisions causing misses (white seams) along the edge. 0195 0196 0197 0198 Thoughts on implementing phicut by CSG combination of two halfspaces 0199 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0200 0201 phi1 - phi0 > 1.0 0202 A+B : union of two halfspaces 0203 !(!A.!B) : complement of intersection of the two halfspaces complemented 0204 0205 :: 0206 0207 0208 A | !A 0209 phi0=0.5 0210 . . . .| 0211 . . . .| 0212 . . . .| 0213 . . . .| 0214 . . . .| !B 0215 ~~~~~~~+--------- phi1=2.0 0216 . . . .:. . . . . B 0217 . . . .:. . . . . 0218 . . . .:. . . . . 0219 . . . .:. . . . . 0220 0221 phi1 - phi0 < 1.0 : 0222 0223 A.B : intersection of two halfspaces 0224 !(!A+!B) : complement of union of two halfspaces complemented 0225 0226 !A | A 0227 phi1=0.5 0228 | . . . . . 0229 | . . . . . 0230 | . . . . . 0231 | . . . . . B 0232 ~~~~~~~+--------- phi0=0.0 0233 : !B 0234 : 0235 : 0236 : 0237 **/ 0238 0239 0240 LEAF_FUNC 0241 void intersect_leaf_phicut( bool& valid_isect, float4& isect, const quad& q0, const float t_min, const float3& o, const float3& d ) 0242 { 0243 const float& cosPhi0 = q0.f.x ; 0244 const float& sinPhi0 = q0.f.y ; 0245 const float& cosPhi1 = q0.f.z ; 0246 const float& sinPhi1 = q0.f.w ; 0247 0248 #ifdef DEBUG 0249 printf("//intersect_leaf_phicut q0.f (%10.4f %10.4f %10.4f %10.4f ) cosPhi0 sinPhi0 cosPhi1 sinPhi1 t_min %10.4f \n", cosPhi0, sinPhi0, cosPhi1, sinPhi1, t_min ); 0250 #endif 0251 0252 const float sd0 = sinPhi0*(o.x+t_min*d.x) - cosPhi0*(o.y+t_min*d.y) ; 0253 const float sd1 = -sinPhi1*(o.x+t_min*d.x) + cosPhi1*(o.y+t_min*d.y) ; 0254 float sd = fminf( sd0, sd1 ); // signed distance at t_min, sd < 0.f means are within the phicut shape : ie between the planes 0255 0256 #ifdef DEBUG 0257 printf("//intersect_leaf_phicut sd0 %10.4f sd1 %10.4f sd %10.4f \n", sd0, sd1, sd ); 0258 #endif 0259 0260 const float PQ = cosPhi0*sinPhi1 - cosPhi1*sinPhi0 ; // PQ +ve => angle < pi, PQ -ve => angle > pi 0261 const bool zpure = d.x == 0.f && d.y == 0.f ; 0262 const float PR = cosPhi0*(zpure ? o.y : d.y) - (zpure ? o.x : d.x)*sinPhi0 ; // PR and QR +ve/-ve selects the "side of the line" 0263 const float QR = cosPhi1*(zpure ? o.y : d.y) - (zpure ? o.x : d.x)*sinPhi1 ; 0264 const bool unbounded_exit = sd < 0.f && ( PQ >= 0.f ? ( PR >= 0.f && QR <= 0.f ) : ( PR >= 0.f || QR <= 0.f )) ; 0265 0266 #ifdef DEBUG 0267 printf("//intersect_leaf_phicut PQ %10.4f zpure %d \n", PQ, zpure ); 0268 printf("//intersect_leaf_phicut PR %10.4f QR %10.4f unbounded_exit %d \n", PR,QR, unbounded_exit ); 0269 #endif 0270 0271 // dotproduct with outward normal [ sinPhi0, -cosPhi0, 0 ] of phi0 plane eg [1,0,0] for pacmanpp 0272 const float t0 = -( o.x*sinPhi0 + o.y*(-cosPhi0) )/ ( d.x*sinPhi0 + d.y*(-cosPhi0) ) ; // -o.x/d.x 0273 const float x0 = o.x+t0*d.x ; 0274 const float y0 = o.y+t0*d.y ; 0275 const float s0x = cosPhi0*x0 + sinPhi0*y0 ; 0276 0277 #ifdef DEBUG 0278 const float s0y = -sinPhi0*x0 + cosPhi0*y0 ; 0279 printf("//intersect_leaf_phicut t0 %10.4f (x0,y0) (%10.4f, %10.4f) (s0x,s0y) (%10.4g, %10.4g) \n", t0, x0,y0, s0x,s0y ); 0280 #endif 0281 0282 // dotproduct with outward normal [ -sinPhi1, cosPhi1, 0 ] of phi1 plane eg [0,1,0] for pacmanpp 0283 const float t1 = -( o.x*(-sinPhi1) + o.y*cosPhi1 )/( d.x*(-sinPhi1) + d.y*cosPhi1 ) ; 0284 const float x1 = o.x+t1*d.x ; 0285 const float y1 = o.y+t1*d.y ; 0286 const float s1x = cosPhi1*x1 + sinPhi1*y1 ; 0287 0288 #ifdef DEBUG 0289 const float s1y = -sinPhi1*x1 + cosPhi1*y1 ; 0290 printf("//intersect_leaf_phicut t1 %10.4f (x1,y1) (%10.4f, %10.4f) (s1x,s1y) (%10.4f, %10.4f) \n", t1, x1,y1, s1x,s1y ); 0291 #endif 0292 0293 const float epsilon = 1e-4f ; 0294 bool safezone = ( fabsf(s0x) > epsilon && fabsf(s1x) > epsilon ) ; 0295 const float t0c = ( s0x >= 0.f && t0 > t_min) ? t0 : RT_DEFAULT_MAX ; 0296 const float t1c = ( s1x >= 0.f && t1 > t_min) ? t1 : RT_DEFAULT_MAX ; 0297 const float t_cand = safezone ? fminf( t0c, t1c ) : ( s0x >= 0.f ? t0c : t1c ) ; 0298 0299 valid_isect = t_cand > t_min && t_cand < RT_DEFAULT_MAX ; 0300 0301 0302 /* 0303 0. s0x s1x are -phi0 and -phi1 rotated xprime coordinates of intersect positions 0304 it might be tempting to simply match signs of intersect x or y 0305 but that does not work in general for any phi0 phi1 angle 0306 0307 * eg pacmanpp +x x1:-inf y1:nan s1x:nan s1y:nan 0308 0309 1. s0x s1x can become nan (from t0 or t1 inf or -inf and inf*0.f->nan or -inf*0.f->nan ) 0310 and comparisons with nan always give false. So arrange direction of the comparisons 0311 such that true yields the root in order that a false from nan comparison does what 0312 is needed and disqualifies the root. 0313 0314 2. t0, t1 can be -inf/inf/nan so must check them against t_min individually 0315 0316 * when t0 OR t1 is inf the s0x OR s1x will be nan 0317 0318 3. must prevent nan from one root infecting the other, by quashing it before root comparison 0319 0320 4. close to knife edge numerical imprecision makes inconsistencies between sign comparisons on s0x and s1x likely 0321 (such inconsistencies cause seams lines of MISS-es along the knife edge between the phi planes) 0322 0323 * having unexpected holes in geometry is more of a problem than having normals at edge swap between planes 0324 * hence : prevent inconsistent decisions by making just one decision over which plane is hit when at knife edge 0325 0326 * TODO: current approach makes the knife edge decision based on s0x (an arbitrary choice) 0327 it would be better to choose based on the s0x or s1x with the larger absolute value, 0328 but need to fish for which is which to pick t0c or t1c:: 0329 0330 fmaxf(abs(s0x), abs(s1x)) == abs(s0x) ? t0c : t1c 0331 0332 */ 0333 0334 0335 #ifdef DEBUG 0336 printf("//intersect_leaf_phicut t0c %10.4f t1c %10.4f safezone %d t_cand %10.4f valid_isect %d unbounded_exit %d \n", t0c, t1c, safezone, t_cand, valid_isect, unbounded_exit ); 0337 #endif 0338 0339 if( valid_isect ) 0340 { 0341 isect.x = t_cand == t1 ? -sinPhi1 : sinPhi0 ; 0342 isect.y = t_cand == t1 ? cosPhi1 : -cosPhi0 ; 0343 isect.z = 0.f ; 0344 isect.w = t_cand ; 0345 } 0346 else if( unbounded_exit ) 0347 { 0348 isect.y = -isect.y ; // -0.f signflip signalling that can promote MISS to EXIT at infinity 0349 } 0350 } 0351 0352 0353 0354 0355 0356 0357 LEAF_FUNC 0358 void intersect_leaf_phicut_dev( bool& valid_isect, float4& isect, const quad& q0, const float t_min, const float3& o, const float3& d ) 0359 { 0360 const float& cosPhi0 = q0.f.x ; 0361 const float& sinPhi0 = q0.f.y ; 0362 const float& cosPhi1 = q0.f.z ; 0363 const float& sinPhi1 = q0.f.w ; 0364 0365 const float PQ = cosPhi0*sinPhi1 - cosPhi1*sinPhi0 ; // PQ +ve => angle < pi, PQ -ve => angle > pi 0366 bool zpure = d.x == 0.f && d.y == 0.f ; 0367 const float PR = cosPhi0*(zpure ? o.y : d.y) - (zpure ? o.x : d.x)*sinPhi0 ; // PR and QR +ve/-ve selects the "side of the line" 0368 const float QR = cosPhi1*(zpure ? o.y : d.y) - (zpure ? o.x : d.x)*sinPhi1 ; 0369 bool unbounded_exit = PQ >= 0.f ? ( PR >= 0.f && QR <= 0.f ) : ( PR >= 0.f || QR <= 0.f ) ; 0370 0371 #ifdef DEBUG 0372 printf("//intersect_leaf_phicut q0.f (%10.4f %10.4f %10.4f %10.4f) %s t_min %10.4f \n" , q0.f.x, q0.f.y, q0.f.z, q0.f.w, "cosPhi0/sinPhi0/cosPhi1/sinPhi1", t_min ) ; 0373 printf("//intersect_leaf_phicut d.xyz ( %10.4f %10.4f %10.4f ) zpure %d \n", d.x, d.y, d.z, zpure ); 0374 printf("//intersect_leaf_phicut PQ %10.4f cosPhi0*sinPhi1 - cosPhi1*sinPhi0 : +ve:angle less than pi, -ve:angle greater than pi \n", PQ ); 0375 printf("//intersect_leaf_phicut PR %10.4f cosPhi0*d.y - d.x*sinPhi0 \n", PR ); 0376 printf("//intersect_leaf_phicut QR %10.4f cosPhi1*d.y - d.x*sinPhi1 \n", QR ); 0377 printf("//intersect_leaf_phicut unbounded_exit %d \n", unbounded_exit ); 0378 #endif 0379 0380 // setting t values to t_min disqualifies that intersect 0381 // dot products with normal0 [ sinPhi0, -cosPhi0, 0.f ] 0382 0383 /* 0384 // Old careful approach works, but unneeded rotation flops for checking the side, 0385 // can just check signbit of x intersect matches the sigbit of the cosPhi 0386 0387 float d_n0 = d.x*sinPhi0 + d.y*(-cosPhi0) ; 0388 float o_n0 = o.x*sinPhi0 + o.y*(-cosPhi0) ; 0389 float t0 = d_n0 == 0.f ? t_min : -o_n0/d_n0 ; // perhaps could avoid the check if side0 became -inf ? 0390 0391 float side0 = o.x*cosPhi0 + o.y*sinPhi0 + ( d.x*cosPhi0 + d.y*sinPhi0 )*t0 ; 0392 if(side0 < 0.f) t0 = t_min ; 0393 0394 float d_n1 = d.x*(-sinPhi1) + d.y*cosPhi1 ; 0395 float o_n1 = o.x*(-sinPhi1) + o.y*cosPhi1 ; 0396 float t1 = d_n1 == 0.f ? t_min : -o_n1/d_n1 ; 0397 0398 float side1 = o.x*cosPhi1 + o.y*sinPhi1 + ( d.x*cosPhi1 + d.y*sinPhi1 )*t1 ; 0399 if(side1 < 0.f) t1 = t_min ; 0400 */ 0401 0402 0403 /* 0404 0405 // Medium careful approach works, accepting t0 and t1 becoming infinity for some ray directions 0406 // but still carefully ordering the roots. 0407 // 0408 float t0 = -(o.x*sinPhi0 + o.y*(-cosPhi0))/ ( d.x*sinPhi0 + d.y*(-cosPhi0) ) ; 0409 if(signbit(o.x+t0*d.x) != signbit(cosPhi0)) t0 = t_min ; 0410 0411 float t1 = -(o.x*(-sinPhi1) + o.y*cosPhi1)/(d.x*(-sinPhi1) + d.y*cosPhi1 ) ; 0412 if(signbit(o.x+t1*d.x) != signbit(cosPhi1)) t1 = t_min ; 0413 0414 float t_near = fminf(t0,t1); // order the intersects 0415 float t_far = fmaxf(t0,t1); 0416 float t_cand = t_near > t_min ? t_near : ( t_far > t_min ? t_far : t_min ) ; 0417 bool valid_intersect = t_cand > t_min ; 0418 0419 */ 0420 0421 0422 // Lucas wild abandon approach gives bad intersects 0423 // Select isect in the bad region:: 0424 // 0425 // SPHI=0.24,1.76 ./csg_geochain.sh ana 0426 // SPHI=0.24,1.76 IXYZ=4,4,0 ./csg_geochain.sh ana 0427 // 0428 // Q: why ? its little different to the above which has no problem 0429 // A: bug t_cand < t_min which should be t_cand <= t_min 0430 // 0431 // https://tavianator.com/2011/ray_box.html 0432 // 0*inf = nan 0433 // 0434 0435 0436 float t_cand = -( o.x*sinPhi0 + o.y*(-cosPhi0) )/ ( d.x*sinPhi0 + d.y*(-cosPhi0) ) ; 0437 // o on phi0 line => t_cand.0 -0.f 0438 // o on phi0 line, d along line => t_cand.0 0/0 = nan 0439 0440 #ifdef DEBUG 0441 //printf("//intersect_leaf_phicut ( o.x*sinPhi0 + o.y*(-cosPhi0) %10.4f \n", ( o.x*sinPhi0 + o.y*(-cosPhi0)) ); 0442 //printf("//intersect_leaf_phicut ( d.x*sinPhi0 + d.y*(-cosPhi0) %10.4f \n", ( d.x*sinPhi0 + d.y*(-cosPhi0)) ); 0443 printf("//intersect_leaf_phicut t_cand.0 %10.4f t_min %10.4f \n", t_cand, t_min ); 0444 //printf("//intersect_leaf_phicut o.x+t_cand*d.x %10.4f \n", o.x+t_cand*d.x ); 0445 //printf("//intersect_leaf_phicut signbit(o.x+t_cand*d.x) %d \n", signbit(o.x+t_cand*d.x) ); 0446 //printf("//intersect_leaf_phicut signbit(o.x+t_cand*d.x) != signbit(cosPhi0) %d \n", signbit(o.x+t_cand*d.x) != signbit(cosPhi0) ); 0447 //printf("//intersect_leaf_phicut t_cand.0 < t_min : %d \n", t_cand < t_min ); 0448 //printf("//intersect_leaf_phicut t_cand.0 > t_min : %d \n", t_cand > t_min ); 0449 //printf("//intersect_leaf_phicut t_cand.0 == t_min : %d \n", t_cand == t_min ); 0450 //printf("//intersect_leaf_phicut signbit(o.x+t_cand*d.x) != signbit(cosPhi0) || t_cand.0 < t_min : %d \n", signbit(o.x+t_cand*d.x) != signbit(cosPhi0) || t_cand < t_min ); 0451 0452 { 0453 /* 0454 in XZ projection testing deciding based on ipos_x yields spurious due to ipos_x going slightly wrong sign 0455 switching to ipos_y avoids the problem : WHY ? 0456 */ 0457 float ipos_x = (o.x+t_cand*d.x) ; 0458 float ipos_y = (o.y+t_cand*d.y) ; 0459 float ipos_z = (o.z+t_cand*d.z) ; 0460 bool x_wrong_side = ipos_x*cosPhi0 < 0.f ; 0461 bool y_wrong_side = ipos_y*sinPhi0 < 0.f ; 0462 bool too_close = t_cand <= t_min ; 0463 printf("//intersect_leaf_phicut ipos_x %10.4f ipos_x*1e6f %10.4f cosPhi0 %10.4f x_wrong_side %d \n", ipos_x, ipos_x*1e6f, cosPhi0, x_wrong_side ); 0464 printf("//intersect_leaf_phicut ipos_y %10.4f ipos_y*1e6f %10.4f sinPhi0 %10.4f y_wrong_side %d \n", ipos_y, ipos_y*1e6f, sinPhi0, y_wrong_side ); 0465 printf("//intersect_leaf_phicut ipos_z %10.4f ipos_z*1e6f %10.4f \n", ipos_z, ipos_z*1e6f ); 0466 printf("//intersect_leaf_phicut t_cand %10.4f t_min %10.4f too_close %d \n", t_cand, t_min, too_close ); 0467 } 0468 0469 0470 /* 0471 rays along the phi0 line get t_cand nan from 0/0 0472 BUT as all comparisons with nan yield false the below 0473 also note that signbit(nan) == true which would also invalidate +ve cosPhi0 0474 */ 0475 #endif 0476 0477 if((o.y+t_cand*d.y)*sinPhi0 < 0.f || t_cand <= t_min ) t_cand = RT_DEFAULT_MAX ; 0478 0479 //if((o.x+t_cand*d.x+1e-4)*cosPhi0 < 0.f || t_cand <= t_min ) t_cand = RT_DEFAULT_MAX ; 0480 //if((o.x+t_cand*d.x)*cosPhi0 < 0.f || t_cand < t_min ) t_cand = RT_DEFAULT_MAX ; // t_cand < t_min YIELDS SPURIOUS INTERSECTS 0481 /* 0482 Disqualify wrong side or too close 0483 ^^^^^^^^^^^^^^^^^^ 0484 0485 1. must be t_cand <= t_min to avoid spurious intersects in CSG combination 0486 for rays starting on phi0 line which have t_cand -0.f 0487 0488 * this is because NOT("t_cand > t_min") -> "t_cand <= t_min" 0489 0490 2. At first glance using signbit seems better, but signbit(nan) == true 0491 which means that the t_cand nan does not propagate to the comparison 0492 so the invalidation will only happen for +ve cosPhi0 0493 0494 signbit(o.x+t_cand*d.x) != signbit(cosPhi0) 0495 0496 * actually not invalidating here doesnt matter as the t_cand nan will 0497 simply end up giving a false for valid_intersect 0498 0499 * product (o.x+t_cand*d.x)*cosPhi0 will be nan for t_cand nan and 0500 all comparisons with nan give false so t_cand will stay nan here 0501 0502 * all comparisons with nan always returns false 0503 but that does not kill the entire short circuit OR 0504 (see sysrap/tests/signbitTest.cc) 0505 0506 3. at first glance may think could make the disqualification based only 0507 x or y of intersect BUT that will nor work for all phi0 phi1 angles. 0508 So in general it is necessary to rotate the intersect (x,y) positions 0509 by -phi0 and -phi1 to place it back on the x line. 0510 0511 0512 */ 0513 0514 #ifdef DEBUG 0515 printf("//intersect_leaf_phicut t_cand.1 %10.4f \n", t_cand ); 0516 #endif 0517 0518 const float t1 = -( o.x*(-sinPhi1) + o.y*cosPhi1 )/( d.x*(-sinPhi1) + d.y*cosPhi1 ) ; 0519 if((o.x + t1*d.x)*cosPhi1 > 0.f && t1 > t_min ) t_cand = fminf( t1, t_cand ); 0520 0521 valid_isect = t_cand > t_min && t_cand < RT_DEFAULT_MAX ; 0522 0523 #ifdef DEBUG 0524 //printf("//intersect_leaf_phicut t1_num ( o.x*(-sinPhi1) + o.y*cosPhi1 ) : %10.4f \n", ( o.x*(-sinPhi1) + o.y*cosPhi1 ) ); 0525 //printf("//intersect_leaf_phicut t1_den ( d.x*(-sinPhi1) + d.y*cosPhi1 ) : %10.4f \n", ( d.x*(-sinPhi1) + d.y*cosPhi1 ) ); 0526 //printf("//intersect_leaf_phicut t1 %10.4f \n", t1 ); 0527 //printf("//intersect_leaf_phicut signbit(o.x + t1*d.x) == signbit(cosPhi1) && t1 > t_min : %d \n", signbit(o.x + t1*d.x) == signbit(cosPhi1) && t1 > t_min ); 0528 printf("//intersect_leaf_phicut t_cand.2 %10.4f valid_isect %d \n", t_cand, valid_isect ); 0529 #endif 0530 0531 if( valid_isect ) 0532 { 0533 isect.x = t_cand == t1 ? -sinPhi1 : sinPhi0 ; 0534 isect.y = t_cand == t1 ? cosPhi1 : -cosPhi0 ; 0535 isect.z = 0.f ; 0536 isect.w = t_cand ; 0537 } 0538 else if( unbounded_exit ) 0539 { 0540 isect.y = -isect.y ; // -0.f signflip signalling that can promote MISS to EXIT at infinity 0541 } 0542 } 0543 0544 /** 0545 intersect_leaf_phicut_simple 0546 ----------------------------- 0547 0548 Translation of phicut.py 0549 0550 The solid lines below denote the valid half planes. 0551 For the infinite plane intersection points [0] [1] (0) (1) 0552 0553 0554 p1 [cosPhi1, sinPhi1] 0555 / 0556 / 0557 (1) 0558 /: 0559 / : 0560 / : 0561 . . .{0}. . . +--(0)--------- p0 [ cosPhi0, sinPhi0 ] 0562 : . : 0563 : . : 0564 : . : 0565 : . : 0566 : . : 0567 : . : 0568 : . : 0569 :. : 0570 {1} : 0571 .: : 0572 . : : 0573 . : : 0574 o o 0575 0576 **/ 0577 0578 0579 0580 LEAF_FUNC 0581 void intersect_leaf_phicut_simple( bool& valid_isect, float4& isect, const quad& q0, const float t_min, const float3& o, const float3& d ) 0582 { 0583 const float& cosPhi0 = q0.f.x ; 0584 const float& sinPhi0 = q0.f.y ; 0585 const float& cosPhi1 = q0.f.z ; 0586 const float& sinPhi1 = q0.f.w ; 0587 0588 // dot products for direction and origin with:: 0589 // normal0 [ sinPhi0, -cosPhi0, 0. ] 0590 // normal1 [ -sinPhi1, cosPhi1, 0. ] 0591 0592 float d_n0 = d.x*sinPhi0 + d.y*(-cosPhi0) ; 0593 float d_n1 = d.x*(-sinPhi1) + d.y*(cosPhi1) ; 0594 float o_n0 = o.x*sinPhi0 + o.y*(-cosPhi0) ; 0595 float o_n1 = o.x*(-sinPhi1) + o.y*(cosPhi1) ; 0596 float t0 = d_n0 == 0.f ? t_min : -o_n0/d_n0 ; // intersect distance to Plane0 0597 float t1 = d_n1 == 0.f ? t_min : -o_n1/d_n1 ; // intersect distance to Plane1 0598 0599 const float PR = d_n0 == 0.f ? -o_n0 : -d_n0 ; 0600 const float QR = d_n1 == 0.f ? -o_n1 : -d_n1 ; 0601 const float PQ = cosPhi0*sinPhi1 - cosPhi1*sinPhi0 ; // PQ +ve => angle < pi : wedge, PQ -ve => angle > pi : pacman 0602 bool unbounded_exit = PQ >= 0.f ? ( PR >= 0.f && QR <= 0.f ) : ( PR >= 0.f || QR <= 0.f ) ; 0603 0604 // Disqualify intersects with the wrong halves of the planes. 0605 // When the dot product of the hit point with the unit vector 0606 // within the plane (in valid direction) is positive it means the 0607 // intersect is with the valid half of the plane. When negative 0608 // are intersecting with the non-allowed half of the plane. 0609 // 0610 // sideI = (ray_origin + ray_direction * tI) ยท (cosPhiI, sinPhiI) I={0,1} 0611 0612 float side0 = o.x*cosPhi0 + o.y*sinPhi0 + ( d.x*cosPhi0 + d.y*sinPhi0 )*t0 ; 0613 float side1 = o.x*cosPhi1 + o.y*sinPhi1 + ( d.x*cosPhi1 + d.y*sinPhi1 )*t1 ; 0614 if(side0 < 0.f) t0 = t_min ; 0615 if(side1 < 0.f) t1 = t_min ; 0616 float t_near = fminf(t0,t1); 0617 float t_far = fmaxf(t0,t1); 0618 float t_cand = t_near > t_min ? t_near : ( t_far > t_min ? t_far : t_min ) ; 0619 0620 0621 valid_isect = t_cand > t_min ; 0622 if(valid_isect) 0623 { 0624 isect.x = t_cand == t1 ? -sinPhi1 : sinPhi0 ; 0625 isect.y = t_cand == t1 ? cosPhi1 : -cosPhi0 ; 0626 isect.z = 0.f ; 0627 isect.w = t_cand ; 0628 } 0629 else if( unbounded_exit ) 0630 { 0631 isect.y = -isect.y ; // -0.f signflip signalling that can promote MISS to EXIT at infinity 0632 } 0633 0634 0635 } 0636 0637 0638 0639 0640 0641 0642 0643 0644 0645 0646 0647 0648 0649 0650 0651 0652 0653 0654 0655 0656 0657 0658 0659 0660 0661 0662 0663 0664 0665 0666 0667 0668 0669 0670 0671 0672 0673 0674 /** 0675 intersect_leaf_phicut_lucas 0676 ---------------------------- 0677 0678 Simon's comments on intersect_leaf_phicut_lucas 0679 0680 1. code must stay readable 0681 0682 2. scrunching up code to make it shorter, does not make it faster. 0683 The only way to tell if its faster is to measure it in the context 0684 in which you want to use it. 0685 0686 3. code you write is not what gets run : the compiler performs lots of optimizations on it first 0687 0688 * you should of course help the compiler to know what your intentions are 0689 using const and references to avoid needless copies while still retaining readability 0690 0691 4. for rays starting inside the planes your t_cand and t1 will get divisions by zero and infinities 0692 0693 * that is not necessarily a problem : but you have to think thru what will happen and test the cases 0694 0695 5. disqualification of candidates needs to use t_cand > t_min as for this shape to work 0696 in CSG combination it must perform as expected as t_min is varied 0697 0698 * using the below commandline with a test geometry using phicut will 0699 produce renders that you can use to see how it performs as t_min is varied:: 0700 0701 EYE=1,1,1 TMIN=0.5 ./cxr_geochain.sh 0702 0703 * the required behaviour is for the t_min to cut away the solid in an expanding sphere 0704 shape when using perspective projection (plane when using parallel projection) 0705 0706 0707 | / 0708 | / 0709 | + 0710 | /: 0711 | / : 0712 | / : 0713 | [1]--:- - - - - 0 0714 | /: : accepted sign(xi) == sign(cosPhi1) 0715 |/ : : 0716 . . . . .O--:-- +-----+ X 0717 .: :xi :cosPhi1 0718 . : 0719 *1*- - - - - - - - - 0 disqualified "other half" intersect 0720 . : (-ve x)*(+ve cosPhi1 ) => -ve => disqualified 0721 . : 0722 . : 0723 . : 0724 0725 **/ 0726 0727 LEAF_FUNC 0728 void intersect_leaf_phicut_lucas(bool& valid_isect, float4& isect, const quad& angles, const float& t_min, const float3& ray_origin, const float3& ray_direction) 0729 { //for future reference: angles.f has: .x = cos0, .y = sin0, .z = cos1, .w = sin1 0730 0731 float t_cand = -(angles.f.y * ray_origin.x - angles.f.x * ray_origin.y) / (angles.f.y * ray_direction.x - angles.f.x * ray_direction.y); 0732 //using t_cand saves unnecessary definition (t_cand = -( Norm0 * Or ) / ( Norm0 * Dir ), ratio of magnitudes in the direction of plane) 0733 0734 if (t_cand * angles.f.x * ray_direction.x + angles.f.x * ray_origin.x < 0.f || t_cand <= t_min) 0735 t_cand = RT_DEFAULT_MAX; // disqualify t_cand for wrong side 0736 0737 const float t1 = -(-angles.f.w * ray_origin.x + angles.f.z * ray_origin.y) / (-angles.f.w * ray_direction.x + angles.f.z * ray_direction.y); 0738 if (t1 * angles.f.z * ray_direction.x + angles.f.z * ray_origin.x > 0.f && t1 > t_min) 0739 t_cand = fminf(t1, t_cand); 0740 0741 // angles.f.z * ( t1 * ray_direction.x + ray_origin.x ) 0742 // cosPhi1 * (intersection_x) > 0 0743 0744 0745 valid_isect = t_cand < RT_DEFAULT_MAX; 0746 if (valid_isect) 0747 { 0748 isect.x = t_cand == t1 ? -angles.f.w: angles.f.y; 0749 isect.y = t_cand == t1 ? angles.f.z : -angles.f.x; 0750 isect.z = 0.f; 0751 isect.w = t_cand; 0752 } 0753 } 0754 0755 0756
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|