public void createKDTree() { max_deep = ((int)(8 + 1.3f * (float)Math.Log(cant_faces))); // creo un nodo con toda la escena int[] p_list = new int[cant_faces]; for (int i = 0; i < cant_faces; ++i) { p_list[i] = i; } kd_tree = createKDTreeNode(bb_min, bb_max, 0, cant_faces, p_list); }
public void deleteKDTreeNode(kd_node p_node) { if (p_node.p_left != null) { deleteKDTreeNode(p_node.p_left); } if (p_node.p_right != null) { deleteKDTreeNode(p_node.p_right); } if (p_node.p_list != null) { p_node.p_list = null; } //SAFE_DELETE(p_node); }
public int countKDTreeNodes(kd_node p_node) { int rta = 0; if (p_node.p_list != null) { rta += p_node.cant_f; } if (p_node.p_left != null) { rta += countKDTreeNodes(p_node.p_left); } if (p_node.p_right != null) { rta += countKDTreeNodes(p_node.p_right); } return(rta); }
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); }
public kd_node createKDTreeNode(Vector3 pmin, Vector3 pmax, int deep, int cant_f, int [] p_list) { kd_node p_node = new kd_node(); p_node.deep = deep; p_node.p_min = pmin; p_node.p_max = pmax; // creo un nodo leaf p_node.cant_f = cant_f; p_node.p_list = p_list; // si la cantidad de primitivas en el nodo es mayor a cierto limite y el deep no supera el maximo, pruebo dividir el nodo if (cant_f >= MAX_FACE_X_NODE && deep < max_deep) { // divido el nodo en 2: Vector3 dim = pmax - pmin; Vector3 Lmin, Lmax, Rmin, Rmax; int eje; float s; // version eje fijo: selecciono el eje en base a la direccion que mas extension tiene { if (MathF.Abs(dim.Z) >= MathF.Abs(dim.X) && MathF.Abs(dim.Z) >= MathF.Abs(dim.Y)) { eje = 2; // split Z s = (pmin.Z + pmax.Z) * 0.5f; } else if (MathF.Abs(dim.X) >= MathF.Abs(dim.Z) && MathF.Abs(dim.X) >= MathF.Abs(dim.Y)) { eje = 0; // splite X s = (pmin.X + pmax.X) * 0.5f; } else { eje = 1; // split Y s = (pmin.Y + pmax.Y) * 0.5f; } //s = best_split(eje,p_node); } /* * else * { * // version que prueba los 3 ejes: * eje = best_split(p_node, &s); * } */ p_node.split = s; p_node.split_plane = eje; Rmin = Lmin = pmin; Rmax = Lmax = pmax; switch (eje) { case 0: Lmax.X = s; Rmin.X = s; break; case 1: Lmax.Y = s; Rmin.Y = s; break; case 2: Lmax.Z = s; Rmin.Z = s; break; } // clasifico las primitivas int cant_L = 0; int cant_R = 0; int[] list_L = new int[cant_f]; int[] list_R = new int[cant_f]; for (int i = 0; i < cant_f; ++i) { bsp_face f = F[p_list[i]]; if (box_overlap(f.pmin, f.pmax, Lmin, Lmax)) { list_L[cant_L++] = p_list[i]; } if (box_overlap(f.pmin, f.pmax, Rmin, Rmax)) { list_R[cant_R++] = p_list[i]; } } // hago el nodo interior: // libero la memoria original /* * if (p_node.p_list) * { * delete[] p_node.p_list; * p_node.p_list = NULL; * }*/ p_node.p_list = null; // creo los 2 nodos hijos p_node.p_left = createKDTreeNode(Lmin, Lmax, deep + 1, cant_L, list_L); p_node.p_right = createKDTreeNode(Rmin, Rmax, deep + 1, cant_R, list_R); } return(p_node); }