/** * 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); }
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); }
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); }
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)); }
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; } } }
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); }
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); }
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); }
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); }
/// <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); }
/// <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); }
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(); }
public WideColor Shoot(Shapes.Ray ray) { return ShootRay(ray, 0); }
public override double GetHitPointDistance(Shapes.Ray r) { return(RaySphere.GetHitPointRaySphereDistance(r.Origin, r.Direction, Position, 0)); }
public override CollisionDetails FindNearestHit(Shapes.Ray ray) { return(Tree.GetFirstCollision(ray)); }
public abstract CollisionDetails FindNearestHit(Shapes.Ray ray);