Advertisement

Render submesh with material of mesh by script.

Started by September 29, 2017 10:42 PM
1 comment, last by h8CplusplusGuru 7 years, 2 months ago

Hi,

I want to create a fairly large "tilemap" with 3D assets. I started testing and have very promising results with generating the terrain mesh by code.


private Mesh createChunck(int width, int height)
    {
        Vector3[] verts = new Vector3[width * height * 6];
        Vector2[] uvs = new Vector2[width * height * 6];
        int[] triangles = new int[width * height * 6];

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                //Debug.Log("x: " + x + ", y: " + y);

                verts[(y * width + x) * 6 + 0] = new Vector3(x, 0, y);
                verts[(y * width + x) * 6 + 1] = new Vector3(x + 1, 0, y);
                verts[(y * width + x) * 6 + 2] = new Vector3(x + 1, .5f, y + 1);

                verts[(y * width + x) * 6 + 3] = new Vector3(x, 0, y);
                verts[(y * width + x) * 6 + 4] = new Vector3(x + 1, .5f, y + 1);
                verts[(y * width + x) * 6 + 5] = new Vector3(x, 0, y + 1);

                uvs[(y * width + x) * 6 + 0] = new Vector2(0, 0);
                uvs[(y * width + x) * 6 + 1] = new Vector2(1, 0);
                uvs[(y * width + x) * 6 + 2] = new Vector2(1, 1);

                uvs[(y * width + x) * 6 + 3] = new Vector2(0, 0);
                uvs[(y * width + x) * 6 + 4] = new Vector2(1, 1);
                uvs[(y * width + x) * 6 + 5] = new Vector2(0, 1);

                for (int t = 0; t < 6; t++)
                {
                    triangles[(y * width + x) * 6 + t] = (y * width + x) * 6 + 5 - t;
                }
            }
        }

        Mesh m = new Mesh();
        m.vertices = verts;
        m.uv = uvs;
        m.triangles = triangles;
        m.RecalculateNormals();

        return m;
    }

 

I can easily render 10 x 10 "chuncks" of 100 x 100 tiles in a scene which is should be enough. However I need the tri's to be able to change material individually, by code. Obviously without (re)generating the mesh again since that does take some time. With the following code I can change and add submeshes to the mesh.


        test.subMeshCount = 2;

        int[] tri1 = new int[] { 5, 4, 3 };
        int[] tri2 = new int[] { 2, 1, 0 };

        test.SetTriangles(tri1, 0);
        test.SetTriangles(tri2, 1);

And it seems like simply adding a Material array to Graphics.DrawMesh(...) but unfortunately it only takes a single material and all the triangles that are out of the submesh group 0 are not being drawn.

I could probably create a GameObject with a renderer component and thrown in the mesh and create my material array there but I don't really need/want a GameObject. I'm just looking for a clean way to render this mesh my script with different materials for it's submeshes by script.

In case you are interested in the stats of rendering 1.000.000 tiles using 100 large meshes here is a screengrab. Looks promising, but I got to be able to change texture/material on individual tiles dynamically. With this setup I might look into a perspective cam and allow for a slightly sharper angle on the camera.
image.thumb.png.b422c80df2ead38903eb5c2af4ff20bd.png

Ok, some options:

1) Changing the mesh data:

A texture-atlas ( a single aggregate texture that contains each tile-texture side-by-side ), and each sub-texture can be referenced through enumeration. Using a triangle list, change the tex-coords of a given quad to the appropriate area in a texture-atlas.

2) using a shader:
You have a texture-atlas. You have a second texture, which contains the map-tile-info in each pixel, such as texture-atlas-index. Pixel (0,0) refers to tile(0,0), and contains a texture-atlas index in say channel R. The shader then grabs the texture-atlas index (channel R) and applies that part of the texture-atlas to the quad. 

This topic is closed to new replies.

Advertisement