- Home /
 
What is the "correct" what to make a procedural mesh script
I'd like to make a procedural mesh that can be changed at runtime and edit time.
I'm using [ExecuteInEditMode] and I get a warning
 Instantiating mesh due to calling MeshFilter.mesh during edit mode. This will leak meshes. Please use MeshFilter.sharedMesh instead.
 UnityEngine.MeshFilter:get_mesh()
 ProceduralPlane:Start() (at Assets/GMan/ProceduralPlane.cs:32)
 
               I tried changing mesh to sharedMesh but there is no sharedMesh. Should I create a Mesh and attach it to sharedMesh? I tried it, it didn't seem to work. I get a different warning about cleaning up meshes. I also tried creating the mesh in the constructor. I still get the same message about leaked meshes.
The question is, what's the correct way to do this? It would be nice if the docs mentioned the right way.
Note: A mesh that is created once (like some script you run and give parameters, click 'create' and it makes a mesh is NOT what I want). I want a mesh I can adjust in resolution after it has been placed in the scene and while I'm editing.
 using UnityEngine;
 using System.Collections;
 
 [ExecuteInEditMode]
 public class ProceduralPlane : MonoBehaviour {
 
     [Range(0, 100)]
     public float width = 1.0f;
 
     [Range(0, 100)]
     public float depth = 1.0f;
 
     [Range(1, 100)]
     public int subDivisionsAcross = 1;
 
     [Range(1, 100)]
     public int subDivisionsDown = 1;
 
     private Mesh m_mesh;
     private int m_oldSubdivisionsAcross;
     private int m_oldSubdivisionsDown;
     private float m_oldWidth;
     private float m_oldDepth;
 
     // Use this for initialization
     void Start() {
         MeshFilter mf = GetComponent<MeshFilter>();
         if (mf == null) {
             gameObject.AddComponent<MeshFilter>();
         }
         mf = GetComponent<MeshFilter>();
         m_mesh = mf.mesh;
         UpdateMesh();
     }
 
     void Update() {
         if (m_oldSubdivisionsAcross != subDivisionsAcross ||
             m_oldSubdivisionsDown != subDivisionsDown ||
             m_oldWidth != width ||
             m_oldDepth != depth) {
             UpdateMesh();
         }
     }
 
     private void UpdateMesh() {
         int vertsAcross = subDivisionsAcross + 1;
         int vertsDown = subDivisionsDown + 1;
         int numVertices = vertsAcross * vertsDown;
         int numQuads = subDivisionsAcross * subDivisionsDown;
 
         Vector3[] positions = new Vector3[numVertices];
         Vector3[] normals = new Vector3[numVertices];
         Vector2[] uvs = new Vector2[numVertices];
         Color32[] colors = new Color32[numVertices];
         int[] triangles = new int[numQuads * 6];
 
         for (int y = 0; y <= subDivisionsDown; ++y) {
             for (int x = 0; x <= subDivisionsAcross; ++x) {
                 int offset = y * vertsAcross + x;
                 float u = (float)x / (float)subDivisionsAcross;
                 float v = (float)y / (float)subDivisionsDown;
                 float px = (u - 0.5f) * width;
                 float pz = (v - 0.5f) * depth;
 
                 positions[offset] = new Vector3(px, 0.0f, pz);
                 normals[offset] = Vector3.up;
                 uvs[offset] = new Vector2(u, v);
                 colors[offset] = new Color32(255, 255, 255, 255);
             }
         }
 
         for (int y = 0; y < subDivisionsDown; ++y) {
             int yoff0 = (y + 0) * vertsAcross;
             int yoff1 = (y + 1) * vertsAcross;
             for (int x = 0; x < subDivisionsAcross; ++x) {
                 int offset = (y * subDivisionsAcross + x) * 6;
 
                 triangles[offset + 0] = yoff0 + x;
                 triangles[offset + 2] = yoff0 + x + 1;
                 triangles[offset + 1] = yoff1 + x;
 
                 triangles[offset + 3] = yoff1 + x;
                 triangles[offset + 5] = yoff0 + x + 1;
                 triangles[offset + 4] = yoff1 + x + 1;
             }
         }
 
         // we have to set no triangles before setting the verts
         // to avoid bounds checking errors.
         m_mesh.triangles = new int[0]; 
         m_mesh.vertices = positions;
         m_mesh.normals = normals;
         m_mesh.uv = uvs;
         m_mesh.colors32 = colors;
         m_mesh.triangles = triangles;
         m_mesh.RecalculateBounds();
 
         m_oldSubdivisionsAcross = subDivisionsAcross;
         m_oldSubdivisionsDown = subDivisionsDown;
         m_oldWidth = width;
         m_oldDepth = depth;
     }
 }
 
               Note: if you want to try the script, create a empty GameObject, attach a MeshRenderer component, set a material, then add this script.
Your answer