0
\$\begingroup\$

I procedurally generate chunks and use the marching cube algorithm to create meshes in 3D. At first, I just created a gameObject for each cube (of course, I knew it was not optimized, but I wanted to see if the algorithm worked). For now I stock all gamesObject in child of "blocks" but it would be much more optimized to directly merge the meshes between them and only create a single gameObject. However, i did not find any way to directly merge the meshes between them.
So my question is: is there a way to directly merge meshes between them without having to use gameObject? (don't worry about texturing)

Here's the code:

    public static GameObject GenerateChunk(int[,,] map, int chunkSize, Vector3 chunkPosition)
    {
        GameObject blocks = new GameObject("BlockList");
        GameObject newMesh;
        int[] cubeVertices = new int[8];


        // create each mesh in a gameObject as child of "blocks"
        for (int x = 0; x < chunkSize; x++)
            for (int z = 0; z < chunkSize; z++)
                for (int y = 0; y < chunkSize; y++) {
                    /*
                    define the vertices (cubeVertices)
                    */
                    Vector3 cubePosition = new Vector3(chunkPosition.x + x, chunkPosition.y + y, chunkPosition.z + z);
                    newMesh = GenerateCube(cubePosition, cubeVertices);

                    if (newMesh != null)
                        newMesh.transform.parent = blocks.transform;
                }

        //combine every children of "blocks" and delete them
        MeshFilter[] filters = blocks.GetComponentsInChildren<MeshFilter>();
        List<CombineInstance> combine = new List<CombineInstance>();
        for (int i = 0; i < filters.Length; i++) {
            if (filters[i].sharedMesh == null)
                continue;
            for (int j = 0; j < filters[i].sharedMesh.subMeshCount; j++) {
                CombineInstance ci = new CombineInstance
                {
                    mesh = filters[i].sharedMesh,
                    subMeshIndex = j,
                    transform = filters[i].transform.localToWorldMatrix
                };
                combine.Add(ci);
            }
            Destroy(filters[i].gameObject);
        }

        //create the chunk and set the final mesh with the CombineMeshes function
        GameObject chunk = new GameObject("Chunk", typeof(MeshFilter), typeof(MeshRenderer));
        chunk.GetComponent<MeshFilter>().mesh.CombineMeshes(combine.ToArray(), true, true);
        Destroy(blocks);
        return chunk;
    }
\$\endgroup\$
0
\$\begingroup\$

Your code shown here doesn't actually depend on GameObjects - they're just serving as an expensive way for you to store a set of positions. So you could get something equivalent as follows, just using transformation matrices instead:

// You can assign the default Unity cube here so you have a template mesh to stamp-out.
public Mesh cubeMesh;

public static Mesh GenerateChunkMesh(int[,,] map, int chunkSize, Vector3Int chunkPosition)
{
    // Prep a list of mesh instances to stitch together.
    List<CombineInstance> instances = new List<CombineInstance>();

    // Prepare a "template" object with the attributes we want to apply to each block.
    CombineInstance instance;
    instance.mesh = cubeMesh;

    for (int x = 0; x < chunkSize; x++)
        for (int z = 0; z < chunkSize; z++)
            for (int y = 0; y < chunkSize; y++) {                    
                Vector3Int cubePosition = chunkPosition + new Vector3Int(x, y, z);

                // If this part of the map is empty, skip it without making a block.
                if(map[cubePosition.x, cubePosition.y, cubePosition.z] == 0)
                    continue;

                // Make a transformation matrix that positions the cube at this location.
                instance.transform = Matrix4x4.Translate(cubePosition);

                // Record "I want a cube at this position" in our work list.
                instances.Add(instance);
            }
        }
    }

    // Build a mesh that combines all of the requested cubes in our work list.
    var mesh = new Mesh();
    mesh.CombineMeshes(instances.ToArray(), true, true);

    return mesh;
}

But note that this is still rendering more geometry than you need, because you're not eliminating hidden faces. This answer outlines how you can do that with your own mesh generation routine.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.