public void SetSingleVoxel() { var testId = new VoxelTypeID(5); int x = 10; int y = 4; int z = 8; rle.Set(MultiIndexToFlat(x, y, z, dimensions), testId); Assert.AreEqual(testId, rle.Get(MultiIndexToFlat(x, y, z, dimensions)), $"Get did not return the previously set item"); var Air = new VoxelTypeID(); //All other locations should be empty for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { for (int k = 0; k < 16; k++) { if (i == x && j == y && k == z) { continue; } var id = rle.Get(MultiIndexToFlat(i, j, k, dimensions)); Assert.AreEqual(Air, id, $"Coordinates {i},{j},{k} were not empty, but nothing was placed here"); } } } }
public void ToArraySparse() { int3 dimensions = new int3(16); OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(dimensions.x, dimensions.y, dimensions.z)); var testId = new VoxelTypeID(5); Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; foreach (var item in testPositions) { svo.Set(item.x, item.y, item.z, testId); } var array = svo.ToArray(); foreach (var item in testPositions) { var flat = Utils.Helpers.MultiIndexToFlat(item.x, item.y, item.z, dimensions); var value = array[flat]; Assert.AreEqual(testId, value, $"Array index {item} was not correctly translated"); } }
public void SetMany() { OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(16, 16, 16)); Vector3Int center = new Vector3Int(7, 7, 7); VoxelTypeID testId = new VoxelTypeID(5); VoxelTypeID[,,] authoritativeArray = new VoxelTypeID[16, 16, 16]; foreach (var item in Utils.Helpers.ManhattanCircle(center, 3)) { svo.Set(item.x, item.y, item.z, testId); authoritativeArray[item.x, item.y, item.z] = testId; } for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { Assert.AreEqual(authoritativeArray[x, y, z], svo.Get(x, y, z), $"Coordinates {x},{y},{z} not equal"); } } } }
public void FromArrayFull() { int3 dimensions = new int3(16); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; var testId = new VoxelTypeID(5); for (int i = 0; i < sourceArray.Length; i++) { sourceArray[i] = testId; } OctreeVoxelStorage svo = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); Assert.IsFalse(svo.IsEmpty, $"Octree empty after initialisation from full array"); int flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { Assert.AreEqual(sourceArray[flat], svo.Get(x, y, z), $"Position {x},{y},{z} at flat index {flat} did not match"); } } } }
private IChunkData FlatWorldWithHoles(Vector3Int chunkID, Vector3Int chunkDimensions) { var ChunkData = chunkDataFactory.Create(chunkID, chunkDimensions); int groundHeight = 0; int chunkYCuttoff = (groundHeight + chunkDimensions.y) / chunkDimensions.y; var chunkPosition = chunkManager.ChunkToWorldPosition(chunkID); bool isHole = chunkID.x % 3 == 0; if (chunkID.y < chunkYCuttoff && !isHole)//Chunks above the cuttof are just pure air { for (int z = 0; z < chunkDimensions.z; z++) { for (int y = 0; y < chunkDimensions.y; y++) { for (int x = 0; x < chunkDimensions.x; x++) { var height = y + chunkPosition.y; if (height == groundHeight) { ChunkData[x, y, z] = new VoxelTypeID(grassID); } else if (height < groundHeight) { ChunkData[x, y, z] = new VoxelTypeID(dirtID); } } } } } return(ChunkData); }
private FaceDescriptor makeFaceDescriptor(VoxelTypeID typeId, Direction originalDirection, LightValue lightValue, VoxelRotation rotation = default) { if (typeId == VoxelTypeID.AIR_ID) { return(nullFace); } var faceDirection = originalDirection; if (!rotation.isBlank) { ///Face direction needs to be the direction index of the face currently pointing in the original ///direction. Therefore it is the direction such that applying the rotation gives the original direction. faceDirection = directionRotator.GetDirectionBeforeRotation(originalDirection, rotation); } FaceDescriptor faceDescriptor = new FaceDescriptor() { typeId = typeId, faceDirection = faceDirection, rotation = rotation, lightValue = lightValue }; return(faceDescriptor); }
public void FromArrayAndBack() { int3 dimensions = new int3(16); OctreeVoxelStorage svo; var testId = new VoxelTypeID(5); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; //Initialise source array foreach (var item in testPositions) { sourceArray[Utils.Helpers.MultiIndexToFlat(item.x, item.y, item.z, dimensions)] = testId; } svo = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); var resultArray = svo.ToArray(); for (int i = 0; i < sourceArray.Length; i++) { Utils.Helpers.FlatIndexToMulti(i, dimensions, out var x, out var y, out var z); Assert.AreEqual(sourceArray[i], resultArray[i], $"Result array did not match source for coordinates {x},{y},{z}"); } }
public void SetSingleVoxel() { OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(16, 16, 16)); var testId = new VoxelTypeID(5); int x = 10; int y = 4; int z = 8; svo.Set(x, y, z, testId); Assert.AreEqual(testId, svo.Get(x, y, z), $"Get did not return the previously set item"); var Air = new VoxelTypeID(); //All other locations should be empty for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { for (int k = 0; k < 16; k++) { if (i == x && j == y && k == z) { continue; } var id = svo.Get(i, j, k); Assert.AreEqual(Air, id, $"Coordinates {i},{j},{k} were not empty, but nothing was placed here"); } } } }
public void RemoveLastVoxelInLeafDoesntPruneTooMuch() { OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(16, 16, 16)); var testId = new VoxelTypeID(5); var Air = new VoxelTypeID(); //Add a complete leaf svo.Set(0, 0, 0, testId); svo.Set(0, 0, 1, testId); svo.Set(0, 1, 0, testId); svo.Set(0, 1, 1, testId); svo.Set(1, 0, 0, testId); svo.Set(1, 0, 1, testId); svo.Set(1, 1, 0, testId); svo.Set(1, 1, 1, testId); //Add another node somewhere else svo.Set(1, 2, 1, testId); //remove all the nodes in the complete leaf svo.Set(0, 0, 0, Air); svo.Set(0, 0, 1, Air); svo.Set(0, 1, 0, Air); svo.Set(0, 1, 1, Air); svo.Set(1, 0, 0, Air); svo.Set(1, 0, 1, Air); svo.Set(1, 1, 0, Air); svo.Set(1, 1, 1, Air); Assert.IsFalse(svo.IsEmpty, $"Octree pruned more than it should have"); }
public void Equals() { int3 dimensions = new int3(16); OctreeVoxelStorage svo1 = new OctreeVoxelStorage(dimensions.ToBasic()); OctreeVoxelStorage svo2 = new OctreeVoxelStorage(dimensions.ToBasic()); Assert.AreEqual(svo1, svo2, $"Empty octrees not equal"); var testId = new VoxelTypeID(5); Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; foreach (var item in testPositions) { svo1.Set(item.x, item.y, item.z, testId); svo2.Set(item.x, item.y, item.z, testId); } Assert.AreEqual(svo1, svo2, $"Octrees with same elements not equal"); svo2.Set(testPositions[0].x, testPositions[0].y, testPositions[0].z, new VoxelTypeID(0)); Assert.AreNotEqual(svo1, svo2, $"Octrees with different elements should note be equal"); }
public void FromArrayEmpty() { var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; RLEArray <VoxelTypeID> rle = new RLEArray <VoxelTypeID>(dimensions.ToBasic(), sourceArray); Assert.IsTrue(rle.IsEmpty, $"RLE not empty after initialisation from empty array"); }
public void FromArrayAndBack() { var testId = new VoxelTypeID(5); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; //Initialise source array foreach (var item in testPositions) { var flat = MultiIndexToFlat(item.x, item.y, item.z, dimensions); sourceArray[flat] = testId; } rle = new RLEArray <VoxelTypeID>(dimensions.ToBasic(), sourceArray); var resultArray = rle.ToArray(); for (int i = 0; i < sourceArray.Length; i++) { FlatIndexToMulti(i, dimensions, out var x, out var y, out var z); Assert.AreEqual(sourceArray[i], resultArray[i], $"Result array did not match source for coordinates {x},{y},{z}"); } }
public void ToArray() { var testId = new VoxelTypeID(5); Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; foreach (var item in testPositions) { rle.Set(MultiIndexToFlat(item.x, item.y, item.z, dimensions), testId); } var array = rle.ToArray(); foreach (var item in testPositions) { var flat = MultiIndexToFlat(item.x, item.y, item.z, dimensions); var value = array[flat]; Assert.AreEqual(testId, value, $"Array index {item} was not correctly translated"); } }
public void SetMany() { Vector3Int center = new Vector3Int(7, 7, 7); VoxelTypeID testId = new VoxelTypeID(5); VoxelTypeID[,,] authoritativeArray = new VoxelTypeID[16, 16, 16]; foreach (var item in ManhattanCircle(center, 3)) { rle.Set(MultiIndexToFlat(item.x, item.y, item.z, dimensions), testId); authoritativeArray[item.x, item.y, item.z] = testId; } for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { Assert.AreEqual(authoritativeArray[x, y, z], rle.Get(MultiIndexToFlat(x, y, z, dimensions)), $"Coordinates {x},{y},{z} not equal"); } } } }
public void FromArrayEmpty() { int3 dimensions = new int3(16); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; OctreeVoxelStorage svo = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); Assert.IsTrue(svo.IsEmpty, $"Octree not empty after initialisation from empty array"); }
private IChunkData SingleBlock(Vector3Int chunkID, Vector3Int chunkDimensions) { var ChunkData = chunkDataFactory.Create(chunkID, chunkDimensions); ChunkData[0, 0, 0] = new VoxelTypeID(grassID); return(ChunkData); }
private void setVoxel(Vector3Int worldPos, VoxelTypeID setTo) { var localPos = worldPos; var centeredNeigh = neighbourhoodFor(ref localPos); var prevVoxel = centeredNeigh.GetVoxel(localPos.x, localPos.y, localPos.z); centeredNeigh.SetVoxel(localPos.x, localPos.y, localPos.z, setTo); lightManager.UpdateLightOnVoxelSet(centeredNeigh, localPos, setTo, prevVoxel); }
public void SetAndRemoveVoxel() { var testId = new VoxelTypeID(5); var Air = new VoxelTypeID(); int x = 10; int y = 4; int z = 8; rle.Set(MultiIndexToFlat(x, y, z, dimensions), testId); rle.Set(MultiIndexToFlat(x, y, z, dimensions), Air); Assert.AreEqual(Air, rle.Get(MultiIndexToFlat(x, y, z, dimensions)), $"Location was not empty after being set to air"); Assert.IsTrue(rle.IsEmpty, "RLEArray<VoxelTypeID> not empty after having item removed from it"); }
public void Execute() { VoxelTypeID air = (VoxelTypeID)VoxelTypeID.AIR_ID; for (int i = 0; i < chunkData.Length; i++) { if (chunkData[i] != air) { isEmpty[0] = false; return; } } }
public void FromArrayFull() { var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; var testId = new VoxelTypeID(5); for (int i = 0; i < sourceArray.Length; i++) { sourceArray[i] = testId; } RLEArray <VoxelTypeID> rle = new RLEArray <VoxelTypeID>(dimensions.ToBasic(), sourceArray); Assert.IsFalse(rle.IsEmpty, $"RLE empty after initialisation from full array"); }
public void SetAndRemoveVoxel() { OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(16, 16, 16)); var testId = new VoxelTypeID(5); var Air = new VoxelTypeID(); int x = 10; int y = 4; int z = 8; svo.Set(x, y, z, testId); svo.Set(x, y, z, Air); Assert.AreEqual(Air, svo.Get(x, y, z), $"Location was not empty after being set to air"); Assert.IsTrue(svo.IsEmpty, "SVO not empty after having item removed from it"); }
public void Execute() { int dx = dimensions.x; int dxdy = dimensions.x * dimensions.y; int i = 0; for (int z = 0; z < dimensions.z; z++) { for (int x = 0; x < dimensions.x; x++, i++) { if (config.oceanIDs.Contains(biomeMap[i])) { if (heightMap[i] <= config.sealevel) { var yStart = (int)math.floor(math.min(config.sealevel - chunkPosition.y, dimensions.y - 1)); if (yStart < 0) { continue; } int y = yStart; int flatIndex = MultiIndexToFlat(x, y, z, dx, dxdy); while (y >= 0 && chunkData[flatIndex] == VoxelTypeID.AIR_ID) { if (chunkPosition.y + y < heightMap[i]) { //Prevent filling below the heightmap ///NOTE: Without this break check, all caves underneath oceans get filled ///with water, even if they do not connect to the ocean at all, ///but with it water can be "floating" over caves that carve out space ///directly under the seabed. ///Neither of these solutions is ideal, a proper water propagation ///system would need to be implemented to get "correct" looking ///water. break; } chunkData[flatIndex] = new VoxelTypeID(config.waterID); y--; flatIndex = MultiIndexToFlat(x, y, z, dx, dxdy); } } } } } }
public void GetFromEmptyIsAir() { var testId = new VoxelTypeID(); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { for (int k = 0; k < 16; k++) { var id = rle.Get(MultiIndexToFlat(i, j, k, dimensions)); Assert.AreEqual(testId, id, $"Getting coordinates {i},{j},{k} from empty rle did not return air"); } } } }
public void FromArrayVsBruteForceDense() { int3 dimensions = new int3(16); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; var testId = new VoxelTypeID(5); OctreeVoxelStorage bruteForceOctree = new OctreeVoxelStorage(dimensions.ToBasic()); int flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { if (y < dimensions.y / 2) { sourceArray[flat] = new VoxelTypeID(1); } else if (x > z) { sourceArray[flat] = new VoxelTypeID(2); } bruteForceOctree.Set(x, y, z, sourceArray[flat]); } } } OctreeVoxelStorage fromArrayOctree = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { Assert.AreEqual(bruteForceOctree.Get(x, y, z), fromArrayOctree.Get(x, y, z), $"Position {x},{y},{z} at flat index {flat} did not match"); } } } Assert.AreEqual(bruteForceOctree, fromArrayOctree, $"Despite equal elements, the octrees did not compare equal"); }
public void SetAtStartOfRun() { var testId = new VoxelTypeID(5); int x = 10; int y = 4; int z = 8; var flat = MultiIndexToFlat(x, y, z, dimensions); rle.Set(flat, testId); Assert.AreEqual(testId, rle.Get(MultiIndexToFlat(x, y, z, dimensions)), $"Get did not return the previously set item"); var runsAfterOne = rle.NumRuns; Assert.AreEqual(3, runsAfterOne); rle.Set(flat + 1, testId); Assert.AreEqual(runsAfterOne, rle.NumRuns, "Adding at the start of a run failed to extend the previous run of the same value"); }
public void GetFromEmptyIsAir() { OctreeVoxelStorage svo = new OctreeVoxelStorage(new Vector3Int(16, 16, 16)); var testId = new VoxelTypeID(); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { for (int k = 0; k < 16; k++) { var id = svo.Get(i, j, k); Assert.AreEqual(testId, id, $"Getting coordinates {i},{j},{k} from empty svo did not return air"); } } } }
public void FromArrayDense() { int3 dimensions = new int3(16); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; int flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { if (y < dimensions.y / 2) { sourceArray[flat] = new VoxelTypeID(1); } else if (x > z) { sourceArray[flat] = new VoxelTypeID(2); } } } } OctreeVoxelStorage svo = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { Assert.AreEqual(sourceArray[flat], svo.Get(x, y, z), $"Position {x},{y},{z} at flat index {flat} did not match"); } } } }
public void FromArrayVsBruteForce() { int3 dimensions = new int3(16); var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; var testId = new VoxelTypeID(5); OctreeVoxelStorage svo1 = new OctreeVoxelStorage(dimensions.ToBasic()); int flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { sourceArray[flat] = testId; svo1.Set(x, y, z, testId); } } } OctreeVoxelStorage svo2 = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { Assert.AreEqual(svo1.Get(x, y, z), svo2.Get(x, y, z), $"Position {x},{y},{z} at flat index {flat} did not match"); } } } Assert.AreEqual(svo1, svo2, $"Despite equal elements, the octrees did not compare equal"); }
public void FromArraySparse() { int3 dimensions = new int3(16); OctreeVoxelStorage svo; var testId = new VoxelTypeID(5); Vector3Int[] testPositions = new Vector3Int[] { new Vector3Int(1, 2, 3), new Vector3Int(4, 5, 6), new Vector3Int(7, 8, 9), new Vector3Int(10, 11, 12), new Vector3Int(0, 0, 0), new Vector3Int(15, 15, 15), }; var sourceArray = new VoxelTypeID[dimensions.x * dimensions.y * dimensions.z]; //Initialise source array foreach (var item in testPositions) { sourceArray[Utils.Helpers.MultiIndexToFlat(item.x, item.y, item.z, dimensions)] = testId; } svo = new OctreeVoxelStorage(dimensions.ToBasic(), sourceArray); int flat = 0; for (int z = 0; z < dimensions.z; z++) { for (int y = 0; y < dimensions.y; y++) { for (int x = 0; x < dimensions.x; x++, flat++) { Assert.AreEqual(sourceArray[flat], svo.Get(x, y, z), $"Position {x},{y},{z} at flat index {flat} did not match"); } } } }
private IChunkData HalfLattice(Vector3Int chunkID, Vector3Int chunkDimensions) { bool b = true; var ChunkData = chunkDataFactory.Create(chunkID, chunkDimensions); for (int z = 0; z < chunkDimensions.z; z++) { b = !b; for (int y = 0; y < chunkDimensions.y / 2; y++) { b = !b; for (int x = 0; x < chunkDimensions.x; x++) { b = !b; if (b) { continue; } ChunkData[x, y, z] = new VoxelTypeID(dirtID); } } } return(ChunkData); }