示例#1
0
文件: Node.cs 项目: FrankyBoy/JRayX
        /**
         * March through Octree checking collisions. Every node on the way (when traversing to leaf direction) is checked for hits.
         *
         * @param v point to search for
         * @param c collision details
         * @return smallest node containing v, or null if (and only if) v is not inside the tree
         */

        public Node MarchToCheckingCollisions(Vect3 v, CollisionDetails c, Shapes.Ray ray)
        {
            if (Encloses(v))
            {
                if (_child == null)
                {
                    return(this);
                }

                foreach (Node n in _child)
                {
                    if (n.Encloses(v))
                    {
                        c.CheckCollisionSet(n.Content, ray);
                        return(n.MarchToCheckingCollisions(v, c, ray));
                    }
                }

                return(this);
            }
            if (_parent != null)
            {
                return(_parent.MarchToCheckingCollisions(v, c, ray));
            }
            return(null);
        }
示例#2
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);
        }
示例#3
0
        public override double GetHitPointDistance(Shapes.Ray r)
        {
            double dist;

            Shapes.Ray subRay;
            Vect3      tmp = Position + _model.GetBoundingSphere().Position;

            if (RaySphere.IsRayOriginatingInSphere(r.Origin, r.Direction, tmp,
                                                   _model.GetBoundingSphere().Radius))
            {
                tmp    = r.Origin - Position;
                subRay = new Shapes.Ray
                {
                    Origin    = tmp,
                    Direction = r.Direction
                };

                dist = 0;
            }
            else
            {
                dist = RaySphere.GetHitPointRaySphereDistance(r.Origin, r.Direction, tmp,
                                                              _model.GetBoundingSphere().Radius);

                if (double.IsInfinity(dist))
                {
                    return(dist);
                }

                tmp    = r.Origin + r.Direction * dist;
                tmp   -= Position;
                subRay = new Shapes.Ray
                {
                    Origin    = tmp,
                    Direction = r.Direction
                };
            }

            var d = new CollisionData
            {
                Details = RayPath.GetFirstCollision(_model.GetTree(), subRay)
            };

            if (!double.IsInfinity(d.Details.Distance))
            {
                Vect3 hitPointLocal = subRay.Origin + subRay.Direction * d.Details.Distance;
                d.HitPointLocal = hitPointLocal;
                Vect3 hitPointGlobal = hitPointLocal + Position;
                d.HitPointGlobal = hitPointGlobal;
                return(d.Details.Distance + dist);
            }
            _lastCollision[Thread.CurrentThread] = d;
            return(d.Details.Distance);
        }
示例#4
0
        public CollisionDetails GetFirstCollision(Shapes.Ray ray)
        {
            // which three sides do we need to perform a collision check with?
            // value > 0 means vect shows in that direction, so nearer side has to be
            // the one with opposite signs
            bool useBiggerX = ray.Direction.X < 0;
            bool useBiggerY = ray.Direction.Y < 0;
            bool useBiggerZ = ray.Direction.Z < 0;

            return(GetFirstCollisionInternal(ray, true, useBiggerX, useBiggerY, useBiggerZ));
        }
示例#5
0
 public void CheckCollisionSet(List <I3DObject> objects, Shapes.Ray ray)
 {
     foreach (I3DObject candidate in objects)
     {
         double distanceCandidate = candidate.GetHitPointDistance(ray);
         if (distanceCandidate > Constants.EPS && distanceCandidate < Distance)
         {
             Obj      = candidate;
             Distance = distanceCandidate;
         }
     }
 }
示例#6
0
        public override double GetHitPointDistance(Shapes.Ray r)
        {
            Vect3 v1v2 = V2 - Position;
            Vect3 v1v3 = V3 - Position;

            double ret = RayTriangle.GetHitPointRayTriangleDistance(r.Origin, r.Direction, Position, v1v2, v1v3);

            if (ret <= 0)
            {
                return(double.PositiveInfinity);
            }
            return(ret);
        }
示例#7
0
        public override CollisionDetails FindNearestHit(Shapes.Ray ray)
        {
            var c = new CollisionDetails();

            //Find nearest Hit
            foreach (I3DObject objectCandidate in _objects)
            {
                double distanceCandidate = objectCandidate.GetHitPointDistance(ray);
                if (distanceCandidate > 0 && distanceCandidate < c.Distance)
                {
                    c.Obj      = objectCandidate;
                    c.Distance = distanceCandidate;
                }
            }

            return(c);
        }
示例#8
0
        protected override WideColor ShootRay(Shapes.Ray ray, int level)
        {
            if (level == MaxRecursionDepth)
            {
                return(Color.Red.ToWide());
            }

            //Find nearest Hit
            CollisionDetails c = Scene.FindNearestHit(ray);

            //No hit
            if (c.Obj == null || double.IsInfinity(c.Distance))
            {
                // TODO: actually use the scene sky here!
                return(Color.White.ToWide());
            }

            //Calculate hit position
            Vect3 hitPoint = ray.Origin + ray.Direction * c.Distance;

            //Get color and normal at hitpoint
            WideColor color  = c.Obj.GetColorAt(hitPoint).ToWide();
            Vect3     normal = c.Obj.GetNormalAt(hitPoint);

            //Check if anything is blocking direct sunlight (go where the sunlight comes from)
            Vect3 lrDir    = Scene.AmbientLightDirection * -1;
            var   lightRay = new Shapes.Ray
            {
                Origin    = hitPoint,
                Direction = lrDir
            };
            CollisionDetails lc = Scene.FindNearestHit(lightRay);

            //if nothing blocks the sun's light, add ambient and diffuse light, otherwise ambient only
            double lightScale = 0;

            if (lc.Obj == null)
            {
                lightScale = normal * Scene.AmbientLightDirection;
            }
            lightScale = AmbientLightIntensity + DiffuseLightIntensity * (lightScale < 0 ? -lightScale : 0);

            return(color * lightScale);
        }
示例#9
0
        private CollisionDetails GetFirstCollisionInternal(Shapes.Ray ray, bool isRayInside, bool useBiggerX, bool useBiggerY, bool useBiggerZ)
        {
            var result = new CollisionDetails {
                Distance = double.PositiveInfinity
            };

            if (isRayInside) // recheck because ray was inside parent
            {
                isRayInside = PointCube.Encloses(_center, _halfWidth, ray.Origin);
            }

            // not inside and no hit -> return
            if (!isRayInside && double.IsInfinity(RayIntersectionDistance(ray, useBiggerX, useBiggerY, useBiggerZ)))
            {
                return(result);
            }


            if (_children != null && _children.Length > 0)
            {
                foreach (var child in _children)
                {
                    var collision = child.GetFirstCollisionInternal(ray, isRayInside, useBiggerX, useBiggerY, useBiggerZ);
                    if (!double.IsInfinity(collision.Distance))
                    {
                        result = collision;
                        break;
                    }
                }
            }

            foreach (var o3D in _objects)
            {
                double distance = o3D.GetHitPointDistance(ray);
                if (distance > 0 && distance < result.Distance)
                {
                    result.Obj      = o3D;
                    result.Distance = distance;
                }
            }

            return(result);
        }
示例#10
0
        /// <summary>
        /// Evaluate one side of the cube for collision
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="normal"></param>
        /// <param name="center"></param>
        /// <returns></returns>
        private double SideRayIntersectionDistance(Shapes.Ray ray, Vect3 normal, Vect3 center)
        {
            var distance = RayPlane.GetHitPointRayPlaneDistance(ray.Origin, ray.Direction, center, normal);

            if (double.IsInfinity(distance))
            {
                return(distance);
            }


            var relativeHitPoint = (ray.Origin + (ray.Direction * distance)) - center;

            if (relativeHitPoint.X <= _halfWidth && relativeHitPoint.Y <= _halfWidth && relativeHitPoint.Z <= _halfWidth)
            {
                return(distance);
            }

            return(double.PositiveInfinity);
        }
示例#11
0
        /// <summary>
        /// Get the nearest intersection with the cube
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="useBiggerX"></param>
        /// <param name="useBiggerY"></param>
        /// <param name="useBiggerZ"></param>
        /// <returns></returns>
        private double RayIntersectionDistance(Shapes.Ray ray, bool useBiggerX, bool useBiggerY, bool useBiggerZ)
        {
            if (PointCube.Encloses(_center, _halfWidth, ray.Origin))
            {
                return(0);
            }

            var normal = new Vect3 {
                X = useBiggerX ? _halfWidth : -_halfWidth
            };
            var    planeCenter = _center + normal;
            double distance    = SideRayIntersectionDistance(ray, normal, planeCenter);

            // we can return instantly as we only evaluate the hear side -> only one side should be hit at any time
            if (!double.IsInfinity(distance))
            {
                return(distance);
            }

            normal = new Vect3 {
                Y = useBiggerY ? _halfWidth : -_halfWidth
            };
            planeCenter = _center + normal;
            distance    = SideRayIntersectionDistance(ray, normal, planeCenter);
            if (!double.IsInfinity(distance))
            {
                return(distance);
            }

            normal = new Vect3 {
                Z = useBiggerZ ? _halfWidth : -_halfWidth
            };
            planeCenter = _center + normal;
            distance    = SideRayIntersectionDistance(ray, normal, planeCenter);
            if (!double.IsInfinity(distance))
            {
                return(distance);
            }

            return(double.PositiveInfinity);
        }
示例#12
0
        protected virtual WideColor ShootRay(Shapes.Ray ray, int level)
        {
            if (level == MaxRecursionDepth)
            {
                return Color.Red.ToWide();
            }

            //Find nearest Hit
            CollisionDetails c = Scene.FindNearestHit(ray);

            //No hit
            if (c.Obj == null)
            {
                return Color.White.ToWide();
            }

            //Calculate hit point
            Vect3 hitPoint = ray.Origin + ray.Direction*c.Distance;

            //Return object's color at hit point
            return c.Obj.GetColorAt(hitPoint).ToWide();
        }
示例#13
0
 public WideColor Shoot(Shapes.Ray ray)
 {
     return ShootRay(ray, 0);
 }
示例#14
0
 public override double GetHitPointDistance(Shapes.Ray r)
 {
     return(RaySphere.GetHitPointRaySphereDistance(r.Origin, r.Direction, Position, 0));
 }
示例#15
0
 public override CollisionDetails FindNearestHit(Shapes.Ray ray)
 {
     return(Tree.GetFirstCollision(ray));
 }
示例#16
0
 public abstract CollisionDetails FindNearestHit(Shapes.Ray ray);