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 }
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; } }