Why i'm getting Thread::CurrentThreadIsMainThread() error and Internal_Create is not allowed error ?

I want to update the plane size in real time while the game is running.

The script is attached to empty GameObject that i added to it a Mesh Filter and a Mesh Renderer components.

I moved the variables vertices and mesh to be global.

Once i moved the two variables to be global and updating the mesh vertices inside the Update function i’m getting this two exceptions when running the game:

Internal_Create is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour ‘DragAndDrop’ on game object ‘CreatedPlane’.
See “Script Serialization” page in the Unity Manual for further details.

And

Thread::CurrentThreadIsMainThread()
UnityEngine.Mesh:.ctor()

The script:

using UnityEngine;
using System.Collections;

public class DragAndDrop : MonoBehaviour
{
    public float width = 5f;
    public float height = 5f;

    private Vector3[] vertices = new Vector3[4];
    private Mesh mesh = new Mesh();

    void Start()
    {
        MeshFilter mf = GetComponent<MeshFilter>();
        mf.mesh = mesh;

        // Vertices
       
        vertices = new[] { new Vector3(0, 0, 0), new Vector3(width, 0, 0), new Vector3(0, height, 0), new Vector3(width, height, 0) };

        // Triangles

        int[] tri = new int[6];

        tri[0] = 0;
        tri[1] = 2;
        tri[2] = 1;

        tri[3] = 2;
        tri[4] = 3;
        tri[5] = 1;

        // Normals (Only if you want to display the object in the game)

        Vector3[] normals = new Vector3[4];

        normals[0] = Vector3.forward;
        normals[1] = Vector3.forward;
        normals[2] = Vector3.forward;
        normals[3] = Vector3.forward;

        // UVs (How textures are displayed)

        Vector2[] UV = new Vector2[4];

        UV[0] = new Vector2(0, 0);
        UV[1] = new Vector2(1, 0);
        UV[2] = new Vector2(0, 1);
        UV[3] = new Vector2(1, 1);

        // Assgin Arrays!


        mesh.vertices = vertices;
        mesh.triangles = tri;
        mesh.normals = normals;
        mesh.uv = UV;
    }

    void Update()
    {
        mesh.vertices = vertices;
    }
}

I bet the problem is just new Mesh(). When you have an assignment like that on a member field (not actually a global, that’s something else), it gets executed whenever an instance of the parent class gets constructed. Unity does a lot of its object construction on threads other than the main thread, including, most likely, instances of your DragAndDrop component.

Mesh is probably special in that instances of it must be constructed on the main thread. (It probably needs to coordinate heavily with the graphics API, and that tends to get really messy to do on multiple threads, especially for a cross-platform product like Unity.)

Fortunately, it should be easy to keep the declaration of the member field where it is, but move the initialization elsewhere, to a place that you know will be executing on the main thread. The most obvious in this case is at the top of the Start() method. (The vertices can stay as they are.)

    private Mesh mesh; // don't initialize it here, just declare it's existence
    void Start()
    {
        mesh = new Mesh(); // initialize it here instead
        MeshFilter mf = GetComponent<MeshFilter>();
        mf.mesh = mesh;
        // the rest...
2 Likes