// experimento ray - tracing public float intersectSegment(Vector3 p, Vector3 q, out ip_data hitinfo) { hitinfo = new ip_data(); hitinfo.nro_face = -1; /* * float min_t = 10000; * Vector3 uvw = new Vector3(); * Vector3 col = new Vector3(); * float t = 0; * for (int i = 0; i < cant_faces; ++i) * { * if (TgcCollisionUtils.intersectSegmentTriangle(p, q, faces[i].v[0], faces[i].v[1], faces[i].v[2], out uvw, out t, out col)) * { * if (t < min_t) * min_t = t; * } * } * return min_t; */ // test kd tree float min_t = 10000; Vector3 dir = q - p; float dist = dir.Length(); dir.Normalize(); if (kd_tree.ray_intersects(p, dir, out ip_data Ip)) { float t = Ip.t / dist; if (t <= 1) { min_t = t; hitinfo = Ip; } } return(min_t); }
public bool ray_intersects(Vector3 O, Vector3 D, out ip_data I) { float R = 10000000; float bc_b = 0; float bc_g = 0; int nro_face = -1; I = new ip_data(); // chequeo la interseccion con el bounding box de la escena o if (!box_intersection(bb_min, bb_max, O, D, out float tnear, out float tfar)) { // el rayo no interseca con la escena return(false); } // precomputo la inv de direccion del rayo float [] ray_invdir = { 0, 0, 0 }; if (Math.Abs(D.X) > 0.00001) { ray_invdir[0] = 1.0f / D.X; } if (Math.Abs(D.Y) > 0.00001) { ray_invdir[1] = 1.0f / D.Y; } if (Math.Abs(D.Z) > 0.00001) { ray_invdir[2] = 1.0f / D.Z; } float [] ray_O = { O.X, O.Y, O.Z }; float [] ray_dir = { D.X, D.Y, D.Z }; // comienzo el traverse con el nodo root = (kd_tree, tnear, tfar) kd_node p_node = kd_tree; // pila de pendientes int p_stack = 0; st_traverse_node [] S = new st_traverse_node[64]; while (p_node != null) { // el rayo atraviesa el nodo p_node entrando por tnear y saliendo por tfar. if (p_node.p_list != null) { // nodo hoja: chequeo la interseccion con la lista de caras en dicho nodo for (int i = 0; i < p_node.cant_f; ++i) { int n = p_node.p_list[i]; if (triangle_ray(n, O, D, out float t, out float b, out float g)) { if (t > 1 && t < R && t >= tnear - 1 && t <= tfar + 1) { // actualizo las coordenadas barycentricas bc_b = b; bc_g = g; R = t; nro_face = n; } } } // early termination if (nro_face != -1) { I.ip = O + D * R; I.t = R; I.bc_b = bc_b; I.bc_g = bc_g; I.nro_face = nro_face; return(true); } // termine de procesar la rama (llegue a un nodo hoja). Si tengo algo pendiente en la pila, lo saco de ahi if (p_stack > 0) { p_stack--; p_node = S[p_stack].p_nodo; tnear = S[p_stack].tnear; tfar = S[p_stack].tfar; } else { p_node = null; // termino } } else { // si es un nodo interior: // determino en que orden tengo que chequear los nodos hijos int p = p_node.split_plane; float tplane = (p_node.split - ray_O[p]) * ray_invdir[p]; kd_node p_near, p_far; if (ray_O[p] <= p_node.split || (ray_O[p] == p_node.split && ray_dir[p] <= 0)) { // proceso primero el Left node y luego el Right node p_near = p_node.p_left; p_far = p_node.p_right; } else { // proceso primero el Right node y luego el Left node p_near = p_node.p_right; p_far = p_node.p_left; } // para procesar ambos nodos el tplane tiene que estar entre tnear y tfar if (tplane > tfar || tplane <= 0) { // el rayo solo pasa por el primer nodo (el nodo cercano) : avanzo hacia el nodo cercano p_node = p_near; } else if (tplane < tnear) { // el rayo solo pasa por el segundo nodo (el nodo lejano) : avanzo hacia el nodo lejano p_node = p_far; } else { // pasa por ambos nodos: // tengo que evaluar el segundo nodo luego del primero, asi que lo pongo en la pila de pendientes // el nodo far va desde tplane hasta tfar S[p_stack].p_nodo = p_far; S[p_stack].tnear = tplane; S[p_stack].tfar = tfar; p_stack++; //if(p_stack>max_todo) //max_todo =p_stack; // a continuacion proceso el nodo cercano: que va desde tnear, hasta tplane p_node = p_near; tfar = tplane; // tnear queda como esta } } } return(false); }