private static bool ShouldRamp(VoxelVertex vertex, RampType rampType) { bool toReturn = false; if ((rampType & RampType.TopFrontRight) == RampType.TopFrontRight) { toReturn = (vertex == VoxelVertex.FrontTopRight); } if ((rampType & RampType.TopBackRight) == RampType.TopBackRight) { toReturn = toReturn || (vertex == VoxelVertex.BackTopRight); } if ((rampType & RampType.TopFrontLeft) == RampType.TopFrontLeft) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopLeft); } if ((rampType & RampType.TopBackLeft) == RampType.TopBackLeft) { toReturn = toReturn || (vertex == VoxelVertex.BackTopLeft); } return(toReturn); }
public static bool ShouldSlope(VoxelVertex vertex, VoxelHandle Voxel) { bool toReturn = false; if ((Voxel.RampType & RampType.TopFrontRight) == RampType.TopFrontRight) { toReturn = (vertex == VoxelVertex.FrontTopRight); } if ((Voxel.RampType & RampType.TopBackRight) == RampType.TopBackRight) { toReturn = toReturn || (vertex == VoxelVertex.BackTopRight); } if ((Voxel.RampType & RampType.TopFrontLeft) == RampType.TopFrontLeft) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopLeft); } if ((Voxel.RampType & RampType.TopBackLeft) == RampType.TopBackLeft) { toReturn = toReturn || (vertex == VoxelVertex.BackTopLeft); } return(toReturn); }
public static bool ShouldRamp(VoxelVertex vertex, RampType rampType) { bool toReturn = false; if (Voxel.HasFlag(rampType, RampType.TopFrontRight)) { toReturn = (vertex == VoxelVertex.BackTopRight); } if (Voxel.HasFlag(rampType, RampType.TopBackRight)) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopRight); } if (Voxel.HasFlag(rampType, RampType.TopFrontLeft)) { toReturn = toReturn || (vertex == VoxelVertex.BackTopLeft); } if (Voxel.HasFlag(rampType, RampType.TopBackLeft)) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopLeft); } return(toReturn); }
public static bool ShouldRamp(VoxelVertex vertex, RampType rampType) { bool toReturn = false; if(Voxel.HasFlag(rampType, RampType.TopFrontRight)) { toReturn = (vertex == VoxelVertex.BackTopRight); } if(Voxel.HasFlag(rampType, RampType.TopBackRight)) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopRight); } if(Voxel.HasFlag(rampType, RampType.TopFrontLeft)) { toReturn = toReturn || (vertex == VoxelVertex.BackTopLeft); } if(Voxel.HasFlag(rampType, RampType.TopBackLeft)) { toReturn = toReturn || (vertex == VoxelVertex.FrontTopLeft); } return toReturn; }
public static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager Chunks, SliceCache Cache) { var r = new VertexColorInfo(); var cacheKey = SliceCache.GetCacheKey(Vox, Vertex); if (!Cache.LightCache.TryGetValue(cacheKey, out r)) { r = CalculateVertexLight(Vox, Vertex, Chunks); Cache.LightCache.Add(cacheKey, r); } return(r); }
public BoxPrimitive(GraphicsDevice device, float width, float height, float depth, BoxTextureCoords uvs) { Width = width; Height = height; Depth = depth; Deltas = new VoxelVertex[NumVertices]; UVs = uvs; CreateVerticies(); ResetBuffer(device); BoundingBox = new BoundingBox(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(width, height, depth)); for (int i = 0; i < NumVertices; i++) { Deltas[i] = VoxelChunk.GetNearestDelta(Vertices[i].Position); } }
private static bool IsBottom(VoxelVertex vertex) { switch (vertex) { case VoxelVertex.BackBottomLeft: return true; case VoxelVertex.BackBottomRight: return true; case VoxelVertex.FrontBottomLeft: return true; case VoxelVertex.FrontBottomRight: return true; default: return false; } }
private static float GetAmbienceBoost(VoxelVertex vertex) { switch (vertex) { case VoxelVertex.FrontTopLeft: case VoxelVertex.FrontTopRight: case VoxelVertex.BackTopLeft: case VoxelVertex.BackTopRight: return(0.25f); case VoxelVertex.BackBottomRight: case VoxelVertex.FrontBottomRight: return(0.15f); default: return(0.0f); } }
public static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager chunks) { var neighborsEmpty = 0; var neighborsChecked = 0; var color = new VertexColorInfo(); color.DynamicColor = 0; color.SunColor = 0; foreach (var c in VoxelHelpers.EnumerateVertexNeighbors(Vox.Coordinate, Vertex)) { var v = chunks.CreateVoxelHandle(c); if (!v.IsValid) { continue; } color.SunColor += v.Sunlight ? 255 : 0; if (!v.IsEmpty || !v.IsExplored) { if (v.Type.EmitsLight) { color.DynamicColor = 255; } neighborsEmpty += 1; neighborsChecked += 1; } else { neighborsChecked += 1; } } var boost = GetAmbienceBoost(Vertex); var proportionHit = (float)neighborsEmpty / (float)neighborsChecked; color.AmbientColor = (int)Math.Min((1.0f - proportionHit) * 255.0f, 255); color.SunColor = (int)Math.Min((float)color.SunColor / (float)neighborsChecked + boost * 255.0f, 255); return(color); }
private static VoxelVertex GetNearestDelta(Vector3 position) { InitializeDeltas(); float bestDist = float.MaxValue; VoxelVertex bestKey = 0; for (int i = 0; i < 8; i++) { float dist = (position - vertexDeltas[i]).LengthSquared(); if (dist < bestDist) { bestDist = dist; bestKey = (VoxelVertex)(i); } } return(bestKey); }
private static VoxelVertex GetNearestDelta(Vector3 position) { InitializeVoxelVertexDeltas(); var shortestDistance = float.MaxValue; VoxelVertex closestVoxelVertex = 0; for (int i = 0; i < 8; i++) { var distance = (position - VoxelVertexDeltas[i]).LengthSquared(); if (distance < shortestDistance) { shortestDistance = distance; closestVoxelVertex = (VoxelVertex)(i); } } return(closestVoxelVertex); }
private static GlobalVoxelCoordinate GetCacheKey(VoxelHandle Handle, VoxelVertex Vertex) { var coord = Handle.Coordinate; if ((Vertex & VoxelVertex.Front) == VoxelVertex.Front) { coord = new GlobalVoxelCoordinate(coord.X, coord.Y, coord.Z + 1); } if ((Vertex & VoxelVertex.Top) == VoxelVertex.Top) { coord = new GlobalVoxelCoordinate(coord.X, coord.Y + 1, coord.Z); } if ((Vertex & VoxelVertex.Right) == VoxelVertex.Right) { coord = new GlobalVoxelCoordinate(coord.X + 1, coord.Y, coord.Z); } return(coord); }
public static bool IsTopVertex(VoxelVertex v) { return(v == VoxelVertex.BackTopLeft || v == VoxelVertex.FrontTopLeft || v == VoxelVertex.FrontTopRight || v == VoxelVertex.BackTopRight); }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { if (chunk == null) { return; } rebuildMutex.WaitOne(); if (isRebuilding) { rebuildMutex.ReleaseMutex(); return; } isRebuilding = true; rebuildMutex.ReleaseMutex(); accumulatedVertices.Clear(); accumulatedIndices.Clear(); faceExists.Clear(); drawFace.Clear(); Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel[] manhattanNeighbors = new Voxel[4]; for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); if (v.IsEmpty || !v.IsVisible) { continue; } BoxPrimitive primitive = VoxelLibrary.GetPrimitive(v.Type); if (primitive == null) { continue; } BoxPrimitive.BoxTextureCoords uvs = primitive.UVs; if (v.Type.HasTransitionTextures) { uvs = v.ComputeTransitionTexture(manhattanNeighbors); } Voxel worldVoxel = new Voxel(); for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; Vector3 delta = FaceDeltas[face]; faceExists[face] = chunk.IsCellValid(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[face] = true; if (faceExists[face]) { voxelOnFace.GridPosition = new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[face] = voxelOnFace.IsEmpty || !voxelOnFace.IsVisible || (voxelOnFace.Type.CanRamp && voxelOnFace.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, voxelOnFace.RampType, v.RampType)); } else { bool success = chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref worldVoxel); drawFace[face] = !success || worldVoxel.IsEmpty || !worldVoxel.IsVisible || (worldVoxel.Type.CanRamp && worldVoxel.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, worldVoxel.RampType, v.RampType)); } } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (!drawFace[face]) { continue; } int faceIndex = 0; int faceCount = 0; int vertexIndex = 0; int vertexCount = 0; primitive.GetFace(face, uvs, out faceIndex, out faceCount, out vertexIndex, out vertexCount); Vector2 texScale = uvs.Scales[i]; int indexOffset = accumulatedVertices.Count; for (int vertOffset = 0; vertOffset < vertexCount; vertOffset++) { ExtendedVertex vert = primitive.Vertices[vertOffset + vertexIndex]; VoxelVertex bestKey = VoxelChunk.GetNearestDelta(vert.Position); Color color = v.Chunk.Data.GetColor(x, y, z, bestKey); Vector3 offset = Vector3.Zero; Vector2 texOffset = Vector2.Zero; if (v.Type.CanRamp && ShouldRamp(bestKey, v.RampType)) { offset = new Vector3(0, -v.Type.RampSize, 0); if (face != BoxFace.Top && face != BoxFace.Bottom) { texOffset = new Vector2(0, v.Type.RampSize * (texScale.Y)); } } ExtendedVertex newVertex = new ExtendedVertex((vert.Position + v.Position + VertexNoise.GetNoiseVectorFromRepeatingTexture(vert.Position + v.Position) + offset), color, uvs.Uvs[vertOffset + vertexIndex] + texOffset, uvs.Bounds[faceIndex / 6]); accumulatedVertices.Add(newVertex); } for (int idx = faceIndex; idx < faceCount + faceIndex; idx++) { int vertexOffset = primitive.Indices[idx]; accumulatedIndices.Add((short)(indexOffset + (vertexOffset - primitive.Indices[faceIndex]))); } } } } } Vertices = new ExtendedVertex[accumulatedVertices.Count]; accumulatedVertices.CopyTo(Vertices); IndexBuffer = new IndexBuffer(graphics, typeof(short), accumulatedIndices.Count, BufferUsage.WriteOnly); IndexBuffer.SetData(accumulatedIndices.ToArray()); ResetBuffer(graphics); isRebuilding = false; //chunk.PrimitiveMutex.WaitOne(); chunk.NewPrimitive = this; chunk.NewPrimitiveReceived = true; //chunk.PrimitiveMutex.ReleaseMutex(); }
private static IEnumerable <ExtendedVertex> CreateWaterFace(Voxel voxel, BoxFace face, VoxelChunk chunk, int x, int y, int z, int totalDepth, bool top) { List <ExtendedVertex> toReturn = new List <ExtendedVertex>(); int idx = 0; int c = 0; int vertOffset = 0; int numVerts = 0; m_canconicalPrimitive.GetFace(face, m_canconicalPrimitive.UVs, out idx, out c, out vertOffset, out numVerts); for (int i = idx; i < idx + c; i++) { toReturn.Add(m_canconicalPrimitive.Vertices[m_canconicalPrimitive.Indices[i]]); } Vector3 origin = chunk.Origin + new Vector3(x, y, z); List <Voxel> neighborsVertex = new List <Voxel>(); for (int i = 0; i < toReturn.Count; i++) { VoxelVertex currentVertex = VoxelChunk.GetNearestDelta(toReturn[i].Position); chunk.GetNeighborsVertex(currentVertex, voxel, neighborsVertex); int index = chunk.Data.IndexAt(x, y, z); float averageWaterLevel = chunk.Data.Water[index].WaterLevel; float count = 1.0f; float emptyNeighbors = 0.0f; foreach (byte level in neighborsVertex.Select(vox => vox.WaterLevel)) { averageWaterLevel += level; count++; if (level < 1) { emptyNeighbors++; } } averageWaterLevel = averageWaterLevel / count; float averageWaterHeight = (float)averageWaterLevel / 255.0f; float puddleness = 0; Vector2 uv; float foaminess = emptyNeighbors / count; if (foaminess <= 0.5f) { foaminess = 0.0f; } if (totalDepth < 5) { foaminess = 0.75f; puddleness = 0; uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } else { uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } Vector4 bounds = new Vector4(0, 0, 1, 1); if (chunk.Data.Water[index].IsFalling || !top) { averageWaterHeight = 1.0f; } if (face == BoxFace.Top) { toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + new Vector3(0, (averageWaterHeight * 0.4f - 1.0f), 0), new Color(foaminess, puddleness, (float)totalDepth / 512.0f, 1.0f), Color.White, uv, bounds); } else { Vector3 offset = Vector3.Zero; switch (face) { case BoxFace.Back: case BoxFace.Front: uv = new Vector2((Math.Abs(toReturn[i].Position.X + origin.X) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Right: case BoxFace.Left: uv = new Vector2((Math.Abs(toReturn[i].Position.Z + origin.Z) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Top: offset = new Vector3(0, -0.5f, 0); break; } toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + offset, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, uv, bounds); } } return(toReturn); }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { if (chunk == null) { return; } rebuildMutex.WaitOne(); if (isRebuilding) { rebuildMutex.ReleaseMutex(); return; } isRebuilding = true; rebuildMutex.ReleaseMutex(); int[] ambientValues = new int[4]; int maxIndex = 0; int maxVertex = 0; Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel[] manhattanNeighbors = new Voxel[4]; BoxPrimitive bedrockModel = VoxelLibrary.GetPrimitive("Bedrock"); Voxel worldVoxel = new Voxel(); if (Vertices == null) { Vertices = new ExtendedVertex[1024]; } if (Indexes == null) { Indexes = new ushort[512]; } for (int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); if ((v.IsExplored && v.IsEmpty) || !v.IsVisible) { continue; } BoxPrimitive primitive = VoxelLibrary.GetPrimitive(v.Type); if (v.IsExplored && primitive == null) { continue; } if (!v.IsExplored) { primitive = bedrockModel; } Color tint = v.Type.Tint; BoxPrimitive.BoxTextureCoords uvs = primitive.UVs; if (v.Type.HasTransitionTextures && v.IsExplored) { uvs = v.ComputeTransitionTexture(manhattanNeighbors); } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; Vector3 delta = FaceDeltas[(int)face]; faceExists[(int)face] = chunk.IsCellValid(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[(int)face] = true; if (faceExists[(int)face]) { voxelOnFace.GridPosition = new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[(int)face] = (voxelOnFace.IsExplored && voxelOnFace.IsEmpty) || !voxelOnFace.IsVisible || (voxelOnFace.Type.CanRamp && voxelOnFace.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, voxelOnFace.RampType, v.RampType)); } else { bool success = chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref worldVoxel); drawFace[(int)face] = !success || (worldVoxel.IsExplored && worldVoxel.IsEmpty) || !worldVoxel.IsVisible || (worldVoxel.Type.CanRamp && worldVoxel.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, worldVoxel.RampType, v.RampType)); } } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (!drawFace[(int)face]) { continue; } int faceIndex = 0; int faceCount = 0; int vertexIndex = 0; int vertexCount = 0; primitive.GetFace(face, uvs, out faceIndex, out faceCount, out vertexIndex, out vertexCount); Vector2 texScale = uvs.Scales[i]; int indexOffset = maxVertex; for (int vertOffset = 0; vertOffset < vertexCount; vertOffset++) { ExtendedVertex vert = primitive.Vertices[vertOffset + vertexIndex]; VoxelVertex bestKey = primitive.Deltas[vertOffset + vertexIndex]; Color color = v.Chunk.Data.GetColor(x, y, z, bestKey); ambientValues[vertOffset] = color.G; Vector3 offset = Vector3.Zero; Vector2 texOffset = Vector2.Zero; if (v.Type.CanRamp && ShouldRamp(bestKey, v.RampType)) { offset = new Vector3(0, -v.Type.RampSize, 0); if (face != BoxFace.Top && face != BoxFace.Bottom) { texOffset = new Vector2(0, v.Type.RampSize * (texScale.Y)); } } if (maxVertex >= Vertices.Length) { ExtendedVertex[] newVertices = new ExtendedVertex[Vertices.Length * 2]; Vertices.CopyTo(newVertices, 0); Vertices = newVertices; } Vertices[maxVertex] = new ExtendedVertex(vert.Position + v.Position + VertexNoise.GetNoiseVectorFromRepeatingTexture( vert.Position + v.Position) + offset, color, tint, uvs.Uvs[vertOffset + vertexIndex] + texOffset, uvs.Bounds[faceIndex / 6]); maxVertex++; } bool flippedQuad = ambientValues[0] + ambientValues[2] > ambientValues[1] + ambientValues[3]; for (int idx = faceIndex; idx < faceCount + faceIndex; idx++) { if (maxIndex >= Indexes.Length) { ushort[] indexes = new ushort[Indexes.Length * 2]; Indexes.CopyTo(indexes, 0); Indexes = indexes; } ushort vertexOffset = flippedQuad ? primitive.FlippedIndexes[idx] : primitive.Indexes[idx]; ushort vertexOffset0 = flippedQuad? primitive.FlippedIndexes[faceIndex] : primitive.Indexes[faceIndex]; Indexes[maxIndex] = (ushort)((int)indexOffset + (int)((int)vertexOffset - (int)vertexOffset0)); maxIndex++; } } } } } MaxIndex = maxIndex; MaxVertex = maxVertex; GenerateLightmap(chunk.Manager.ChunkData.Tilemap.Bounds); isRebuilding = false; //chunk.PrimitiveMutex.WaitOne(); chunk.NewPrimitive = this; chunk.NewPrimitiveReceived = true; //chunk.PrimitiveMutex.ReleaseMutex(); }
public static void CalculateVertexLight(Voxel vox, VoxelVertex face, ChunkManager chunks, List<Voxel> neighbors, ref VertexColorInfo color) { float numHit = 1; float numChecked = 1; int index = vox.Index; color.DynamicColor = 0; color.SunColor += vox.Chunk.Data.SunColors[index]; vox.Chunk.GetNeighborsVertex(face, vox, neighbors); foreach(Voxel v in neighbors) { if(!chunks.ChunkData.ChunkMap.ContainsKey(v.Chunk.ID)) { continue; } VoxelChunk c = chunks.ChunkData.ChunkMap[v.Chunk.ID]; color.SunColor += c.Data.SunColors[v.Index]; if(VoxelLibrary.IsSolid(v)) { if (v.Type.EmitsLight) color.DynamicColor = 255; numHit++; numChecked++; } else { numChecked++; } } float proportionHit = numHit / numChecked; color.AmbientColor = (int) Math.Min((1.0f - proportionHit) * 255.0f, 255); color.SunColor = (int) Math.Min((float) color.SunColor / (float) numChecked, 255); }
public int VertIndex(int x, int y, int z, VoxelVertex v) { int cornerX = x; int cornerY = y; int cornerZ = z; switch (v) { // -x, -y, -z case VoxelVertex.BackBottomLeft: cornerX += 0; cornerY += 0; cornerZ += 0; break; // +x, -y, -z case VoxelVertex.BackBottomRight: cornerX += 1; cornerY += 0; cornerZ += 0; break; // -x, +y, -z case VoxelVertex.BackTopLeft: cornerX += 0; cornerY += 1; cornerZ += 0; break; // +x, +y, -z case VoxelVertex.BackTopRight: cornerX += 1; cornerY += 1; cornerZ += 0; break; // -x, -y, +z case VoxelVertex.FrontBottomLeft: cornerX += 0; cornerY += 0; cornerZ += 1; break; // +x, -y, +z case VoxelVertex.FrontBottomRight: cornerX += 1; cornerY += 0; cornerZ += 1; break; // -x, +y, +z case VoxelVertex.FrontTopLeft: cornerX += 0; cornerY += 1; cornerZ += 1; break; // +x, +y, +z case VoxelVertex.FrontTopRight: cornerX += 1; cornerY += 1; cornerZ += 1; break; } return CornerIndexAt(cornerX, cornerY, cornerZ); }
private static void CreateWaterFaces( VoxelHandle voxel, VoxelChunk chunk, int x, int y, int z, ExtendedVertex[] vertices, ushort[] Indexes, int startVertex, int startIndex) { // Reset the appropriate parts of the cache. cache.Reset(); // These are reused for every face. var origin = voxel.WorldPosition; float centerWaterlevel = voxel.LiquidLevel; var below = VoxelHelpers.GetVoxelBelow(voxel); bool belowFilled = false; bool belowLiquid = below.IsValid && below.LiquidLevel > 0; bool belowRamps = below.IsValid && below.RampType != RampType.None; if ((below.IsValid && !below.IsEmpty) || belowLiquid) { belowFilled = true; } float[] foaminess = new float[4]; for (int i = 0; i < cache.drawFace.Length; i++) { if (!cache.drawFace[i]) { continue; } BoxFace face = (BoxFace)i; var faceDescriptor = primitive.GetFace(face); int indexOffset = startVertex; for (int vertOffset = 0; vertOffset < faceDescriptor.VertexCount; vertOffset++) { VoxelVertex currentVertex = primitive.Deltas[faceDescriptor.VertexOffset + vertOffset]; // These will be filled out before being used lh . //float foaminess1; foaminess[vertOffset] = 0.0f; bool shoreLine = false; Vector3 pos = Vector3.Zero; Vector3 rampOffset = Vector3.Zero; var uv = primitive.UVs.Uvs[vertOffset + faceDescriptor.VertexOffset]; // We are going to have to reuse some vertices when drawing a single so we'll store the position/foaminess // for quick lookup when we find one of those reused ones. // When drawing multiple faces the Vertex overlap gets bigger, which is a bonus. if (!cache.vertexCalculated[(int)currentVertex]) { float count = 1.0f; float emptyNeighbors = 0.0f; float averageWaterLevel = centerWaterlevel; var vertexSucc = VoxelHelpers.VertexNeighbors[(int)currentVertex]; // Run through the successors and count up the water in each voxel. for (int v = 0; v < vertexSucc.Length; v++) { var neighborVoxel = new VoxelHandle(chunk.Manager, voxel.Coordinate + vertexSucc[v]); if (!neighborVoxel.IsValid) { continue; } // Now actually do the math. count++; if (neighborVoxel.LiquidLevel < 1) { emptyNeighbors++; } if (neighborVoxel.LiquidType == LiquidType.None && !neighborVoxel.IsEmpty) { shoreLine = true; } } foaminess[vertOffset] = emptyNeighbors / count; if (foaminess[vertOffset] <= 0.5f) { foaminess[vertOffset] = 0.0f; } // Check if it should ramp. else if (!shoreLine) { //rampOffset.Y = -0.4f; } pos = primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position; if ((currentVertex & VoxelVertex.Top) == VoxelVertex.Top) { if (belowFilled) { pos.Y -= 0.6f;// Minimum ramp position } var neighbors = VoxelHelpers.EnumerateVertexNeighbors2D(voxel.Coordinate, currentVertex) .Select(c => new VoxelHandle(chunk.Manager, c)) .Where(h => h.IsValid) .Select(h => MathFunctions.Clamp((float)h.LiquidLevel / 8.0f, 0.25f, 1.0f)); if (neighbors.Count() > 0) { if (belowFilled) { pos.Y *= neighbors.Average(); } } } else { uv.Y -= 0.6f; } pos += VertexNoise.GetNoiseVectorFromRepeatingTexture(voxel.WorldPosition + primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position); if (!belowFilled) { pos = (pos - Vector3.One * 0.5f); pos.Normalize(); pos *= 0.35f; pos += Vector3.One * 0.5f; } else if ((belowLiquid || belowRamps) && IsBottom(currentVertex)) { if (belowRamps) { pos -= Vector3.Up * 0.5f; } else { pos -= Vector3.Up * 0.8f; } } pos += origin + rampOffset; // Store the vertex information for future use when we need it again on this or another face. cache.vertexCalculated[(int)currentVertex] = true; cache.vertexFoaminess[(int)currentVertex] = foaminess[vertOffset]; cache.vertexPositions[(int)currentVertex] = pos; } else { // We've already calculated this one. Time for a cheap grab from the lookup. foaminess[vertOffset] = cache.vertexFoaminess[(int)currentVertex]; pos = cache.vertexPositions[(int)currentVertex]; } vertices[startVertex].Set(pos, new Color(foaminess[vertOffset], 0.0f, 1.0f, 1.0f), Color.White, uv, new Vector4(0, 0, 1, 1)); startVertex++; } bool flippedQuad = foaminess[1] + foaminess[3] > foaminess[0] + foaminess[2]; for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = flippedQuad ? primitive.FlippedIndexes[idx] : primitive.Indexes[idx]; ushort offset0 = flippedQuad ? primitive.FlippedIndexes[faceDescriptor.IndexOffset] : primitive.Indexes[faceDescriptor.IndexOffset]; Indexes[startIndex] = (ushort)(indexOffset + offset - offset0); startIndex++; } } // End cache.drawFace loop }
public Color GetColor(int x, int y, int z, VoxelVertex v) { return VertexColors[VertIndex(x, y, z, v)]; }
public void GetSharedVertices(Voxel v, VoxelVertex vertex, List<KeyValuePair<Voxel, List<VoxelVertex>>> vertices, List<Voxel> neighbors ) { vertices.Clear(); GetNeighborsVertex(vertex, v, neighbors); Vector3 myDelta = vertexDeltas[(int) vertex]; foreach(Voxel neighbor in neighbors) { if(neighbor == null || neighbor.IsEmpty) { continue; } List<VoxelVertex> vertsNeighbor = new List<VoxelVertex>(); Vector3 otherDelta = v.Position - neighbor.Position + myDelta; vertsNeighbor.Add(GetNearestDelta(otherDelta)); vertices.Add(new KeyValuePair<Voxel, List<VoxelVertex>>(neighbor, vertsNeighbor)); } }
public void GetNeighborsVertexDiag(VoxelVertex vertex, int x, int y, int z, List<Voxel> toReturn) { GetNeighborsSuccessors(VertexSuccessorsDiag[vertex], x, y, z, toReturn); }
//------------------------- public void GetNeighborsVertex(VoxelVertex vertex, Voxel v, List<Voxel> toReturn) { Vector3 grid = v.GridPosition; GetNeighborsVertex(vertex, (int) grid.X, (int) grid.Y, (int) grid.Z, toReturn); }
private static void CreateWaterFace(Voxel voxel, BoxFace face, VoxelChunk chunk, int x, int y, int z, bool top, ExtendedVertex[] vertices, int startVertex) { int idx = 0; int vertexCount = 0; int vertOffset = 0; int numVerts = 0; primitive.GetFace(face, primitive.UVs, out idx, out vertexCount, out vertOffset, out numVerts); for (int i = idx; i < idx + vertexCount; i++) { vertices[i + startVertex - idx] = primitive.Vertices[primitive.Indexes[i]]; } Vector3 origin = chunk.Origin + new Vector3(x, y, z); List <Voxel> neighborsVertex = new List <Voxel>(); for (int i = 0; i < vertexCount; i++) { VoxelVertex currentVertex = VoxelChunk.GetNearestDelta(vertices[i + startVertex].Position); chunk.GetNeighborsVertex(currentVertex, voxel, neighborsVertex); int index = chunk.Data.IndexAt(x, y, z); float averageWaterLevel = chunk.Data.Water[index].WaterLevel; float count = 1.0f; float emptyNeighbors = 0.0f; foreach (byte level in neighborsVertex.Select(vox => vox.WaterLevel)) { averageWaterLevel += level; count++; if (level < 1) { emptyNeighbors++; } } averageWaterLevel = averageWaterLevel / count; float averageWaterHeight = (float)averageWaterLevel / 8.0f; float foaminess = emptyNeighbors / count; if (foaminess <= 0.5f) { foaminess = 0.0f; } /* * if(chunk.Data.Water[index].IsFalling || !top) * { * averageWaterHeight = 1.0f; * } */ Vector3 pos = vertices[i + startVertex].Position; pos.Y *= averageWaterHeight; pos += origin; switch (face) { case BoxFace.Back: case BoxFace.Front: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.X, pos.Y), new Vector4(0, 0, 1, 1)); break; case BoxFace.Right: case BoxFace.Left: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.Z, pos.Y), new Vector4(0, 0, 1, 1)); break; case BoxFace.Top: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.X, pos.Z), new Vector4(0, 0, 1, 1)); break; } } }
public static bool IsTopVertex(VoxelVertex v) { return v == VoxelVertex.BackTopLeft || v == VoxelVertex.FrontTopLeft || v == VoxelVertex.FrontTopRight || v == VoxelVertex.BackTopRight; }
private static void CreateWaterFaces(Voxel voxel, VoxelChunk chunk, int x, int y, int z, ExtendedVertex[] vertices, int startVertex) { // Reset the appropriate parts of the cache. cache.Reset(); // These are reused for every face. Vector3 origin = chunk.Origin + new Vector3(x, y, z); int index = chunk.Data.IndexAt(x, y, z); float centerWaterlevel = chunk.Data.Water[chunk.Data.IndexAt(x, y, z)].WaterLevel; for (int faces = 0; faces < cache.drawFace.Length; faces++) { if (!cache.drawFace[faces]) { continue; } BoxFace face = (BoxFace)faces; // Let's get the vertex/index positions for the current face. int idx = 0; int vertexCount = 0; int vertOffset = 0; int numVerts = 0; primitive.GetFace(face, primitive.UVs, out idx, out vertexCount, out vertOffset, out numVerts); for (int i = 0; i < vertexCount; i++) { // Used twice so we'll store it for later use. int primitiveIndex = primitive.Indexes[i + idx]; VoxelVertex currentVertex = primitive.Deltas[primitiveIndex]; // These two will be filled out before being used. float foaminess; Vector3 pos; // We are going to have to reuse some vertices when drawing a single so we'll store the position/foaminess // for quick lookup when we find one of those reused ones. // When drawing multiple faces the Vertex overlap gets bigger, which is a bonus. if (!cache.vertexCalculated[(int)currentVertex]) { float count = 1.0f; float emptyNeighbors = 0.0f; float averageWaterLevel = centerWaterlevel; List <Vector3> vertexSucc = VoxelChunk.VertexSuccessors[currentVertex]; // Run through the successors and count up the water in each voxel. for (int v = 0; v < vertexSucc.Count; v++) { Vector3 succ = vertexSucc[v]; // We are going to use a lookup key so calculate it now. int key = VoxelChunk.SuccessorToEuclidianLookupKey(succ); // If we haven't gotten this Voxel yet then retrieve it. // This allows us to only get a particular voxel once a function call instead of once per vertexCount/per face. if (!cache.retrievedNeighbors[key]) { Voxel neighbor = cache.neighbors[key]; cache.validNeighbors[key] = voxel.GetNeighborBySuccessor(succ, ref neighbor, false); cache.retrievedNeighbors[key] = true; } // Only continue if it's a valid (non-null) voxel. if (!cache.validNeighbors[key]) { continue; } // Now actually do the math. Voxel vox = cache.neighbors[key]; averageWaterLevel += vox.WaterLevel; count++; if (vox.WaterLevel < 1) { emptyNeighbors++; } } averageWaterLevel = averageWaterLevel / count; float averageWaterHeight = averageWaterLevel / WaterManager.maxWaterLevel; foaminess = emptyNeighbors / count; if (foaminess <= 0.5f) { foaminess = 0.0f; } pos = primitive.Vertices[primitiveIndex].Position; pos.Y *= averageWaterHeight; pos += origin; // Store the vertex information for future use when we need it again on this or another face. cache.vertexCalculated[(int)currentVertex] = true; cache.vertexFoaminess[(int)currentVertex] = foaminess; cache.vertexPositions[(int)currentVertex] = pos; } else { // We've already calculated this one. Time for a cheap grab from the lookup. foaminess = cache.vertexFoaminess[(int)currentVertex]; pos = cache.vertexPositions[(int)currentVertex]; } switch (face) { case BoxFace.Back: case BoxFace.Front: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.X, pos.Y), new Vector4(0, 0, 1, 1)); break; case BoxFace.Right: case BoxFace.Left: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.Z, pos.Y), new Vector4(0, 0, 1, 1)); break; case BoxFace.Top: vertices[i + startVertex].Set(pos, new Color(foaminess, 0.0f, 1.0f, 1.0f), Color.White, new Vector2(pos.X, pos.Z), new Vector4(0, 0, 1, 1)); break; } } startVertex += 6; } }
public static IEnumerable <GlobalVoxelCoordinate> EnumerateVertexNeighbors2D( GlobalVoxelCoordinate Coordinate, VoxelVertex Vertex) { return(EnumerateNeighbors(VertexNeighbors2D[(int)Vertex], Coordinate)); }
public void SetColor(int x, int y, int z, VoxelVertex v, Color color) { VertexColors[VertIndex(x, y, z, v)] = color; }