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 + ")"); }
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 + ")"); }