Пример #1
0
        public static CollisionDetails GetFirstCollision(Octree tree, Shapes.Ray r)
        {
            var c = new CollisionDetails {
                Distance = double.PositiveInfinity
            };

            double distanceTravelled = 0; //distance traveled since the ray's origin

            //Algorithm starts at the ray's origin and in the root node.

            Node n = tree.GetRoot();

            c.CheckCollisionSet(n.Content, r);

            var pos = r.Origin;

            if (!n.Encloses(pos))
            {
                throw new Exception("Ray's origin is not located in the octree!");
            }

            do
            {
                //March to the leaf containing "pos" and check collisions
                n = n.MarchToCheckingCollisions(pos, c, r);

                //No leaf is containing "pos" -> left tree -> stop searching
                if (n == null)
                {
                    break;
                }

                //march out of current node
                double d = RayCube.GetDistanceToBorderPlane(pos, r.Direction, n.Center, n.Width / 2) + Constants.EPS * 1e4;
                //distance traveled since the ray's origin
                pos = pos + r.Direction * d;
                distanceTravelled += d;

                //in case eps was not enough
                while (n.Encloses(pos))
                {
                    d   = Constants.EPS * 1e4;
                    pos = pos + r.Direction * d;
                    distanceTravelled += d;
                }

                /**
                 * When passing a box-border, all intersection tests between the ray's origin and the
                 * box-border-intersection-point must have taken place (and some beyond the box-border too).
                 * Therefore, if an intersection located between the ray's origin and the box-border has been found, this
                 * must be the nearest intersection and the search may stop.
                 */
            } while (c.Distance > distanceTravelled);

            return(c);
        }
Пример #2
0
        public static Octree BuildTree(Vect3 center, IList <I3DObject> objects)
        {
            double maxQuadDist = 0;

            Log.Debug("Building octree... ");

            foreach (I3DObject o in objects)
            {
                Sphere s = o.GetBoundingSphere();
                if (s != null)
                {
                    Vect3  dist  = center - s.Position;
                    double qdist = s.Radius;
                    if (double.IsInfinity(qdist) || Double.IsNaN(qdist))
                    {
                        throw new Exception("Invalid BoundingSphere: " + s + " from " + o);
                    }
                    qdist = qdist * qdist + dist.QuadLength();
                    if (maxQuadDist < qdist)
                    {
                        maxQuadDist = qdist;
                    }
                }
            }

            /**
             * Workaround: *2.1 instead of *2, because rays must always start inside an octree for RayPath.
             * To fix this problem, a RayPath should allow ray-origins outside the octree, but this would need
             * an additional ray-cube intersection test which is currently not implemented. Another downside of
             * this is that the camera must always be located inside the octree - it must not be moved outside.
             */
            double sizeHint = System.Math.Sqrt(maxQuadDist) * 2.1;

            Sw.Restart();
            Octree t;

            while (true)
            {
                t = new Octree(center, sizeHint);
                foreach (I3DObject o in objects)
                {
                    if (!t.Root.Insert(o, o.GetBoundingSphere()))
                    {
                        sizeHint *= 2;
                        Log.Warn("Warning - resize needed!");
                        goto cont;
                    }
                }
                break;

cont:
                {
                }
            }

            t.GetRoot().Compress();
            Sw.Stop();

            Log.Debug(string.Format("{0} ms\n", Sw.ElapsedMilliseconds));
            Log.Debug(string.Format(" - contains {0} of {1} elements ({2:0.##}%)",
                                    t.GetRoot().GetSize(), objects.Count,
                                    t.GetRoot().GetSize() / (float)objects.Count * 100));
            Log.Debug(" - avg depth: " + t.GetAverageObjectDepth());
            Log.Debug(" - node count: " + t.GetRoot().GetNodeCount());
            Log.Debug(" - objects per node: " + t.GetRoot().GetSize() / (float)t.GetRoot().GetNodeCount());

            return(t);
        }