Beispiel #1
0
 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);
 }
Beispiel #2
0
 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);
 }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }