Beispiel #1
0
    public void UpdateMesh()
    {
        if (_mesh == null) {
            _mesh = new Mesh();
            GetComponent<MeshFilter>().sharedMesh = _mesh;
            GetComponent<MeshRenderer>().sharedMaterial =
                terrain.GetComponent<MeshRenderer>().sharedMaterial;
        }
        var access = new IRawBlockAccess[8];
        for (var i = 0; i < access.Length; i++)
            access[i] = terrain[
                new ChunkPos(position.x + (i & 1),
                             position.y + ((i >> 1) & 1),
                             position.z + ((i >> 2) & 1))];
        SurfaceNetsMeshGenerator.Generate(_mesh, access, terrain);

        // This should also update the collision mesh properly.
        GetComponent<MeshCollider>().sharedMesh = _mesh;
    }
    // TODO: Attempt to speed this up a little.
    public static Mesh Generate(Mesh mesh, IRawBlockAccess[] access, IBlockMaterialLookup lookup)
    {
        var vertices = new List<Vector3>();
        var normals  = new List<Vector3>();
        var colors   = new List<Color>();
        var indices  = new List<int>();

        int width, depth, height;
        width = depth = height = Chunk.SIZE + 1;

        var pos = new int[3];
        var R = new int[]{ 1, width, width * depth };
        var grid = new BlockData[8];

        Vector3[] _vertexBuffer = new Vector3[R[2] * 2];

        // March over the voxel grid.
        for (pos[2] = 0; pos[2] < height; pos[2]++, R[2] = -R[2]) {

            // m is the pointer into the buffer we are going to use.
            var m = (~pos[2] & 1) * width * depth;

            for (pos[1] = 0; pos[1] < depth; pos[1]++)
            for (pos[0] = 0; pos[0] < width; pos[0]++, m++) {

                // Read in 8 field values around this vertex and store them in an array.
                // Also calculate 8-bit mask, like in marching cubes, so we can speed up sign checks later.
                int mask = 0, g = 0;
                for (var z = 0; z < 2; z++)
                for (var y = 0; y < 2; y++)
                for (var x = 0; x < 2; x++, g++) {
                    var accessIndex = 0;
                    var index = ((pos[0] + x) & 0xF) | (((pos[1] + y) & 0xF) << 4) | (((pos[2] + z) & 0xF) << 8);
                    if (pos[0] + x > Chunk.SIZE - 1) accessIndex |= 1;
                    if (pos[1] + y > Chunk.SIZE - 1) accessIndex |= 2;
                    if (pos[2] + z > Chunk.SIZE - 1) accessIndex |= 4;
                    grid[g] = access[accessIndex][index];
                    mask |= grid[g].isSolid ? (1 << g) : 0;
                }

                // Check for early termination if cell does not intersect boundary.
                if ((mask == 0) || (mask == 0xFF))
                    continue;

                // Sum up edge intersections.
                var edgeMask = _edgeTable[mask];
                var v = new Vector3();
                var eCount = 0;

                // For every edge of the cube...
                for (var i = 0; i < 12; i++) {

                    // Use edge mask to check if it is crossed.
                    if((edgeMask & (1 << i)) == 0)
                        continue;

                    // If it did, increment number of edge crossings.
                    eCount++;

                    // Now find the point of intersection.
                    var e0 = _cubeEdges[i << 1];       // Unpack vertices.
                    var e1 = _cubeEdges[(i << 1) + 1];
                    var g0 = GetGridValue(grid[e0]);   // Unpack grid values.
                    var g1 = GetGridValue(grid[e1]);
                    var t  = g0 - g1;                  // Compute point of intersection.

                    if (Mathf.Abs(t) <= 1e-6)
                        continue;
                    //t = g0 / t;

                    // Interpolate vertices and add up intersections (this can be done without multiplying).
                    for (int j = 0, k = 1; j < 3; j++, k <<= 1) {
                        var a = e0 & k;
                        var b = e1 & k;
                        if (a != b) v[j] += (a != 0) ? (1.0F - t) : t;
                        else v[j] += (a != 0) ? 1.0F : 0.0F;
                    }
                }

                // Now we just average the edge intersections and add them to coordinate.
                var s = 1.0F / eCount;
                for (var i = 0; i < 3; i++)
                    v[i] = pos[i] + s * v[i];

                // Add vertex to buffer.
                _vertexBuffer[m] = v;

                // Now we need to add faces together, to do this we just loop over 3 basic components.
                for (var i = 0; i < 3; i++) {
                    // The first three entries of the edge_mask count the crossings along the edge.
                    if ((edgeMask & (1 << i)) == 0)
                        continue;

                    // i = axes we are point along. iu, iv = orthogonal axes.
                    var iu = (i + 1) % 3;
                    var iv = (i + 2) % 3;

                    // If we are on a boundary, skip it.
                    if ((pos[i] <= 0) || (pos[iu] <= 0) || (pos[iv] <= 0))
                        continue;

                    // Otherwise, look up adjacent edges in buffer.
                    var du = R[iu];
                    var dv = R[iv];

                    var v1 = _vertexBuffer[m];
                    var v2 = _vertexBuffer[m - du];
                    var v3 = _vertexBuffer[m - du - dv];
                    var v4 = _vertexBuffer[m - dv];

                    var normal1 = Vector3.Cross(v2 - v1, v3 - v1).normalized;
                    var normal2 = Vector3.Cross(v3 - v1, v4 - v1).normalized;

                    // Remember to flip orientation depending on the sign of the corner.
                    if ((mask & 1) != 0) {
                        var color = lookup.GetMaterial(grid[0].material).color;
                        AddFlatTriangle(vertices, normals, colors, indices, v1, v2, v3, normal1, color);
                        AddFlatTriangle(vertices, normals, colors, indices, v1, v3, v4, normal2, color);
                    } else {
                        var color = lookup.GetMaterial(grid[1 << i].material).color;
                        AddFlatTriangle(vertices, normals, colors, indices, v4, v2, v1, -normal1, color);
                        AddFlatTriangle(vertices, normals, colors, indices, v4, v3, v2, -normal2, color);
                    }
                }
            }
        }

        mesh.Clear();
        mesh.vertices  = vertices.ToArray();
        mesh.normals   = normals.ToArray();
        mesh.colors    = colors.ToArray();
        mesh.triangles = indices.ToArray();
        mesh.Optimize();

        return mesh;
    }