Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        // 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 + ")");
        }
Пример #4
0
        /// <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 + ")");
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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 + ")");
        }
Пример #8
0
        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 + ")");
        }