public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated) { bool backFace = DirectionUtils.IsBackface(face.side); var pools = Globals.WorkPool.GetPool(chunk.ThreadID); var verts = pools.Vector3ArrayPool.PopExact(4); var cols = pools.Color32ArrayPool.PopExact(4); { verts[0] = vertices[0]; verts[1] = vertices[1]; verts[2] = vertices[2]; verts[3] = vertices[3]; cols[0] = palette[face.block.Type]; cols[1] = palette[face.block.Type]; cols[2] = palette[face.block.Type]; cols[3] = palette[face.block.Type]; BlockUtils.AdjustColors(chunk, cols, face.light); RenderGeometryBatcher batcher = chunk.RenderGeometryHandler.Batcher; batcher.AddFace(face.materialID, verts, cols, backFace); } pools.Color32ArrayPool.Push(cols); pools.Vector3ArrayPool.Push(verts); }
public void Reset() { // Reset chunk events m_removalRequested = false; m_firstFinalization = true; m_lod = 0; m_setBlockQueue.Clear(); // Reset blocks Blocks.Reset(); PossiblyVisible = false; MinRenderX = EngineSettings.ChunkConfig.Mask; MaxRenderX = 0; MinRenderY = EngineSettings.ChunkConfig.Mask; MaxRenderY = 0; MinRenderZ = EngineSettings.ChunkConfig.Mask; MaxRenderZ = 0; m_lowestEmptyBlock = EngineSettings.ChunkConfig.Mask; // Reset sections NonEmptyBlocks = 0; RenderGeometryBatcher.Clear(); ResetGeometryBoundingMesh(); StateManager.Reset(); }
public override void BuildBlock(Chunk chunk, ref Vector3Int localPos, int materialID) { for (int d = 0; d < 6; d++) { Direction dir = DirectionUtils.Get(d); BlockFace face = new BlockFace { block = null, pos = localPos, side = dir, light = new BlockLightData(0), materialID = materialID }; BuildFace(chunk, null, null, ref face, false); } RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; var d2 = customMeshConfig.data; Rect texture = d2.textures.GetTexture(chunk, ref localPos, Direction.down); batcher.AddMeshData(materialID, d2.tris, d2.verts, d2.colors, d2.uvs, ref texture, localPos); }
public virtual void BuildMesh( Map map, RenderGeometryBatcher batcher, int offsetX, int offsetY, int offsetZ, int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int lod, LocalPools pools ) { throw new NotImplementedException(); }
public override void BuildBlock(Chunk chunk, Vector3Int localPos) { Rect texture = customMeshConfig.texture != null ? customMeshConfig.texture.GetTexture(chunk, localPos, Direction.down) : new Rect(); RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; batcher.AddMeshData(customMeshConfig.tris, customMeshConfig.verts, texture, localPos); }
public Chunk() { Blocks = new BlockStorage(); // Associate Chunk with a certain thread and make use of its memory pool // This is necessary in order to have lock-free caches ThreadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++); Pools = Globals.WorkPool.GetPool(ThreadID); RenderGeometryBatcher = new RenderGeometryBatcher(Globals.CubeMeshGeometryBuilder, this); BBoxVertices = new List <Vector3>(); BBoxVerticesTransformed = new List <Vector3>(); StateManager = new ChunkStateManagerClient(this); }
public void Build(RenderGeometryBatcher batcher, ref BlockData block, BlockFace face, bool backFace, ref Vector3[] vecs, LocalPools pools) { int iface = (int)face; // Randomize the color a bit Color32 color = BlockDatabase.GetBlockInfo(block.BlockType).Color; if (block.BlockType != BlockType.None) { float value = m_noise.GetValue(vecs[0] + vecs[1] + vecs[2] + vecs[3]); // -1.0f..1.0f float noise = (255.0f * value) * 0.02f; // Deviation of 0.02f points from the original int n = (int)noise; byte r = (byte)Math.Max(0, Math.Min(color.r + n, 255)); byte g = (byte)Math.Max(0, Math.Min(color.g + n, 255)); byte b = (byte)Math.Max(0, Math.Min(color.b + n, 255)); color = new Color32(r, g, b, color.a); } VertexData[] vertexData = pools.PopVertexDataArray(4); VertexDataFixed[] vertexDataFixed = pools.PopVertexDataFixedArray(4); { for (int i = 0; i < 4; i++) { vertexData[i] = pools.PopVertexData(); } for (int i = 0; i < 4; i++) { vertexData[i].Vertex = vecs[i]; vertexData[i].Color = color; vertexData[i].UV = AddFaceUV(i, GetTexture(iface), backFace); vertexData[i].Normal = SNormals[iface][i]; } for (int i = 0; i < 4; i++) { vertexDataFixed[i] = VertexDataUtils.ClassToStruct(vertexData[i]); } batcher.AddFace(vertexDataFixed, backFace); for (int i = 0; i < 4; i++) { pools.PushVertexData(vertexData[i]); } } pools.PushVertexDataFixedArray(vertexDataFixed); pools.PushVertexDataArray(vertexData); }
public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated) { var d = connectedMeshConfig.dataDir[(int)face.side]; var tris = d.tris; if (tris == null) { return; } var verts = d.verts; var uvs = d.uvs; var textures = d.textures; var colors = d.colors; Rect rect; ChunkBlocks blocks = chunk.blocks; RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; Vector3Int sidePos = face.pos.Add(face.side); if (connectedMeshConfig.connectsToSolid && blocks.Get(ref sidePos).Solid) { rect = textures.GetTexture(chunk, ref face.pos, face.side); batcher.AddMeshData(face.materialID, tris, verts, colors, uvs, ref rect, face.pos); } else if (connectedMeshConfig.connectsToTypes.Length != 0) { int neighborType = blocks.Get(ref sidePos).Type; for (int i = 0; i < connectedMeshConfig.connectsToTypes.Length; i++) { if (neighborType == connectedMeshConfig.connectsToTypes[i]) { rect = textures.GetTexture(chunk, ref face.pos, face.side); batcher.AddMeshData(face.materialID, tris, verts, colors, uvs, ref rect, face.pos); break; } } } var d2 = customMeshConfig.data; rect = d2.textures.GetTexture(chunk, ref face.pos, Direction.down); batcher.AddMeshData(face.materialID, d2.tris, d2.verts, d2.colors, d2.uvs, ref rect, face.pos); }
public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated) { bool backFace = DirectionUtils.IsBackface(face.side); int d = DirectionUtils.Get(face.side); LocalPools pools = chunk.pools; var verts = pools.Vector3ArrayPool.PopExact(4); var cols = pools.Color32ArrayPool.PopExact(4); { if (vertices == null) { Vector3 pos = face.pos; verts[0] = pos + BlockUtils.PaddingOffsets[d][0]; verts[1] = pos + BlockUtils.PaddingOffsets[d][1]; verts[2] = pos + BlockUtils.PaddingOffsets[d][2]; verts[3] = pos + BlockUtils.PaddingOffsets[d][3]; cols[0] = colors[d]; cols[1] = colors[d]; cols[2] = colors[d]; cols[3] = colors[d]; } else { verts[0] = vertices[0]; verts[1] = vertices[1]; verts[2] = vertices[2]; verts[3] = vertices[3]; cols[0] = colors[d]; cols[1] = colors[d]; cols[2] = colors[d]; cols[3] = colors[d]; } BlockUtils.AdjustColors(chunk, cols, face.light); RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; batcher.AddFace(face.materialID, verts, cols, backFace); } pools.Color32ArrayPool.Push(cols); pools.Vector3ArrayPool.Push(verts); }
public override void BuildBlock(Chunk chunk, ref Vector3Int localPos, int materialID) { var data = customMeshConfig.data; Rect texture = data.textures != null ? data.textures.GetTexture(chunk, ref localPos, Direction.down) : new Rect(); RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; if (data.uvs == null) { batcher.AddMeshData(materialID, data.tris, data.verts, data.colors, localPos); } else if (data.colors == null) { batcher.AddMeshData(materialID, data.tris, data.verts, data.uvs, ref texture, localPos); } else { batcher.AddMeshData(materialID, data.tris, data.verts, data.colors, data.uvs, ref texture, localPos); } }
public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated) { bool backface = DirectionUtils.IsBackface(face.side); int d = DirectionUtils.Get(face.side); var pools = Globals.WorkPool.GetPool(chunk.ThreadID); var verts = pools.Vector3ArrayPool.PopExact(4); var uvs = pools.Vector2ArrayPool.PopExact(4); var cols = pools.Color32ArrayPool.PopExact(4); { if (vertices == null) { Vector3 pos = face.pos; verts[0] = pos + BlockUtils.PaddingOffsets[d][0]; verts[1] = pos + BlockUtils.PaddingOffsets[d][1]; verts[2] = pos + BlockUtils.PaddingOffsets[d][2]; verts[3] = pos + BlockUtils.PaddingOffsets[d][3]; } else { verts[0] = vertices[0]; verts[1] = vertices[1]; verts[2] = vertices[2]; verts[3] = vertices[3]; } BlockUtils.PrepareTexture(chunk, ref face.pos, uvs, face.side, textures, rotated); BlockUtils.PrepareColors(chunk, cols, face.light); RenderGeometryBatcher batcher = chunk.RenderGeometryHandler.Batcher; batcher.AddFace(face.materialID, verts, cols, uvs, backface); } pools.Color32ArrayPool.Push(cols); pools.Vector2ArrayPool.Push(uvs); pools.Vector3ArrayPool.Push(verts); }
public override void BuildBlock(Chunk chunk, Vector3Int localPos, Vector3Int globalPos) { Rect texture; RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher; WorldBlocks blocks = chunk.world.blocks; for (int d = 0; d < 6; d++) { Direction dir = DirectionUtils.Get(d); if (!connectedMeshConfig.directionalTris.ContainsKey(dir)) { continue; } if (connectedMeshConfig.connectsToSolid && blocks.GetBlock(globalPos + dir).IsSolid(DirectionUtils.Opposite(dir))) { texture = connectedMeshConfig.texture.GetTexture(chunk, localPos, globalPos, dir); batcher.AddMeshData(connectedMeshConfig.directionalTris[dir], connectedMeshConfig.directionalVerts[dir], texture, localPos); } else if (connectedMeshConfig.connectsToTypes.Length != 0) { int neighborType = blocks.Get(globalPos.Add(dir)).Type; for (int i = 0; i < connectedMeshConfig.connectsToTypes.Length; i++) { if (neighborType == connectedMeshConfig.connectsToTypes[i]) { texture = connectedMeshConfig.texture.GetTexture(chunk, localPos, globalPos, dir); batcher.AddMeshData(connectedMeshConfig.directionalTris[dir], connectedMeshConfig.directionalVerts[dir], texture, localPos); break; } } } } texture = customMeshConfig.texture.GetTexture(chunk, localPos, globalPos, Direction.down); batcher.AddMeshData(customMeshConfig.tris, customMeshConfig.verts, texture, localPos); }
public ARenderGeometryHandler(string prefabName) { Batcher = new RenderGeometryBatcher(prefabName); }
public override void BuildBlock(Chunk chunk, ref Vector3Int localPos, int materialID) { var pools = Globals.WorkPool.GetPool(chunk.ThreadID); RenderGeometryBatcher batcher = chunk.RenderGeometryHandler.Batcher; // Using the block positions hash is much better for random numbers than saving the offset and height in the block data int hash = localPos.GetHashCode(); float blockHeight = (hash & 63) * coef * Env.BlockSize; hash *= 39; float offsetX = (hash & 63) * coef * Env.BlockSizeHalf - Env.BlockSizeHalf * 0.5f; hash *= 39; float offsetZ = (hash & 63) * coef * Env.BlockSizeHalf - Env.BlockSizeHalf * 0.5f; // Converting the position to a vector adjusts it based on block size and gives us real world coordinates for x, y and z Vector3 vPos = localPos; vPos += new Vector3(offsetX, 0, offsetZ); float x1 = vPos.x - BlockUtils.blockPadding; float x2 = vPos.x + BlockUtils.blockPadding + Env.BlockSize; float y1 = vPos.y - BlockUtils.blockPadding; float y2 = vPos.y + BlockUtils.blockPadding + blockHeight; float z1 = vPos.z - BlockUtils.blockPadding; float z2 = vPos.z + BlockUtils.blockPadding + Env.BlockSize; var verts = pools.Vector3ArrayPool.PopExact(4); var uvs = pools.Vector2ArrayPool.PopExact(4); var colors = pools.Color32ArrayPool.PopExact(4); BlockUtils.PrepareTexture(chunk, ref localPos, uvs, Direction.north, texture, false); // TODO: How do I make sure that if I supply no color value, white is used? // TODO: These colors could be removed and memory would be saved { colors[0] = new Color32(255, 255, 255, 255); colors[1] = new Color32(255, 255, 255, 255); colors[2] = new Color32(255, 255, 255, 255); colors[3] = new Color32(255, 255, 255, 255); } { verts[0] = new Vector3(x1, y1, z2); verts[1] = new Vector3(x1, y2, z2); verts[2] = new Vector3(x2, y2, z1); verts[3] = new Vector3(x2, y1, z1); batcher.AddFace(materialID, verts, colors, uvs, false); } { verts[0] = new Vector3(x2, y1, z1); verts[1] = new Vector3(x2, y2, z1); verts[2] = new Vector3(x1, y2, z2); verts[3] = new Vector3(x1, y1, z2); batcher.AddFace(materialID, verts, colors, uvs, false); } { verts[0] = new Vector3(x2, y1, z2); verts[1] = new Vector3(x2, y2, z2); verts[2] = new Vector3(x1, y2, z1); verts[3] = new Vector3(x1, y1, z1); batcher.AddFace(materialID, verts, colors, uvs, false); } { verts[0] = new Vector3(x1, y1, z1); verts[1] = new Vector3(x1, y2, z1); verts[2] = new Vector3(x2, y2, z2); verts[3] = new Vector3(x2, y1, z2); batcher.AddFace(materialID, verts, colors, uvs, false); } pools.Color32ArrayPool.Push(colors); pools.Vector2ArrayPool.Push(uvs); pools.Vector3ArrayPool.Push(verts); }
protected ARenderGeometryHandler(string prefabName, Material[] materials) { Batcher = new RenderGeometryBatcher(prefabName, materials); }
public void Build() { // Prepare chunk for rendering RenderGeometryBatcher.Commit(); }
public override void BuildMesh( Map map, RenderGeometryBatcher batcher, int offsetX, int offsetY, int offsetZ, int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int lod, LocalPools pools ) { BlockFace face = 0; int stepSize = 1 << lod; Assert.IsTrue(lod <= EngineSettings.ChunkConfig.LogSize); // LOD can't be bigger than chunk size int width = EngineSettings.ChunkConfig.Size >> lod; int[] mins = { minX >> lod, minY >> lod, minZ >> lod }; int[] maxes = { maxX >> lod, maxY >> lod, maxZ >> lod }; int[] x = { 0, 0, 0 }; // Relative position of a block int[] xx = { 0, 0, 0 }; // Relative position of a block after applying lod int[] q = { 0, 0, 0 }; // Direction in which we compare neighbors when building mask (q[d] is our current direction) int[] du = { 0, 0, 0 }; // Width in a given dimension (du[u] is our current dimension) int[] dv = { 0, 0, 0 }; // Height in a given dimension (dv[v] is our current dimension) int[] s = { map.VoxelLogScaleX, map.VoxelLogScaleY, map.VoxelLogScaleZ }; // Scale in each dimension BlockData[] mask = pools.PopBlockDataArray(width * width); Vector3[] vecs = pools.PopVector3Array(4); // Iterate over 3 dimensions. Once for front faces, once for back faces for (int dd = 0; dd < 2 * 3; dd++) { int d = dd % 3; int u = (d + 1) % 3; int v = (d + 2) % 3; x[0] = 0; x[1] = 0; x[2] = 0; q[0] = 0; q[1] = 0; q[2] = 0; q[d] = stepSize << s[d]; // Determine which side we're meshing bool backFace = dd < 3; switch (dd) { case 0: face = BlockFace.Left; break; case 3: face = BlockFace.Right; break; case 1: face = BlockFace.Bottom; break; case 4: face = BlockFace.Top; break; case 2: face = BlockFace.Back; break; case 5: face = BlockFace.Front; break; } // Move through the dimension from front to back for (x[d] = mins[d] - 1; x[d] <= maxes[d];) { // Compute the mask int n = 0; for (x[v] = 0; x[v] < mins[v]; x[v]++) { for (x[u] = 0; x[u] < width; x[u]++) { mask[n++] = BlockData.Air; } } for (x[v] = mins[v]; x[v] <= maxes[v]; x[v]++) { for (x[u] = 0; x[u] < mins[u]; x[u]++) { mask[n++] = BlockData.Air; } for (x[u] = mins[u]; x[u] <= maxes[u]; x[u]++) { int realX = (x[0] << lod << s[0]) + offsetX; int realY = (x[1] << lod << s[1]) + offsetY; int realZ = (x[2] << lod << s[2]) + offsetZ; BlockData voxelFace0 = map.GetBlock(realX, realY, realZ); BlockData voxelFace1 = map.GetBlock(realX + q[0], realY + q[1], realZ + q[2]); mask[n++] = (voxelFace0.IsSolid() && voxelFace1.IsSolid()) ? BlockData.Air : (backFace ? voxelFace1 : voxelFace0); } for (x[u] = maxes[u] + 1; x[u] < width; x[u]++) { mask[n++] = BlockData.Air; } } for (x[v] = maxes[v] + 1; x[v] < width; x[v]++) { for (x[u] = 0; x[u] < width; x[u]++) { mask[n++] = BlockData.Air; } } x[d]++; n = 0; // Build faces from the mask if it's possible int j; for (j = 0; j < width; j++) { int i; for (i = 0; i < width;) { if (mask[n].IsEmpty()) { i++; n++; continue; } BlockType type = mask[n].BlockType; // Compute width & height const int w = 1; const int h = 1; // Determine whether we really want to build this face // TODO: Skip bottom faces at the bottom of the world bool buildFace = true; if (buildFace) { // Prepare face coordinates and dimensions x[u] = i; x[v] = j; xx[0] = ((x[0] << lod) << s[0]) + offsetX; xx[1] = ((x[1] << lod) << s[1]) + offsetY; xx[2] = ((x[2] << lod) << s[2]) + offsetZ; du[0] = du[1] = du[2] = 0; dv[0] = dv[1] = dv[2] = 0; du[u] = (w << lod) << s[u]; dv[v] = (h << lod) << s[v]; // Face vertices Vector3Int v1 = new Vector3Int( xx[0], xx[1], xx[2] ); Vector3Int v2 = new Vector3Int( xx[0] + du[0], xx[1] + du[1], xx[2] + du[2] ); Vector3Int v3 = new Vector3Int( xx[0] + du[0] + dv[0], xx[1] + du[1] + dv[1], xx[2] + du[2] + dv[2] ); Vector3Int v4 = new Vector3Int( xx[0] + dv[0], xx[1] + dv[1], xx[2] + dv[2] ); // Face vertices transformed to world coordinates // 0--1 // | | // | | // 3--2 vecs[0] = new Vector3(v4.X, v4.Y, v4.Z); vecs[1] = new Vector3(v3.X, v3.Y, v3.Z); vecs[2] = new Vector3(v2.X, v2.Y, v2.Z); vecs[3] = new Vector3(v1.X, v1.Y, v1.Z); // Build the face IFaceBuilder builder = BlockDatabase.GetFaceBuilder(type); builder.Build(batcher, ref mask[n], face, backFace, ref vecs, pools); } // Zero out the mask int l; for (l = 0; l < h; ++l) { int k; for (k = 0; k < w; ++k) { mask[n + k + l * width] = BlockData.Air; } } i += w; n += w; } } } } pools.PushBlockDataArray(mask); pools.PushVector3Array(vecs); }