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