Search Unity

Assigning procedural Quad mesh to GameObject loses transform.position

Discussion in 'Scripting' started by GDiSalvo, May 28, 2020.

  1. GDiSalvo

    GDiSalvo

    Joined:
    Apr 14, 2013
    Posts:
    4
    Hi everyone! I had the problem mentioned in the subject and I only found one similar thread in answers.unity. There I got a solution, but it looks weird and maybe there is a better way to solve this.Below I post an extended description and my code that's easy to understand, but to summarize:
    • If I create a quad mesh and assign it to a GO, I can get a grid with meshes in the right position but all the GOs are at zero transform.position (I lose that info for later use)
    • If I try to set the GO transform.position (doesn't matter the method used or if I do it after/before assigning the mesh) I keep the right transform.position but all the meshes are moved.
    • The present solution (lines between comments in the code below) requires to recalculate an reassign again all the meshes values! I think that this looks bad and redundant
    Full description and code:
    I'm making a procedural grid of quads (so, it's a plane with square tiles). I post my code below to create a single tile: I create a quad and assign it to a GO, this is simple and works fine with all the tiles in the right position but all the GOs transform.position are at the zero position. The problem is that I need to add a dynamic destroy of this objects when they are far from the player, and I don't have a tile transform.position to compare!
    I've added a vertices' repositioning (as the linked thread mentioned) and now I have the correct positioning and the transform.position correct values, but it's an ugly solution! Maybe anyone knows about a better option. Thank you!

    public void CreateQuadMesh(GameObject segmentPrefab, Vector3 pointX0Z0, Vector3 pointX1Z0, Vector3 pointX0Z1, Vector3 pointX1Z1)
    {
    Vector3[] vertices = new Vector3[4] { pointX0Z0, pointX1Z0, pointX0Z1, pointX1Z1 };
    mesh = new Mesh();
    mesh.vertices = vertices;
    mesh.triangles = tris;
    mesh.RecalculateNormals();
    mesh.uv = uv;
    tempQuad = Instantiate(segmentPrefab, Vector3.zero, Quaternion.identity);
    tempQuad.GetComponent<MeshFilter>().mesh = mesh;

    // Required added steps to keep position in transform:
    // - doing nothing = right position but transform.position zero
    // - assign transform.position only = GO with right transform.position but mesh moves position
    tempQuad.transform.position = pointX0Z0;
    vertices[0] = pointX0Z0 - pointX0Z0;
    vertices[1] = pointX1Z0 - pointX0Z0;
    vertices[2] = pointX0Z1 - pointX0Z0;
    vertices[3] = pointX1Z1 - pointX0Z0;
    mesh.Clear();
    mesh.vertices = vertices;
    mesh.triangles = tris;
    mesh.RecalculateNormals();
    mesh.uv = uv; // this maybe is the only one not required
    //
    tempQuad.GetComponent<MeshCollider>().sharedMesh = mesh;
    }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Not sure what your question is. Vertices are always in local space on an object. That's what lets you make a cube and drag it around without changing the vertices inside it. For instance, two default cubes share the same mesh, but can be displayed anywhere at any scale and any rotation.

    If you wanna see some more procedural geometry examples, check out my MakeGeo package.

    MakeGeo is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/makegeo

    https://github.com/kurtdekker/makegeo

    https://gitlab.com/kurtdekker/makegeo

    https://sourceforge.net/p/makegeo
     
  3. GDiSalvo

    GDiSalvo

    Joined:
    Apr 14, 2013
    Posts:
    4
    Hi. The question was how to "copy" the (correct) position of the created mesh to the gameobject to whom I was assigning it. The solution above required to set twice the mesh position, but I'm posting below a better solution I found.
    Thanks for answer! I'll be checking your package.
     
  4. GDiSalvo

    GDiSalvo

    Joined:
    Apr 14, 2013
    Posts:
    4
    I found a better way to code the method above. The modified code assign immediately to the gameobject the new empty mesh created, and then I configure the mesh values. It's really obvious once you see it, but I was always performing all the mesh creation before assign it to the GO...
    Here's the new code:


    public void CreateQuadMesh(GameObject segmentPrefab, Vector3 pointX0Z0, Vector3 pointX1Z0, Vector3 pointX0Z1, Vector3 pointX1Z1)
    {
    tempQuad = Instantiate(segmentPrefab, Vector3.zero, Quaternion.identity);
    tempQuad.transform.position = pointX0Z0;
    mesh = new Mesh();
    tempQuad.GetComponent<MeshFilter>().mesh = mesh;
    tempQuad.GetComponent<MeshCollider>().sharedMesh = mesh;
    Vector3[] vertices = new Vector3[4] {pointX0Z0 - pointX0Z0, pointX1Z0 - pointX0Z0, pointX0Z1 - pointX0Z0, pointX1Z1 - pointX0Z0 };
    mesh.vertices = vertices;
    mesh.triangles = tris;
    mesh.RecalculateNormals();
    mesh.uv = uv;
    }