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