public static EnumIntersect AabbIntersect(Cuboidd aabb, Cuboidd aabb2, Vec3d motion) { bool beforeIntersect = aabb.Intersects(aabb2); if (beforeIntersect) { return(EnumIntersect.Stuck); } // X bool xIntersect = aabb.X1 <aabb2.X2 + motion.X && aabb.Y1 <aabb2.Y2 && aabb.Z1 <aabb2.Z2 && aabb.X2> aabb2.X1 + motion.X && aabb.Y2> aabb2.Y1 && aabb.Z2> aabb2.Z1 ; if (xIntersect) { return(EnumIntersect.IntersectX); } // Y bool yIntersect = aabb.X1 <aabb2.X2 && aabb.Y1 <aabb2.Y2 + motion.Y && aabb.Z1 <aabb2.Z2 && aabb.X2> aabb2.X1 && aabb.Y2> aabb2.Y1 + motion.Y && aabb.Z2> aabb2.Z1 ; if (yIntersect) { return(EnumIntersect.IntersectY); } // Z bool zIntersect = aabb.X1 <aabb2.X2 && aabb.Y1 <aabb2.Y2 && aabb.Z1 <aabb2.Z2 + motion.Z && aabb.X2> aabb2.X1 && aabb.Y2> aabb2.Y1 && aabb.Z2> aabb2.Z1 + motion.Z ; if (zIntersect) { return(EnumIntersect.IntersectZ); } return(EnumIntersect.NoIntersect); }
public bool RayIntersectsWithCuboid(Cuboidd selectionBox, ref BlockFacing hitOnBlockFace, ref Vec3d hitPosition) { if (selectionBox == null) { return(false); } double w = selectionBox.X2 - selectionBox.X1; double h = selectionBox.Y2 - selectionBox.Y1; double l = selectionBox.Z2 - selectionBox.Z1; for (int i = 0; i < BlockFacing.NumberOfFaces; i++) { BlockFacing blockSideFacing = BlockFacing.ALLFACES[i]; Vec3i planeNormal = blockSideFacing.Normali; // Dot product of 2 vectors // If they are parallel the dot product is 1 // At 90 degrees the dot product is 0 double demon = planeNormal.X * ray.dir.X + planeNormal.Y * ray.dir.Y + planeNormal.Z * ray.dir.Z; // Does intersect this plane somewhere (only negative because we are not interested in the ray leaving a face, negative because the ray points into the cube, the plane normal points away from the cube) if (demon < -0.00001) { Vec3d planeCenterPosition = blockSideFacing.PlaneCenter .ToVec3d() .Mul(w, h, l) .Add(selectionBox.X1, selectionBox.Y1, selectionBox.Z1) ; Vec3d pt = Vec3d.Sub(planeCenterPosition, ray.origin); double t = (pt.X * planeNormal.X + pt.Y * planeNormal.Y + pt.Z * planeNormal.Z) / demon; if (t >= 0) { hitPosition = new Vec3d(ray.origin.X + ray.dir.X * t, ray.origin.Y + ray.dir.Y * t, ray.origin.Z + ray.dir.Z * t); lastExitedBlockFacePos = Vec3d.Sub(hitPosition, planeCenterPosition); // Does intersect this plane within the block if (Math.Abs(lastExitedBlockFacePos.X) <= w / 2 && Math.Abs(lastExitedBlockFacePos.Y) <= h / 2 && Math.Abs(lastExitedBlockFacePos.Z) <= l / 2) { hitOnBlockFace = blockSideFacing; return(true); } } } } return(false); }
/// <summary> /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that. /// </summary> /// <param name="blockAccessor"></param> /// <param name="entityBoxRel"></param> /// <param name="pos"></param> /// <param name="alsoCheckTouch"></param> /// <returns></returns> public Cuboidd GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true) { BlockPos blockPos = new BlockPos(); Vec3d blockPosVec = new Vec3d(); Cuboidd entityBox = entityBoxRel.ToDouble().Translate(pos); entityBox.Y1 = Math.Round(entityBox.Y1, 5); // Fix float/double rounding errors. Only need to fix the vertical because gravity. int minX = (int)(entityBoxRel.X1 + pos.X); int minY = (int)(entityBoxRel.Y1 + pos.Y - 1); // -1 for the extra high collision box of fences int minZ = (int)(entityBoxRel.Z1 + pos.Z); int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X); int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y); int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); blockPosVec.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec); if (colliding) { return(collBox.ToDouble().Translate(blockPos)); } } } } } return(null); }
public Block GetCollidingBlock(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true) { Cuboidd entityBox = tmpBox.SetAndTranslate(entityBoxRel, pos); int minX = (int)(entityBox.X1); int minY = (int)(entityBox.Y1) - 1; // -1 for the extra high collision box of fences int minZ = (int)(entityBox.Z1); int maxX = (int)(entityBox.X2); int maxY = (int)(entityBox.Y2); int maxZ = (int)(entityBox.Z2); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); if (collisionBoxes == null || collisionBoxes.Length == 0) { continue; } blockPosVec.Set(x, y, z); for (int i = 0; i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } if (alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec)) { return(block); } } } } } return(null); }
/// <summary> /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that. /// </summary> /// <param name="blockAccessor"></param> /// <param name="entityBoxRel"></param> /// <param name="pos"></param> /// <param name="alsoCheckTouch"></param> /// <returns></returns> public bool GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, ref Cuboidd intoCubuid, bool alsoCheckTouch = true) { BlockPos blockPos = new BlockPos(); Vec3d blockPosVec = new Vec3d(); Cuboidd entityBox = entityBoxRel.ToDouble().Translate(pos); int minX = (int)(entityBoxRel.X1 + pos.X); int minY = (int)(entityBoxRel.Y1 + pos.Y - 1); // -1 for the extra high collision box of fences int minZ = (int)(entityBoxRel.Z1 + pos.Z); int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X); int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y); int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { Block block = blockAccessor.GetBlock(x, y, z); blockPos.Set(x, y, z); blockPosVec.Set(x, y, z); Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos); for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++) { Cuboidf collBox = collisionBoxes[i]; if (collBox == null) { continue; } bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec); if (colliding) { intoCubuid.Set(collBox).Translate(blockPos); return(true); } } } } } return(false); }
public static bool RayInteresectWithCuboidSlabMethod(Cuboidd b, Ray r) { double tx1 = (b.X1 - r.dir.X) / r.dir.X; double tx2 = (b.X2 - r.dir.X) / r.dir.X; double tmin = Math.Min(tx1, tx2); double tmax = Math.Max(tx1, tx2); double ty1 = (b.Y1 - r.dir.Y) / r.dir.Y; double ty2 = (b.Y2 - r.dir.Y) / r.dir.Y; tmin = Math.Max(tmin, Math.Min(ty1, ty2)); tmax = Math.Min(tmax, Math.Max(ty1, ty2)); double tz1 = (b.Z1 - r.dir.Z) / r.dir.Z; double tz2 = (b.Z2 - r.dir.Z) / r.dir.Z; tmin = Math.Max(tmin, Math.Min(tz1, tz2)); tmax = Math.Min(tmax, Math.Max(tz1, tz2)); return(tmax >= tmin); }