Ejemplo n.º 1
0
        // 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);
        }
Ejemplo n.º 2
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);
        }