public IEnumerable <ushort> GetAllData() { int size = _Extent << 1; for (int index = 0; index < Length; index++) { yield return(GetPoint(WydMath.IndexTo3D(index, size))); } }
private void GenerateIndex(int index) { int3 localPosition = WydMath.IndexTo3D(index, GenerationConstants.CHUNK_SIZE); int heightmapIndex = WydMath.PointToIndex(localPosition.xz, GenerationConstants.CHUNK_SIZE); int noiseHeight = _Heightmap[heightmapIndex]; if (noiseHeight < _OriginPoint.y) { return; } int globalPositionY = _OriginPoint.y + localPosition.y; if ((globalPositionY < 4) && (globalPositionY <= _SeededRandom.Next(0, 4))) { _Blocks.SetPoint(localPosition, GetCachedBlockID("bedrock")); return; } else if (_CaveNoise[index] < 0.000225f) { return; } if (globalPositionY == noiseHeight) { _Blocks.SetPoint(localPosition, GetCachedBlockID("grass")); } else if ((globalPositionY < noiseHeight) && (globalPositionY >= (noiseHeight - 3))) // lay dirt up to 3 blocks below noise height { _Blocks.SetPoint(localPosition, _SeededRandom.Next(0, 8) == 0 ? GetCachedBlockID("dirt_coarse") : GetCachedBlockID("dirt")); } else if (globalPositionY < (noiseHeight - 3)) { if (_SeededRandom.Next(0, 100) == 0) { _Blocks.SetPoint(localPosition, GetCachedBlockID("coal_ore")); } else { _Blocks.SetPoint(localPosition, GetCachedBlockID("stone")); } } }
public T GetPoint(int3 point) { int index = WydMath.PointToIndex(point, GenerationConstants.CHUNK_SIZE); LinkedListNode <RLENode <T> > currentNode = _RLENodes.First; for (uint i = 0; (i < index) && ((currentNode = currentNode.Next) != null);) { uint totalRunLength = i + currentNode.Value.RunLength; if (totalRunLength >= index) { return(currentNode.Value.Value); } else { i = totalRunLength; } } return(default);
protected override Task ProcessIndex(int index) { if (_CancellationToken.IsCancellationRequested) { return(Task.CompletedTask); } ushort currentBlockId = _MeshingBlocks[index].ID; int localPosition = CompressVertex(WydMath.IndexTo3D(index, GenerationConstants.CHUNK_SIZE)); if (currentBlockId == BlockController.AirID) { return(Task.CompletedTask); } bool transparentTraversal = BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent); NaiveMeshIndex(index, localPosition, currentBlockId, transparentTraversal); return(Task.CompletedTask); }
public void CopyTo(ushort[] destinationArray) { if (destinationArray == null) { throw new NullReferenceException(nameof(destinationArray)); } else if (destinationArray.Rank != 1) { throw new RankException("Only single dimension arrays are supported here."); } else if (destinationArray.Length < Length) { throw new ArgumentOutOfRangeException(nameof(destinationArray), "Destination array was not long enough."); } int size = _Extent << 1; for (int index = 0; index < destinationArray.Length; index++) { destinationArray[index] = GetPoint(WydMath.IndexTo3D(index, size)); } }
private async Task GenerateNoise() { // SIZE_SQUARED + 1 to facilitate compute shader's above-y-value count _Heightmap = _HeightmapPool.Retrieve() ?? new int[GenerationConstants.CHUNK_SIZE_SQUARED]; _CaveNoise = _CaveNoisePool.Retrieve() ?? new float[GenerationConstants.CHUNK_SIZE_CUBED]; if ((_HeightmapBuffer == null) || (_CaveNoiseBuffer == null)) { for (int x = 0; x < GenerationConstants.CHUNK_SIZE; x++) { for (int z = 0; z < GenerationConstants.CHUNK_SIZE; z++) { int2 xzCoords = new int2(x, z); int heightmapIndex = WydMath.PointToIndex(xzCoords, GenerationConstants.CHUNK_SIZE); _Heightmap[heightmapIndex] = GetHeightByGlobalPosition(_OriginPoint.xz + xzCoords); for (int y = 0; y < GenerationConstants.CHUNK_SIZE; y++) { int3 localPosition = new int3(x, y, z); int3 globalPosition = _OriginPoint + localPosition; int caveNoiseIndex = WydMath.PointToIndex(localPosition, GenerationConstants.CHUNK_SIZE); _CaveNoise[caveNoiseIndex] = GetCaveNoiseByGlobalPosition(globalPosition); } } } } else { // ReSharper disable once ConvertToUsingDeclaration // .... because Rider doesn't actually consider language feature version // remark: thanks JetBrains using (SemaphoreSlim semaphoreReset = MainThreadActionsController.Current.QueueAction(GetComputeBufferData)) { await semaphoreReset.WaitAsync(_CancellationToken); } } }
private void NaiveMeshIndex(int index, int localPosition, ushort currentBlockId, bool isCurrentBlockTransparent) { Debug.Assert(currentBlockId != BlockController.AirID, $"{nameof(TraverseIndex)} should not run on air blocks."); Debug.Assert((index >= 0) && (index < GenerationConstants.CHUNK_SIZE_CUBED), $"{nameof(index)} is not within chunk bounds."); Debug.Assert(WydMath.PointToIndex(DecompressVertex(localPosition), GenerationConstants.CHUNK_SIZE) == index, $"{nameof(localPosition)} does not match given {nameof(index)}."); Debug.Assert(_MeshingBlocks[index].ID == currentBlockId, $"{currentBlockId} is not equal to block ID at given index."); Debug.Assert( BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent) == isCurrentBlockTransparent, $"Given transparency state for {nameof(currentBlockId)} does not match actual block transparency."); // iterate once over all 6 faces of given cubic space for (int normalIndex = 0; normalIndex < 6; normalIndex++) { // face direction always exists on a single bit, so shift 1 by the current normalIndex (0-5) Direction faceDirection = (Direction)(1 << normalIndex); // check if current index has face already if (_MeshingBlocks[index].HasFace(faceDirection)) { continue; } // indicates whether the current face checking direction is negative or positive bool isNegativeFace = (normalIndex - 3) >= 0; // normalIndex constrained to represent the 3 axes int iModulo3 = normalIndex % 3; int iModulo3Shift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * iModulo3; // axis value of the current face check direction // example: for iteration normalIndex == 0—which is positive X—it'd be equal to localPosition.x int faceCheckAxisValue = (localPosition >> iModulo3Shift) & GenerationConstants.CHUNK_SIZE_BIT_MASK; // indicates whether or not the face check is within the current chunk bounds bool isFaceCheckOutOfBounds = (!isNegativeFace && (faceCheckAxisValue == (GenerationConstants.CHUNK_SIZE - 1))) || (isNegativeFace && (faceCheckAxisValue == 0)); if (!isFaceCheckOutOfBounds) { // amount by integer to add to current traversal index to get 3D->1D position of facing block int facedBlockIndex = index + GenerationConstants.IndexStepByNormalIndex[normalIndex]; // if so, index into block ids and set facingBlockId ushort facedBlockId = _MeshingBlocks[facedBlockIndex].ID; // if transparent, traverse so long as facing block is not the same block id // if opaque, traverse so long as facing block is transparent if (isCurrentBlockTransparent) { if (currentBlockId != facedBlockId) { continue; } } else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent)) { if (!isNegativeFace) { Direction inverseFaceDirection = (Direction)(1 << ((normalIndex + 3) % 6)); _MeshingBlocks[facedBlockIndex].SetFace(inverseFaceDirection); } continue; } } else { // this block of code translates the integer local position to the local position of the neighbor at [normalIndex] int sign = isNegativeFace ? -1 : 1; int iModuloComponentMask = GenerationConstants.CHUNK_SIZE_BIT_MASK << iModulo3Shift; int finalLocalPosition = (~iModuloComponentMask & localPosition) | (WydMath.Wrap(((localPosition & iModuloComponentMask) >> iModulo3Shift) + sign, GenerationConstants.CHUNK_SIZE, 0, GenerationConstants.CHUNK_SIZE - 1) << iModulo3Shift); // index into neighbor blocks collections, call .GetPoint() with adjusted local position // remark: if there's no neighbor at the index given, then no chunk exists there (for instance, // chunks at the edge of render distance). In this case, return NullID so no face is rendered on edges. ushort facedBlockId = _NeighborBlocksCollections[normalIndex]?.GetPoint(DecompressVertex(finalLocalPosition)) ?? BlockController.NullID; if (isCurrentBlockTransparent) { if (currentBlockId != facedBlockId) { continue; } } else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent)) { continue; } } _MeshingBlocks[index].SetFace(faceDirection); if (BlockController.Current.GetUVs(currentBlockId, faceDirection, out ushort textureId)) { int compressedUv = (textureId << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2)) ^ (1 << GenerationConstants.CHUNK_SIZE_BIT_SHIFT) ^ 1; int normals = GenerationConstants.NormalByIteration[normalIndex]; int[] compressedVertices = GenerationConstants.VerticesByIteration[normalIndex]; _MeshData.AddVertex((localPosition + compressedVertices[3]) | normals); _MeshData.AddVertex(compressedUv & (int.MaxValue << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2))); _MeshData.AddVertex((localPosition + compressedVertices[2]) | normals); _MeshData.AddVertex(compressedUv & (int.MaxValue << GenerationConstants.CHUNK_SIZE_BIT_SHIFT)); _MeshData.AddVertex((localPosition + compressedVertices[1]) | normals); _MeshData.AddVertex(compressedUv & ~(GenerationConstants.CHUNK_SIZE_BIT_MASK << GenerationConstants.CHUNK_SIZE_BIT_SHIFT)); _MeshData.AddVertex((localPosition + compressedVertices[0]) | normals); _MeshData.AddVertex(compressedUv & int.MaxValue); int verticesCount = _MeshData.VerticesCount / 2; int transparentAsInt = Convert.ToInt32(isCurrentBlockTransparent); _MeshData.AddTriangle(transparentAsInt, 0 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 3 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount); } else { } } }
/// <summary> /// Traverse given index of <see cref="_MeshingBlocks" /> to conditionally emit vertex data for each face. /// </summary> /// <param name="index">Current working index.</param> /// <param name="localPosition">3D projected local position of the current working index.</param> /// <param name="currentBlockId">Block ID present at the current working index.</param> /// <param name="isCurrentBlockTransparent">Whether or not this traversal uses transparent-specific conditionals.</param> private void TraverseIndex(int index, int localPosition, ushort currentBlockId, bool isCurrentBlockTransparent) { Debug.Assert(currentBlockId != BlockController.AirID, $"{nameof(TraverseIndex)} should not run on air blocks."); Debug.Assert((index >= 0) && (index < GenerationConstants.CHUNK_SIZE_CUBED), $"{nameof(index)} is not within chunk bounds."); Debug.Assert(WydMath.PointToIndex(DecompressVertex(localPosition), GenerationConstants.CHUNK_SIZE) == index, $"{nameof(localPosition)} does not match given {nameof(index)}."); Debug.Assert(_MeshingBlocks[index].ID == currentBlockId, $"{currentBlockId} is not equal to block ID at given index."); Debug.Assert( BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent) == isCurrentBlockTransparent, $"Given transparency state for {nameof(currentBlockId)} does not match actual block transparency."); // iterate once over all 6 faces of given cubic space for (int normalIndex = 0; normalIndex < 6; normalIndex++) { // face direction always exists on a single bit, so shift 1 by the current normalIndex (0-5) Direction faceDirection = (Direction)(1 << normalIndex); // check if current index has face already if (_MeshingBlocks[index].HasFace(faceDirection)) { continue; } // indicates whether the current face checking direction is negative or positive bool isNegativeFace = (normalIndex - 3) >= 0; // normalIndex constrained to represent the 3 axes int iModulo3 = normalIndex % 3; int iModulo3Shift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * iModulo3; // axis value of the current face check direction // example: for iteration normalIndex == 0—which is positive X—it'd be equal to localPosition.x int faceCheckAxisValue = (localPosition >> iModulo3Shift) & GenerationConstants.CHUNK_SIZE_BIT_MASK; // indicates whether or not the face check is within the current chunk bounds bool isFaceCheckOutOfBounds = (!isNegativeFace && (faceCheckAxisValue == (GenerationConstants.CHUNK_SIZE - 1))) || (isNegativeFace && (faceCheckAxisValue == 0)); // total number of successful traversals int traversals = 0; for (int perpendicularNormalIndex = 1; perpendicularNormalIndex < 3; perpendicularNormalIndex++) { // the index of the int3 traversalNormal to traverse on int traversalNormalIndex = (iModulo3 + perpendicularNormalIndex) % 3; int traversalNormalShift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * traversalNormalIndex; // current value of the local position by traversal direction int traversalNormalAxisValue = (localPosition >> traversalNormalShift) & GenerationConstants.CHUNK_SIZE_BIT_MASK; // amount by integer to add to current index to get 3D->1D position of traversal position int traversalIndexStep = GenerationConstants.IndexStepByNormalIndex[traversalNormalIndex]; // current traversal index, which is increased by traversalIndexStep every iteration the for loop below int traversalIndex = index + (traversals * traversalIndexStep); // local start axis position + traversals int totalTraversalLength = traversalNormalAxisValue + traversals; for (; (totalTraversalLength < GenerationConstants.CHUNK_SIZE) && !_MeshingBlocks[traversalIndex].HasFace(faceDirection) && (_MeshingBlocks[traversalIndex].ID == currentBlockId); totalTraversalLength++, traversals++, // increment traversals traversalIndex += traversalIndexStep) // increment traversal index by index step to adjust local working position { // check if current facing block axis value is within the local chunk if (!isFaceCheckOutOfBounds) { // amount by integer to add to current traversal index to get 3D->1D position of facing block int facedBlockIndex = traversalIndex + GenerationConstants.IndexStepByNormalIndex[normalIndex]; // if so, index into block ids and set facingBlockId ushort facedBlockId = _MeshingBlocks[facedBlockIndex].ID; // if transparent, traverse so long as facing block is not the same block id // if opaque, traverse so long as facing block is transparent if (isCurrentBlockTransparent) { if (currentBlockId != facedBlockId) { break; } } else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent)) { if (!isNegativeFace) { // we've culled this face, and faced block is opaque as well, so cull it's face inverse to the current. Direction inverseFaceDirection = (Direction)(1 << ((normalIndex + 3) % 6)); _MeshingBlocks[facedBlockIndex].SetFace(inverseFaceDirection); } break; } } else { // this block of code translates the integer local position to the local position of the neighbor at [normalIndex] int sign = isNegativeFace ? -1 : 1; int iModuloComponentMask = GenerationConstants.CHUNK_SIZE_BIT_MASK << iModulo3Shift; int translatedLocalPosition = localPosition + (traversals << traversalNormalShift); int finalLocalPosition = (~iModuloComponentMask & translatedLocalPosition) | (WydMath.Wrap(((translatedLocalPosition & iModuloComponentMask) >> iModulo3Shift) + sign, GenerationConstants.CHUNK_SIZE, 0, GenerationConstants.CHUNK_SIZE - 1) << iModulo3Shift); // index into neighbor blocks collections, call .GetPoint() with adjusted local position // remark: if there's no neighbor at the index given, then no chunk exists there (for instance, // chunks at the edge of render distance). In this case, return NullID so no face is rendered on edges. ushort facedBlockId = _NeighborBlocksCollections[normalIndex]?.GetPoint(DecompressVertex(finalLocalPosition)) ?? BlockController.NullID; if (isCurrentBlockTransparent) { if (currentBlockId != facedBlockId) { break; } } else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent)) { break; } } _MeshingBlocks[traversalIndex].SetFace(faceDirection); } // if it's the first traversal and we've only made a 1x1x1 face, continue to test next axis if ((traversals == 1) && (perpendicularNormalIndex == 1)) { continue; } if ((traversals == 0) || !BlockController.Current.GetUVs(currentBlockId, faceDirection, out ushort textureId)) { break; } // add triangles int verticesCount = _MeshData.VerticesCount / 2; int transparentAsInt = Convert.ToInt32(isCurrentBlockTransparent); _MeshData.AddTriangle(transparentAsInt, 0 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 3 + verticesCount); _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount); int uvShift = (iModulo3 + traversalNormalIndex) % 2; int compressedUv = (textureId << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2)) | (1 << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * ((uvShift + 1) % 2))) | (traversals << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * uvShift)); int traversalShiftedMask = GenerationConstants.CHUNK_SIZE_BIT_MASK << traversalNormalShift; int unaryTraversalShiftedMask = ~traversalShiftedMask; int aggregatePositionNormal = localPosition | GenerationConstants.NormalByIteration[normalIndex]; int[] compressedVertices = GenerationConstants.VerticesByIteration[normalIndex]; _MeshData.AddVertex(aggregatePositionNormal + ((unaryTraversalShiftedMask & compressedVertices[3]) | ((((compressedVertices[3] >> traversalNormalShift) * traversals) << traversalNormalShift) & traversalShiftedMask))); _MeshData.AddVertex(compressedUv & (int.MaxValue << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2))); _MeshData.AddVertex(aggregatePositionNormal + ((unaryTraversalShiftedMask & compressedVertices[2]) | ((((compressedVertices[2] >> traversalNormalShift) * traversals) << traversalNormalShift) & traversalShiftedMask))); _MeshData.AddVertex(compressedUv & (int.MaxValue << GenerationConstants.CHUNK_SIZE_BIT_SHIFT)); _MeshData.AddVertex(aggregatePositionNormal + ((unaryTraversalShiftedMask & compressedVertices[1]) | ((((compressedVertices[1] >> traversalNormalShift) * traversals) << traversalNormalShift) & traversalShiftedMask))); _MeshData.AddVertex(compressedUv & ~(GenerationConstants.CHUNK_SIZE_BIT_MASK << GenerationConstants.CHUNK_SIZE_BIT_SHIFT)); _MeshData.AddVertex(aggregatePositionNormal + ((unaryTraversalShiftedMask & compressedVertices[0]) | ((((compressedVertices[0] >> traversalNormalShift) * traversals) << traversalNormalShift) & traversalShiftedMask))); _MeshData.AddVertex(compressedUv & int.MaxValue); break; } } }