public MeshRay TraceRay(Vector3 start, Vector3 dir)
        {
            MeshRay ray = new MeshRay();

            ray.distance = float.PositiveInfinity;

            TraceRecursive(0, start, dir, ref ray);

            ray.hit = ray.distance != float.PositiveInfinity;

            return(ray);
        }
        public MeshRay TraceRaySlow(Vector3 start, Vector3 dir)
        {
            float minT, minU, minV, minW, minS;

            minT = minU = minV = minW = minS = float.PositiveInfinity;

            float t, u, v, w, s;
            bool  hit      = false;
            int   minIndex = 0;

            for (int i = 0; i < NumFaces; ++i)
            {
                Vector3 a = Vertices[Indices[i * 3 + 0]];
                Vector3 b = Vertices[Indices[i * 3 + 1]];
                Vector3 c = Vertices[Indices[i * 3 + 2]];

                if (IntersectRayTriTwoSided(start, dir, a, b, c, out t, out u, out v, out w, out s))
                {
                    if (t < minT)
                    {
                        minT     = t;
                        minU     = u;
                        minV     = v;
                        minW     = w;
                        minS     = s;
                        minIndex = i;
                        hit      = true;
                    }
                }
            }

            MeshRay ray = new MeshRay();

            ray.distance  = minT;
            ray.u         = minU;
            ray.v         = minV;
            ray.w         = minW;
            ray.faceSign  = minS;
            ray.faceIndex = minIndex;
            ray.hit       = hit;

            return(ray);
        }
        private void TraceRecursive(int nodeIndex, Vector3 start, Vector3 dir, ref MeshRay ray)
        {
            AABBNode node = Nodes[nodeIndex];

            if (node.Faces == null)
            {
                // find closest node
                AABBNode leftChild  = Nodes[node.Children + 0];
                AABBNode rightChild = Nodes[node.Children + 1];

                float[] dist = new float[] { float.PositiveInfinity, float.PositiveInfinity };

                IntersectRayAABB(start, dir, leftChild.Bounds.Min, leftChild.Bounds.Max, out dist[0]);
                IntersectRayAABB(start, dir, rightChild.Bounds.Min, rightChild.Bounds.Max, out dist[1]);

                int closest  = 0;
                int furthest = 1;

                if (dist[1] < dist[0])
                {
                    closest  = 1;
                    furthest = 0;
                }

                if (dist[closest] < ray.distance)
                {
                    TraceRecursive(node.Children + closest, start, dir, ref ray);
                }

                if (dist[furthest] < ray.distance)
                {
                    TraceRecursive(node.Children + furthest, start, dir, ref ray);
                }
            }
            else
            {
                float t, u, v, w, s;

                for (int i = 0; i < node.Faces.Length; ++i)
                {
                    int indexStart = node.Faces[i] * 3;

                    Vector3 a = Vertices[Indices[indexStart + 0]];
                    Vector3 b = Vertices[Indices[indexStart + 1]];
                    Vector3 c = Vertices[Indices[indexStart + 2]];

                    if (IntersectRayTriTwoSided(start, dir, a, b, c, out t, out u, out v, out w, out s))
                    {
                        if (t < ray.distance)
                        {
                            ray.distance  = t;
                            ray.u         = u;
                            ray.v         = v;
                            ray.w         = w;
                            ray.faceSign  = s;
                            ray.faceIndex = node.Faces[i];
                        }
                    }
                }
            }
        }
        public void Voxelize(IList <Vector3> vertices, IList <int> indices, Box3 bounds)
        {
            Array.Clear(Voxels, 0, Voxels.Length);

            // build an aabb tree of the mesh
            MeshRayTracer tree = new MeshRayTracer(vertices, indices);

            Bounds = tree.GetBounds();

            // parity count method, single pass
            Vector3 extents = bounds.Size;
            Vector3 delta   = new Vector3(extents.x / Width, extents.y / Height, extents.z / Depth);
            Vector3 offset  = new Vector3(0.5f / Width, 0.5f / Height, 0.5f / Depth);

            float eps = 1e-7f * extents.z;

            for (int x = 0; x < Width; ++x)
            {
                for (int y = 0; y < Height; ++y)
                {
                    bool    inside = false;
                    Vector3 rayDir = new Vector3(0.0f, 0.0f, 1.0f);

                    // z-coord starts somewhat outside bounds
                    Vector3 rayStart = bounds.Min + new Vector3(x * delta.x + offset.x, y * delta.y + offset.y, -0.0f * extents.z);

                    while (true)
                    {
                        MeshRay ray = tree.TraceRay(rayStart, rayDir);

                        if (ray.hit)
                        {
                            // calculate cell in which intersection occurred
                            float zpos = rayStart.z + ray.distance * rayDir.z;
                            float zhit = (zpos - bounds.Min.z) / delta.z;

                            int z    = (int)((rayStart.z - bounds.Min.z) / delta.z);
                            int zend = (int)Math.Min(zhit, Depth - 1);

                            if (inside)
                            {
                                for (int k = z; k <= zend; ++k)
                                {
                                    Voxels[x, y, k] = 1;
                                    Count++;
                                }
                            }

                            inside    = !inside;
                            rayStart += rayDir * (ray.distance + eps);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            //end
        }