Пример #1
0
        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
        }
Пример #2
0
        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;
            }
        }