/// <summary> /// World position to block-local voxel coordinate. /// </summary> public static VectorI3 WorldToBlockVoxel(Vector3 WorldPosition) { VectorI3 voxel = new VectorI3(); double x = (((double)WorldPosition.x % HighPrecision.kBlockSize) * HighPrecision.kOneOverVoxelSize); double y = (((double)WorldPosition.y % HighPrecision.kBlockSize) * HighPrecision.kOneOverVoxelSize); double z = (((double)WorldPosition.z % HighPrecision.kBlockSize) * HighPrecision.kOneOverVoxelSize); if (x < 0) { voxel.x = (int)x - 1 + kVoxelsPerBlock; } else { voxel.x = (int)x; } if (y < 0) { voxel.y = (int)y - 1 + kVoxelsPerBlock; } else { voxel.y = (int)y; } if (z < 0) { voxel.z = (int)z - 1 + kVoxelsPerBlock; } else { voxel.z = (int)z; } return(voxel); }
public VectorI4(VectorI3 vector) { this.x = vector.x; this.y = vector.y; this.z = vector.z; w = 0; }
/// <summary> /// Clamp block-local coordinates to [0, kVoxelsPerBlock) range and adjust block. /// </summary> public static VectorI3 ClampBlockVoxel(VectorI3 block, ref int vx, ref int vy, ref int vz) { while (vx < 0) { vx += kVoxelsPerBlock; --block.x; } while (vx >= kVoxelsPerBlock) { vx -= kVoxelsPerBlock; ++block.x; } while (vy < 0) { vy += kVoxelsPerBlock; --block.y; } while (vy >= kVoxelsPerBlock) { vy -= kVoxelsPerBlock; ++block.y; } while (vz < 0) { vz += kVoxelsPerBlock; --block.z; } while (vz >= kVoxelsPerBlock) { vz -= kVoxelsPerBlock; ++block.z; } return(block); }
/// <summary> /// Initializes array of blocks and the neighbour references in blocks and chunks. /// </summary> public void Initialize() { _worldApi = GetComponent <WorldApi>(); // initialize arrays _blocks = new Block[_worldApi.SizeX * _worldApi.SizeY * _worldApi.SizeZ]; _worldApi.Initialize(_blocks); for (int blockX = 0; blockX < _worldApi.SizeX; blockX++) { for (int blockY = 0; blockY < _worldApi.SizeY; blockY++) { for (int blockZ = 0; blockZ < _worldApi.SizeZ; blockZ++) { int blockId = blockX * _worldApi.SizeZ * _worldApi.SizeY + blockY * _worldApi.SizeZ + blockZ; VectorI3 coords = new VectorI3(blockX, blockY, blockZ); Block block = new GameObject($"Block ({blockX}, {blockY}, {blockZ})").AddComponent <Block>(); _blocks[blockId] = block; block.Initialize(blockId, transform, _worldApi, coords); } } } InitializeBlockReferences(); for (int blockId = 0; blockId < _blocks.Length; blockId++) { _blocks[blockId].InitializeChunkReferences(); } }
public static ICollection <VectorI3> Clone(VectorI3 vectorI3, int count) { return (Enumerable .Range(0, count) .Select(_ => Clone(vectorI3)) .ToList()); }
/// <summary> /// Global voxel coordinate to world position of origin of the voxel. /// </summary> public static Vector3 VoxelToWorld(VectorI3 voxel) { //double helps but does not eliminate precision problems float x = (float)(voxel.x * HighPrecision.kVoxelSize); float y = (float)(voxel.y * HighPrecision.kVoxelSize); float z = (float)(voxel.z * HighPrecision.kVoxelSize); return(new Vector3(x, y, z)); }
/// <summary> /// Clamp block-local coordinates to [0, kVoxelsPerBlock) range and adjust block. /// </summary> public static VectorI3 ClampBlockVoxel(VectorI3 block, ref VectorI3 voxel) { int vx = voxel.x; int vy = voxel.y; int vz = voxel.z; block = ClampBlockVoxel(block, ref vx, ref vy, ref vz); voxel.x = vx; voxel.y = vy; voxel.z = vz; return(block); }
public static VectorI3 Clone(VectorI3 vectorI3) { return (vectorI3 != null ? new VectorI3 { X = vectorI3.X, Y = vectorI3.Y, Z = vectorI3.Z } : null); }
private Mesh GetMesh(Vector3 chunkWorldPos, bool solid, Viscosity viscosity = default) { _vertices.Clear(); _triangles.Clear(); for (int voxelId = 0; voxelId < WorldGridInfo.kTotalVoxelsInChunk; voxelId++) { VectorI3 posI = WorldGridInfo.VoxelIdToChunkVoxel(voxelId); Vector3 pos = new Vector3(posI.x, posI.y, posI.z); _cubeVertices[0] = pos + new Vector3(0, 0, 1); _cubeVertices[1] = pos + new Vector3(1, 0, 1); _cubeVertices[2] = pos + new Vector3(1, 0, 0); _cubeVertices[3] = pos + new Vector3(0, 0, 0); _cubeVertices[4] = pos + new Vector3(0, 1, 1); _cubeVertices[5] = pos + new Vector3(1, 1, 1); _cubeVertices[6] = pos + new Vector3(1, 1, 0); _cubeVertices[7] = pos + new Vector3(0, 1, 0); for (int i = 0; i < _cubeVertices.Length; i++) { pos = _cubeVertices[i] + Vector3.one; Voxel voxel = _borderedChunk[(int)(pos.x * Chunk.kColumnBordered + pos.y * Chunk.kRowBordered + pos.z)]; _cubeVertices[i] *= WorldGridInfo.kVoxelSize; _cubeVertices[i] += chunkWorldPos; if (solid) { _cubeValues[i] = !_worldApi.IsBorder(in _cubeVertices[i]) ? voxel.Solid * Voxel.kByteToFloat : 0; } else { _cubeValues[i] = voxel.Viscosity == (byte)viscosity ? voxel.Fluid * Voxel.kByteToFloat : 0; } } Polygonise(); } Mesh mesh = new Mesh(); mesh.vertices = new List <Vector3>(_vertices.Keys).ToArray(); mesh.triangles = _triangles.ToArray(); mesh.RecalculateNormals(); return(mesh); }
/// <summary> /// Clamp block-local voxel coordinates into range [0, kVoxelsPerBlocks) and return the offset in blocks used. /// </summary> /// <remarks> /// Works values that are less than kVoxelPerBlock distant from range. /// </remarks> public static bool ClampBlockVoxel(ref int vx, ref int vy, ref int vz, out VectorI3 offset) { bool rv = false; offset = default(VectorI3); if (vx >= WorldGridInfo.kVoxelsPerBlock) { vx -= WorldGridInfo.kVoxelsPerBlock; offset.x = 1; rv = true; } else if (vx < 0) { vx += WorldGridInfo.kVoxelsPerBlock; offset.x = -1; rv = true; } if (vy >= WorldGridInfo.kVoxelsPerBlock) { offset.y = 1; vy -= WorldGridInfo.kVoxelsPerBlock; rv = true; } else if (vy < 0) { offset.y = -1; vy += WorldGridInfo.kVoxelsPerBlock; rv = true; } if (vz >= WorldGridInfo.kVoxelsPerBlock) { offset.z = 1; vz -= WorldGridInfo.kVoxelsPerBlock; rv = true; } else if (vz < 0) { offset.z = -1; vz += WorldGridInfo.kVoxelsPerBlock; rv = true; } return(rv); }
/// <summary> /// Initialize array of voxels and chunks. /// </summary> public void Initialize(int id, Transform parent, WorldApi worldApi, VectorI3 coords) { Id = id; transform.parent = parent; Coords = coords; worldApi.GetBlockWorldPos(id, out Vector3 worldPos); WorldPos = worldPos; Chunks = new Chunk[WorldGridInfo.kTotalChunksInBlock]; _voxels = new NativeArray <Voxel>(WorldGridInfo.kTotalVoxelsInBlock, Unity.Collections.Allocator.Persistent); SimData = new FluidBlockSimData(this); SimData.ReadVoxels = _voxels; for (int chunkX = 0; chunkX < WorldGridInfo.kChunksPerBlock; chunkX++) { for (int chunkY = 0; chunkY < WorldGridInfo.kChunksPerBlock; chunkY++) { for (int chunkZ = 0; chunkZ < WorldGridInfo.kChunksPerBlock; chunkZ++) { int chunkId = chunkX * WorldGridInfo.kChunksPerBlock * WorldGridInfo.kChunksPerBlock + chunkY * WorldGridInfo.kChunksPerBlock + chunkZ; Chunk chunk = new GameObject($"Chunk ({chunkX}, {chunkY}, {chunkZ})").AddComponent <Chunk>(); Chunks[chunkId] = chunk; chunk.Initialize(chunkId, transform, worldApi, this); for (int voxelX = 0; voxelX < WorldGridInfo.kVoxelsPerChunk; voxelX++) { for (int voxelY = 0; voxelY < WorldGridInfo.kVoxelsPerChunk; voxelY++) { for (int voxelZ = 0; voxelZ < WorldGridInfo.kVoxelsPerChunk; voxelZ++) { int voxelId = voxelX * WorldGridInfo.kVoxelsPerChunk * WorldGridInfo.kVoxelsPerChunk + voxelY * WorldGridInfo.kVoxelsPerChunk + voxelZ; _voxels.GetWritable(chunkId, voxelId).Valid = true; } } } } } } }
/// <summary> /// World space bounds of a block. /// </summary> public static Bounds BlockBounds(VectorI3 block) { Vector3 size = new Vector3(kBlockSize, kBlockSize, kBlockSize); return(new Bounds(BlockToWorld(block) + size * 0.5f, size)); }
/// <summary> /// World space block origin from block coordinates. /// </summary> public static Vector3 BlockToWorld(VectorI3 blockCoordinates) { return(new Vector3(blockCoordinates.x * kBlockSize, blockCoordinates.y * kBlockSize, blockCoordinates.z * kBlockSize)); }
public static VectorI3 Clone(this VectorI3 vectorI3) { return(BlueprintScrappinUtil.Clone(vectorI3)); }
public static ICollection <VectorI3> Clone(this VectorI3 vectorI3, int count) { return(BlueprintScrappinUtil.Clone(vectorI3, count)); }