Esempio n. 1
0
        public IEnumerable <CellCastInfo> CastCells(Vector3 origin, Vector3 dir, float maxDistance)
        {
            int     currentX, currentY, currentZ;
            Vector3 intersectPoint, faceNormal;
            T       startCell, endCell, currentCell;

            var ray = new Ray(origin, dir);

            GetCellIndices(origin, out currentX, out currentY, out currentZ);

            intersectPoint = Vector3.zero;

            float   distance = 0f;
            Vector3 normal;

            if (IsValidCell(currentX, currentY, currentZ)) // Started inside a cell
            {
                intersectPoint = origin;
                startCell      = cells[currentX, currentY, currentZ];
            }
            else
            {
                if (bounds.Intersects(ray, maxDistance, out normal, out distance) == false)
                {
                    //Console.Log("Does not intersect grid {0}", this);
                    yield break;
                }

                distance = Mathf.Abs(distance);

                intersectPoint = origin + (dir * distance);
                origin         = intersectPoint + (dir * 0.001f);
                GetCellIndices(origin, out currentX, out currentY, out currentZ);

                if (!IsValidCell(currentX, currentY, currentZ))
                {
                    yield break;
                }

                startCell = cells[currentX, currentY, currentZ];
            }

            var reverseRay = new Ray(ray.origin + (dir * maxDistance), -dir);

            if (bounds.Intersects(ray, maxDistance, out normal, out distance) == false)
            {
                //Console.Log("Does not intersect grid reverse {0}", this);
                yield break;
            }

            //Console.Log("R: {0}, d: {1}", ray, distance);
            distance = Mathf.Abs(distance);

            Vector3 endPoint = reverseRay.origin + (reverseRay.direction * (distance + 0.001f));

            endCell = GetCell(endPoint);

            faceNormal = GetCellFaceNormal(currentX, currentY, currentZ, intersectPoint);
            var castInfo = new CellCastInfo(currentX, currentY, currentZ, startCell, intersectPoint, faceNormal);

            yield return(castInfo);

            Vector3 current = (origin - Position) / CellSize;

            currentX = (int)current.x;
            currentY = (int)current.y;
            currentZ = (int)current.z;
            GetCellIndices(origin, out currentX, out currentY, out currentZ);

            int stepX, stepY, stepZ;

            stepX = dir.x > 0 ? 1 : (dir.x < 0 ? -1 : 0);
            stepY = dir.y > 0 ? 1 : (dir.y < 0 ? -1 : 0);
            stepZ = dir.z > 0 ? 1 : (dir.z < 0 ? -1 : 0);

            Vector3 rayDelta = dir * (maxDistance);

            Vector3 tDelta = Vector3.zero; // size of voxel in terms of t

            if (stepX != 0)
            {
                tDelta.x = CellSize / rayDelta.x;
            }
            else
            {
                tDelta.x = 10000000.0f;
            }

            if (stepY != 0)
            {
                tDelta.y = CellSize / rayDelta.y;
            }
            else
            {
                tDelta.y = 10000000.0f;
            }

            if (stepZ != 0)
            {
                tDelta.z = CellSize / rayDelta.z;
            }
            else
            {
                tDelta.z = 10000000.0f;
            }

            Vector3 tMax = Vector3.zero; // distance to next boundary (in terms of t)

            if (stepX > 0)
            {
                tMax.x = tDelta.x * MathsHelper.FracPos(current.x);
            }
            else
            {
                tMax.x = tDelta.x * MathsHelper.FracNeg(current.x);
            }

            if (stepY > 0)
            {
                tMax.y = tDelta.y * MathsHelper.FracPos(current.y);
            }
            else
            {
                tMax.y = tDelta.y * MathsHelper.FracNeg(current.y);
            }

            if (stepZ > 0)
            {
                tMax.z = tDelta.z * MathsHelper.FracPos(current.z);
            }
            else
            {
                tMax.z = tDelta.z * MathsHelper.FracNeg(current.z);
            }

            currentCell = startCell;
            int        iters    = 0;
            const int  MaxIters = 10000;
            Directions movementDirection;

            while (IsValidCell(currentX, currentY, currentZ) && iters < MaxIters)
            {
                ++iters;
#if DEBUG
                if (iters == MaxIters)
                {
                    Console.LogWarning("Grid cell cast hit max iters");
                }
#endif

                if (Mathf.Abs(tMax.x) < Mathf.Abs(tMax.y))
                {
                    if (Mathf.Abs(tMax.x) < Mathf.Abs(tMax.z))
                    {
                        if (stepX > 0)
                        {
                            movementDirection = Directions.Left;
                        }
                        else
                        {
                            movementDirection = Directions.Right;
                        }

                        currentX += stepX;
                        tMax.x   += tDelta.x;
                    }
                    else
                    {
                        if (stepZ > 0)
                        {
                            movementDirection = Directions.Forward;
                        }
                        else
                        {
                            movementDirection = Directions.Backward;
                        }

                        currentZ += stepZ;
                        tMax.z   += tDelta.z;
                    }
                }
                else
                {
                    if (Mathf.Abs(tMax.y) < Mathf.Abs(tMax.z))
                    {
                        if (stepY > 0)
                        {
                            movementDirection = Directions.Down;
                        }
                        else
                        {
                            movementDirection = Directions.Up;
                        }

                        currentY += stepY;
                        tMax.y   += tDelta.y;
                    }
                    else
                    {
                        if (stepZ > 0)
                        {
                            movementDirection = Directions.Forward;
                        }
                        else
                        {
                            movementDirection = Directions.Backward;
                        }

                        currentZ += stepZ;
                        tMax.z   += tDelta.z;
                    }
                }

                if (!IsValidCell(currentX, currentY, currentZ))
                {
                    break;
                }

                currentCell    = cells[currentX, currentY, currentZ];
                intersectPoint = tMax;
                faceNormal     = GetDirectionVector(movementDirection);

                Bounds cellBounds = GetCellBounds(currentX, currentY, currentZ);
                if (cellBounds.IntersectRay(ray, out distance))
                {
                    intersectPoint = ray.origin + (ray.direction * distance);
                }
                if (distance > maxDistance)
                {
                    //Console.Log("Over max distance {0}", this);
                    yield break;
                }

                castInfo = new CellCastInfo(currentX, currentY, currentZ, currentCell, intersectPoint, faceNormal);

                yield return(castInfo);
            }
        }