private List<RaycastHitResult> RaycastAllInternal(Ray ray) { if (Map == null) throw new InvalidOperationException("Cannot raycast against an unloaded map!"); List<RaycastHitResult> returnResults = new List<RaycastHitResult>(); foreach (Room room in Map.Rooms) { foreach (var entity in room.Entities) { if (!Map.LayerIsVisible(entity.Layer)) continue; SceneComponent sceneEntity = entity as SceneComponent; if (sceneEntity == null) continue; Vector3 aabbMin, aabbMax; sceneEntity.GetAABB(out aabbMin, out aabbMax); float intersectionDist; if (RayIntersectsAABB(ray, aabbMin, aabbMax, out intersectionDist)) { RaycastHitResult result = new RaycastHitResult(); result.Distance = intersectionDist; result.Entity = entity; returnResults.Add(result); } } } // Sort the results - nearest to furthest. returnResults = returnResults.OrderBy(x => x.Distance).ToList(); return returnResults; }
/// <summary> /// Returns all results (sorted in closest to furthest) order which intersect the <see cref="Ray"/>, or an /// empty list if there are no results. /// </summary> /// <param name="ray"></param> /// <returns></returns> public List<MapEntity> RaycastAll(Ray ray) { var allResults = RaycastAllInternal(ray); List<MapEntity> outputList = new List<MapEntity>(); foreach (var result in allResults) outputList.Add(result.Entity); return outputList; }
private static bool RayIntersectsAABB(Ray ray, Vector3 aabbMin, Vector3 aabbMax, out float intersectionDistance) { Vector3 t_1 = new Vector3(), t_2 = new Vector3(); float tNear = float.MinValue; float tFar = float.MaxValue; // Test infinite planes in each directin. for (int i = 0; i < 3; i++) { // Ray is parallel to planes in this direction. if (ray.Direction[i] == 0) { if ((ray.Origin[i] < aabbMin[i]) || (ray.Origin[i] > aabbMax[i])) { // Parallel and outside of the box, thus no intersection is possible. intersectionDistance = float.MinValue; return false; } } else { t_1[i] = (aabbMin[i] - ray.Origin[i]) / ray.Direction[i]; t_2[i] = (aabbMax[i] - ray.Origin[i]) / ray.Direction[i]; // Ensure T_1 holds values for intersection with near plane. if (t_1[i] > t_2[i]) { Vector3 temp = t_2; t_2 = t_1; t_1 = temp; } if (t_1[i] > tNear) tNear = t_1[i]; if (t_2[i] < tFar) tFar = t_2[i]; if ((tNear > tFar) || (tFar < 0)) { intersectionDistance = float.MinValue; return false; } } } intersectionDistance = tNear; return true; }
/// <summary> /// Returns the closest result which intersects the Ray, or null if there is nothing. /// </summary> /// <param name="ray">Ray along which to check for intersections.</param> /// <returns>Closest MapEntity, or null if none.</returns> public MapEntity Raycast(Ray ray) { var allEnts = RaycastAllInternal(ray); if (allEnts.Count > 0) return allEnts[0].Entity; return null; }