Beispiel #1
0
        public bool RaytraceCollision(Vector3 origin, Vector3 direction, float maxDistance, bool ignoreStartAndEnd, bool drawDebug,
                                      out Block hitBlock, out Vector3 hitBlockLocation, out Vector3 hitNormal)
        {
            hitBlock         = Block.EmptyBlock();
            hitBlockLocation = Vector3.zero;
            hitNormal        = Vector3.zero;
            bool    hit = false;
            Vector3 movementAddition = Vector3.Normalize(direction);
            float   movementSpeed    = 0.05f;

            movementAddition.x *= movementSpeed;
            movementAddition.y *= movementSpeed;
            movementAddition.z *= movementSpeed;

            ray.direction = direction.normalized;

            Vector3 checkPosition     = origin;
            Vector3 prevCheckPosition = checkPosition;
            float   checkDistance     = 0.0f;

            bool refreshXPlane = true;
            bool refreshYPlane = true;
            bool refreshZPlane = true;

            float xDistance = maxDistance;
            float yDistance = maxDistance;
            float zDistance = maxDistance;

            Chunk chunkCache = null;

            while (checkDistance <= maxDistance)
            {
                bool validBlock =
                    ignoreStartAndEnd == false ||
                    (
                        (
                            (int)checkPosition.x != (int)origin.x ||
                            (int)checkPosition.y != (int)origin.y ||
                            (int)checkPosition.z != (int)origin.z
                        )
                    );

                ChunkBlockPair chunkBlockPair = ChunkRepository.GetBlockAtPosition(checkPosition, chunkCache);
                chunkCache = chunkBlockPair.chunk;

                if (drawDebug && chunkBlockPair.chunk != null)
                {
                    Vector3 drawPosition;
                    drawPosition.x = chunkBlockPair.chunk.WorldPosition().x *Chunk.SIZE + Chunk.SIZE / 2;
                    drawPosition.y = chunkBlockPair.chunk.WorldPosition().y *Chunk.SIZE + Chunk.SIZE / 2;
                    drawPosition.z = chunkBlockPair.chunk.WorldPosition().z *Chunk.SIZE + Chunk.SIZE / 2;
                    DebugUtils.DrawCube(drawPosition, Vector3.one * Chunk.SIZE / 2, Color.magenta, 0, true);
                }

                Block checkBlock = chunkBlockPair.block;

                if (checkBlock.IsSolidToTouch() && validBlock)
                {
                    hitBlock         = checkBlock;
                    hitBlockLocation = checkPosition;
                    hit = true;
                    if ((int)prevCheckPosition.y != (int)checkPosition.y)
                    {
                        hitNormal.y = ((int)prevCheckPosition.y).CompareTo((int)checkPosition.y);
                    }
                    else if ((int)prevCheckPosition.x != (int)checkPosition.x)
                    {
                        hitNormal.x = ((int)prevCheckPosition.x).CompareTo((int)checkPosition.x);
                    }
                    else if ((int)prevCheckPosition.z != (int)checkPosition.z)
                    {
                        hitNormal.z = ((int)prevCheckPosition.z).CompareTo((int)checkPosition.z);
                    }
                    break;
                }
                else
                {
                    prevCheckPosition = checkPosition;
                    ray.origin        = checkPosition;

                    // ---- X ----
                    if (refreshXPlane)
                    {
                        if (direction.x < 0.0f)
                        {
                            Vector3 westPlanePosition;
                            if (checkPosition.x == Mathf.Floor(checkPosition.x))
                            {
                                westPlanePosition.x = Mathf.Floor(checkPosition.x) - 1.0f - INSIDE_WALL_OFFSET;
                            }
                            else
                            {
                                westPlanePosition.x = Mathf.Floor(checkPosition.x) - INSIDE_WALL_OFFSET;
                            }
                            westPlanePosition.y = 0.0f;
                            westPlanePosition.z = 0.0f;

                            plane.SetNormalAndPosition(Vector3.right, westPlanePosition);
                            plane.Raycast(ray, out xDistance);
                        }
                        else if (direction.x > 0.0f)
                        {
                            Vector3 eastPlanePosition;
                            eastPlanePosition.x = Mathf.Floor(checkPosition.x) + 1.0f;
                            eastPlanePosition.y = 0.0f;
                            eastPlanePosition.z = 0.0f;

                            plane.SetNormalAndPosition(Vector3.left, eastPlanePosition);
                            plane.Raycast(ray, out xDistance);
                        }
                    }

                    // ---- Y ----
                    if (refreshYPlane)
                    {
                        if (direction.y < 0.0f)
                        {
                            Vector3 downwardPlanePosition;
                            downwardPlanePosition.x = 0.0f;
                            if (checkPosition.y == Mathf.Floor(checkPosition.y))
                            {
                                downwardPlanePosition.y = Mathf.Floor(checkPosition.y) - 1.0f - INSIDE_WALL_OFFSET;
                            }
                            else
                            {
                                downwardPlanePosition.y = Mathf.Floor(checkPosition.y) - INSIDE_WALL_OFFSET;
                            }
                            downwardPlanePosition.z = 0.0f;

                            plane.SetNormalAndPosition(Vector3.down, downwardPlanePosition);
                            plane.Raycast(ray, out yDistance);
                        }
                        else if (direction.y > 0.0f)
                        {
                            Vector3 upwardPlanePosition;
                            upwardPlanePosition.x = 0.0f;
                            upwardPlanePosition.y = Mathf.Floor(checkPosition.y) + 1.0f;
                            upwardPlanePosition.z = 0.0f;

                            plane.SetNormalAndPosition(Vector3.up, upwardPlanePosition);
                            plane.Raycast(ray, out yDistance);
                        }
                    }

                    // ---- Z ----
                    if (refreshZPlane)
                    {
                        if (direction.z < 0.0f)
                        {
                            Vector3 southPlanePosition;
                            southPlanePosition.x = 0.0f;
                            southPlanePosition.y = 0.0f;
                            if (checkPosition.z == Mathf.Floor(checkPosition.z))
                            {
                                southPlanePosition.z = Mathf.Floor(checkPosition.z) - 1.0f - INSIDE_WALL_OFFSET;
                            }
                            else
                            {
                                southPlanePosition.z = Mathf.Floor(checkPosition.z) - INSIDE_WALL_OFFSET;
                            }

                            plane.SetNormalAndPosition(Vector3.forward, southPlanePosition);
                            plane.Raycast(ray, out zDistance);
                        }
                        else if (direction.z > 0.0f)
                        {
                            Vector3 northPlanePosition;
                            northPlanePosition.x = 0.0f;
                            northPlanePosition.y = 0.0f;
                            northPlanePosition.z = Mathf.Floor(checkPosition.z) + 1.0f;

                            plane.SetNormalAndPosition(Vector3.back, northPlanePosition);
                            plane.Raycast(ray, out zDistance);
                        }
                    }

                    float distance;
                    if (xDistance > 0.0f && (xDistance < zDistance || zDistance == 0.0f) && (xDistance < yDistance || yDistance == 0.0f))
                    {
                        distance      = xDistance;
                        refreshXPlane = true;
                    }
                    else if (zDistance > 0.0f && (zDistance < yDistance || yDistance == 0.0f))
                    {
                        distance      = zDistance;
                        refreshZPlane = true;
                        if (xDistance == zDistance)
                        {
                            refreshXPlane = true;
                        }
                    }
                    else
                    {
                        distance      = yDistance;
                        refreshYPlane = true;
                        if (xDistance == yDistance)
                        {
                            refreshXPlane = true;
                        }
                        if (zDistance == yDistance)
                        {
                            refreshZPlane = true;
                        }
                    }

                    if (distance < 0.0f)
                    {
                        Debug.LogWarning("Distance: " + distance);
                        throw new Exception("Distance: " + distance + ". direction: " + direction + ". x dist: " + xDistance + ". y dist: " + yDistance + ". z dist: " + zDistance);
                    }

                    Vector3 drawPoint1 = checkPosition;

                    if (drawDebug)
                    {
                        DebugUtils.DrawMark(checkPosition, Color.red, 0);

                        Vector3 drawPosition;
                        drawPosition.x = Mathf.Floor(checkPosition.x) + 0.5f;
                        drawPosition.y = Mathf.Floor(checkPosition.y) + 0.5f;
                        drawPosition.z = Mathf.Floor(checkPosition.z) + 0.5f;
                        DebugUtils.DrawCube(drawPosition, Vector3.one / 2.0f, Color.blue, 0, true);
                    }

                    checkPosition  = ray.GetPoint(distance);
                    checkDistance += distance;

                    if (drawDebug)
                    {
                        DebugUtils.DrawMark(checkPosition, Color.green, 0);
                        UnityEngine.Debug.DrawLine(drawPoint1, checkPosition, Color.white, 0.0f, true);
                    }

                    xDistance -= distance;
                    yDistance -= distance;
                    zDistance -= distance;
                }
            }

            return(hit);
        }
Beispiel #2
0
        private bool RaytraceLightBeam(BlockSpacePosition lightPosition, BlockSpacePosition samplePosition,
                                       CubeSide sampleSide,
                                       byte inLightHue, byte inLightSaturation, byte inLightValue,
                                       out byte outLightHue, out byte outLightSaturation, out byte outLightValue)
        {
            // Setup
            outLightHue        = inLightHue;
            outLightSaturation = inLightSaturation;
            outLightValue      = inLightValue;

            Vector3 originVector;
            Vector3 endpointVector;

            originVector      = lightPosition.GetVector3();
            originVector.x   += 0.5f;
            originVector.y   += 0.5f;
            originVector.z   += 0.5f;
            endpointVector    = samplePosition.GetVector3();
            endpointVector.x += 0.5f;
            endpointVector.y += 0.5f;
            endpointVector.z += 0.5f;

            if (sampleSide == CubeSide.West)
            {
                endpointVector.x -= 0.5f;
            }
            if (sampleSide == CubeSide.East)
            {
                endpointVector.x += 0.5f;
            }
            if (sampleSide == CubeSide.North)
            {
                endpointVector.z -= 0.5f;
            }
            if (sampleSide == CubeSide.South)
            {
                endpointVector.z += 0.5f;
            }
            if (sampleSide == CubeSide.Bottom)
            {
                endpointVector.y -= 0.5f;
            }
            if (sampleSide == CubeSide.Top)
            {
                endpointVector.y += 0.5f;
            }

            // Do the raytrace
            Vector3 direction   = Vector3.Normalize(endpointVector - originVector);
            float   maxDistance = Vector3.Distance(originVector, endpointVector) - 1.0f;

            Vector3 movementAddition = Vector3.Normalize(direction);
            float   movementSpeed    = 0.05f;

            movementAddition.x *= movementSpeed;
            movementAddition.y *= movementSpeed;
            movementAddition.z *= movementSpeed;

            Vector3 checkPosition     = originVector;
            Vector3 prevCheckPosition = checkPosition;
            float   checkDistance     = 0.0f;
            Chunk   chunkCache        = null;

            while (checkDistance <= maxDistance)
            {
                bool validBlock = (int)checkPosition.x != (int)originVector.x ||
                                  (int)checkPosition.y != (int)originVector.y ||
                                  (int)checkPosition.z != (int)originVector.z;

                ChunkBlockPair chunkBlockPair = ChunkRepository.GetBlockAtPosition(checkPosition, chunkCache);
                chunkCache = chunkBlockPair.chunk;
                Block checkBlock = chunkBlockPair.block;

                if (checkBlock.IsActive() && checkBlock.IsTransparent())
                {
                    HSBColor outLightColor = FilterLightSample(outLightHue, outLightSaturation, outLightValue,
                                                               checkBlock.FilterColorHue(), checkBlock.FilterColorSaturation(), checkBlock.FilterColorValue());

                    outLightHue        = (byte)(outLightColor.h * byte.MaxValue);
                    outLightSaturation = (byte)(outLightColor.s * byte.MaxValue);
                    outLightValue      = (byte)(outLightColor.b * byte.MaxValue);
                }

                if (checkBlock.IsSolidToTouch() && validBlock && checkBlock.IsNotTransparent())
                {
                    return(true);
                }
                else
                {
                    prevCheckPosition = checkPosition;
                    do
                    {
                        checkPosition += movementAddition;
                        checkDistance += movementSpeed;
                    }while((int)checkPosition.x == (int)prevCheckPosition.x &&
                           (int)checkPosition.y == (int)prevCheckPosition.y &&
                           (int)checkPosition.z == (int)prevCheckPosition.z);
                }
            }

            return(false);
        }