static bool CameraClip(Game game, PickedPos pos) { if (BlockInfo.Draw[t.Block] == DrawType.Gas || BlockInfo.Collide[t.Block] != CollideType.Solid) { return(false); } float t0, t1; const float adjust = 0.1f; if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1)) { return(false); } Vector3 I = t.Origin + t.Dir * t0; pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I); switch (pos.Face) { case BlockFace.XMin: pos.Intersect.X -= adjust; break; case BlockFace.XMax: pos.Intersect.X += adjust; break; case BlockFace.YMin: pos.Intersect.Y -= adjust; break; case BlockFace.YMax: pos.Intersect.Y += adjust; break; case BlockFace.ZMin: pos.Intersect.Z -= adjust; break; case BlockFace.ZMax: pos.Intersect.Z += adjust; break; } return(true); }
static bool PickBlock(Game game, PickedPos pos) { if (!game.CanPick(t.Block)) { return(false); } // This cell falls on the path of the ray. Now perform an additional bounding box test, // since some blocks do not occupy a whole cell. float t0, t1; if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1)) { return(false); } Vector3 I = t.Origin + t.Dir * t0; // Only pick the block if the block is precisely within reach distance. float lenSq = (I - t.Origin).LengthSquared; float reach = game.LocalPlayer.ReachDistance; if (lenSq <= reach * reach) { pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I); } else { pos.SetAsInvalid(); } return(true); }
// http://www.xnawiki.com/index.php/Voxel_traversal // https://web.archive.org/web/20120113051728/http://www.xnawiki.com/index.php?title=Voxel_traversal /// <summary> Determines the picked block based on the given origin and direction vector.<br/> /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries /// or not being able to find a suitable candiate within the given reach distance. </summary> public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos) { // Implementation based on: "A Fast Voxel Traversal Algorithm for Ray Tracing" // John Amanatides, Andrew Woo // http://www.cse.yorku.ca/~amana/research/grid.pdf // http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf // The cell in which the ray starts. Vector3I start = Vector3I.Floor(origin); // Rounds the position's X, Y and Z down to the nearest integer values. int x = start.X, y = start.Y, z = start.Z; Vector3I step, cellBoundary; Vector3 tMax, tDelta; CalcVectors(origin, dir, out step, out cellBoundary, out tMax, out tDelta); Map map = game.Map; BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; // For each step, determine which distance to the next voxel boundary is lowest (i.e. // which voxel boundary is nearest) and walk that way. while (iterations < 10000) { byte block = GetBlock(map, x, y, z, origin); Vector3 min = new Vector3(x, y, z) + info.MinBB[block]; Vector3 max = new Vector3(x, y, z) + info.MaxBB[block]; float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X)); float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y)); float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z)); if (dx * dx + dy * dy + dz * dz > reachSquared) { pickedPos.SetAsInvalid(); return; } if (game.CanPick(block)) { // This cell falls on the path of the ray. Now perform an additional bounding box test, // since some blocks do not occupy a whole cell. float t0, t1; if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1)) { Vector3 intersect = origin + dir * t0; pickedPos.SetAsValid(x, y, z, min, max, block, intersect); return; } } Step(ref tMax, ref tDelta, ref step, ref x, ref y, ref z); iterations++; } throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " + "Something has gone wrong. (dir: " + dir + ")"); }
/// <summary> Determines the picked block based on the given origin and direction vector.<br/> /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries /// or not being able to find a suitable candiate within the given reach distance. </summary> public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos) { tracer.SetRayData(origin, dir); World map = game.World; BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; Vector3I pOrigin = Vector3I.Floor(origin); while (iterations < 10000) { int x = tracer.X, y = tracer.Y, z = tracer.Z; byte block = GetBlock(map, x, y, z, pOrigin); Vector3 min = new Vector3(x, y, z) + info.MinBB[block]; Vector3 max = new Vector3(x, y, z) + info.MaxBB[block]; if (info.IsLiquid[block]) { min.Y -= 1.5f / 16; max.Y -= 1.5f / 16; } float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X)); float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y)); float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z)); if (dx * dx + dy * dy + dz * dz > reachSquared) { pickedPos.SetAsInvalid(); return; } if (game.CanPick(block)) { // This cell falls on the path of the ray. Now perform an additional bounding box test, // since some blocks do not occupy a whole cell. float t0, t1; if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1)) { Vector3 intersect = origin + dir * t0; pickedPos.SetAsValid(x, y, z, min, max, block, intersect); return; } } tracer.Step(); iterations++; } throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " + "Something has gone wrong. (dir: " + dir + ")"); }
static bool PickBlock(Game game, PickedPos pos) { if (!game.CanPick(t.Block)) { return(false); } // This cell falls on the path of the ray. Now perform an additional bounding box test, // since some blocks do not occupy a whole cell. float t0, t1; if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1)) { return(false); } Vector3 I = t.Origin + t.Dir * t0; pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I); return(true); }
static bool CameraClip(Game game, PickedPos pos) { if (BlockInfo.Draw[t.Block] == DrawType.Gas || BlockInfo.Collide[t.Block] != CollideType.Solid) { return(false); } float t0, t1; if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1)) { return(false); } // Need to collide with slightly outside block, to avoid camera clipping issues t.Min -= adjust; t.Max += adjust; Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1); Vector3 I = t.Origin + t.Dir * t0; pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I); return(true); }
public static void ClipCameraPos(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos) { if (!game.CameraClipping) { pickedPos.SetAsInvalid(); pickedPos.IntersectPoint = origin + dir * reach; return; } Vector3I start = Vector3I.Floor(origin); int x = start.X, y = start.Y, z = start.Z; Vector3I step, cellBoundary; Vector3 tMax, tDelta; CalcVectors(origin, dir, out step, out cellBoundary, out tMax, out tDelta); Map map = game.Map; BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; while (iterations < 10000) { byte block = GetBlock(map, x, y, z, origin); Vector3 min = new Vector3(x, y, z) + info.MinBB[block]; Vector3 max = new Vector3(x, y, z) + info.MaxBB[block]; float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X)); float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y)); float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z)); if (dx * dx + dy * dy + dz * dz > reachSquared) { pickedPos.SetAsInvalid(); pickedPos.IntersectPoint = origin + dir * reach; return; } if (info.CollideType[block] == BlockCollideType.Solid && !info.IsAir[block]) { float t0, t1; const float adjust = 0.1f; if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1)) { Vector3 intersect = origin + dir * t0; pickedPos.SetAsValid(x, y, z, min, max, block, intersect); switch (pickedPos.BlockFace) { case CpeBlockFace.XMin: pickedPos.IntersectPoint.X -= adjust; break; case CpeBlockFace.XMax: pickedPos.IntersectPoint.X += adjust; break; case CpeBlockFace.YMin: pickedPos.IntersectPoint.Y -= adjust; break; case CpeBlockFace.YMax: pickedPos.IntersectPoint.Y += adjust; break; case CpeBlockFace.ZMin: pickedPos.IntersectPoint.Z -= adjust; break; case CpeBlockFace.ZMax: pickedPos.IntersectPoint.Z += adjust; break; } return; } } Step(ref tMax, ref tDelta, ref step, ref x, ref y, ref z); iterations++; } throw new InvalidOperationException("did over 10000 iterations in ClipCameraPos(). " + "Something has gone wrong. (dir: " + dir + ")"); }
public static void ClipCameraPos(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos) { if (!game.CameraClipping) { pickedPos.SetAsInvalid(); pickedPos.IntersectPoint = origin + dir * reach; return; } tracer.SetRayData(origin, dir); World map = game.World; BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; Vector3I pOrigin = Vector3I.Floor(origin); while (iterations < 10000) { int x = tracer.X, y = tracer.Y, z = tracer.Z; byte block = GetBlock(map, x, y, z, pOrigin); Vector3 min = new Vector3(x, y, z) + info.MinBB[block]; Vector3 max = new Vector3(x, y, z) + info.MaxBB[block]; if (info.IsLiquid[block]) { min.Y -= 1.5f / 16; max.Y -= 1.5f / 16; } float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X)); float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y)); float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z)); if (dx * dx + dy * dy + dz * dz > reachSquared) { pickedPos.SetAsInvalid(); pickedPos.IntersectPoint = origin + dir * reach; return; } if (info.Collide[block] == CollideType.Solid && !info.IsAir[block]) { float t0, t1; const float adjust = 0.1f; if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1)) { Vector3 intersect = origin + dir * t0; pickedPos.SetAsValid(x, y, z, min, max, block, intersect); switch (pickedPos.BlockFace) { case CpeBlockFace.XMin: pickedPos.IntersectPoint.X -= adjust; break; case CpeBlockFace.XMax: pickedPos.IntersectPoint.X += adjust; break; case CpeBlockFace.YMin: pickedPos.IntersectPoint.Y -= adjust; break; case CpeBlockFace.YMax: pickedPos.IntersectPoint.Y += adjust; break; case CpeBlockFace.ZMin: pickedPos.IntersectPoint.Z -= adjust; break; case CpeBlockFace.ZMax: pickedPos.IntersectPoint.Z += adjust; break; } return; } } tracer.Step(); iterations++; } throw new InvalidOperationException("did over 10000 iterations in ClipCameraPos(). " + "Something has gone wrong. (dir: " + dir + ")"); }