Search Unity

Swapping out a mesh at runtime on a GameObject

Discussion in 'Scripting' started by mstelzer4, Apr 7, 2010.

  1. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    I have a GameObject with a MeshFilter and Renderer and Material but it also has a bunch of other components such as scripts attached.

    In response to a game even I want to swap the mesh and materials out with that of another asset.

    I've loaded the other asset and I can get access to it's MeshFilter and Renderer (and hence Materials) but it's flaky. Sometimes the new mesh doesn't render. Sometimes after a save the original asset prefab seems to have been modified! The new mesh shows it's MeshFilter referencing the mesh in "*scene" and not "*asset" and I don't know what that means.

    I definitely don't want to Instantiate the new mesh because I have all the state of the original object but I just need to change the appearance.

    Surely someone has encountered this before, but I can't find a solution.
     
    dan_ginovker likes this.
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Instantiating a new mesh won't change any of the other components.

    --Eric
     
  3. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    Instantiating a new mesh creates a new GameObject which is NOT what I want. Forget I mentioned Instantiate then. How do I change the mesh on an existing GameObject?
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    No, instantiating a mesh just instantiates a mesh. Not a game object.

    Code (csharp):
    1. var aMesh : Mesh;
    2.  
    3. function Start () {
    4.     var meshInstance : Mesh = Instantiate(aMesh);
    5.     GetComponent(MeshFilter).mesh = meshInstance;
    6. }
    --Eric
     
  5. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    Ah, but I don't have the mesh yet, I need to load it from a resource. And also what about the materials?
     
  6. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    And is the Instantiate necessary? Why can't I just assign the mesh to my existing GameObject without Instantiate?
     
  7. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    Well it's not quite working. Here is my code:

    Code (csharp):
    1.  
    2.     public void OnTypeChanged()
    3.     {
    4.         Vector3 newScale = new Vector3(1, 1, 1);
    5.         GameObject go;
    6.  
    7.         switch (Type)
    8.         {
    9.             case NodeType.TREE:
    10.                 go = Resources.Load("Meshes/BanyanTree") as GameObject;
    11.                 newScale = new Vector3(0.15f, 0.15f, 0.15f);
    12.                 break;
    13.  
    14.             case NodeType.ROCK:
    15.                 go = Resources.Load("Meshes/RockMesh") as GameObject;
    16.                 newScale = new Vector3(0.5f, 0.5f, 0.5f);
    17.                 break;
    18.  
    19.             default:
    20.                 go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    21.                 break;
    22.         }
    23.        
    24.         MeshFilter mf1 = go.GetComponent(typeof(MeshFilter)) as MeshFilter;
    25.         MeshFilter mf2 = GetComponent(typeof(MeshFilter)) as MeshFilter;
    26.         mf2.mesh = Instantiate(mf1.mesh) as Mesh;
    27.  
    28.         transform.localScale = newScale;
    29.  
    30.         if (Type == TreeNodeTypeWatcher.NodeType.NONE)
    31.         {
    32.             renderer.material = null;
    33.         }
    34.         else
    35.         {
    36.             renderer.material = Instantiate(go.renderer.material) as Material;
    37.         }
    38.     }
    39.  
    So I import a package such as RockMesh from another project and place the RockMesh prefab into my "Resources/Meshes" folder. Now I hit this code when I change the type of a placed GameObject from NONE to ROCK. The object appears now as a rock. Good, right? Wrong :(

    If I then drag my RockMesh prefab onto the scene, the mesh reference in its MeshFilter is now set to None! The collider is still there so I see the wireframe of the mesh, but there's no mesh to draw in it anymore.

    What removed the Mesh from my prefab?
     
  8. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    I'm even more confused now, maybe my understanding of Instantiate is wrong, but here's what happens when I use the above code:

    1) Import the RockMesh package. The mesh prefab has a MeshFilter with a mesh named "RockMesh".

    2) Change the type on my object to ROCK so that the above code runs.

    3) The ROCK object's MeshFilter now has mesh "RockMesh Instance(Clone)" and the RockMesh prefab's MeshFilter has "RockMesh Instance" as it's Mesh.

    How did the prefab change? If you look at the code, the prefab was loaded as GameObject "go", its MeshFilter was retrieved as mf1, and mf1 was Instantiated to mf2's Mesh.

    Now save and quit and restart Unity and the prefab's MeshFilter's Mesh is now "None (Mesh)"
     
  9. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    Sorry for yet another post but more to add:

    I don't even have to save and quit! Something modifies the prefab without me even saving!

    I import the mesh, change a game object to ROCK, then quit without saving. When I get back in the editor here is what's odd...

    In the project view I can see the RockMesh mesh assigned to the RockMesh prefab.
    When I click that prefab and look in the Inspector I see "None (Mesh)" and the MeshFilter's Mesh.
    If I try to reassign the MeshFilter, I see "* Assets *" in grey with "RockMesh - RockMesh" listed under that. When I try to select that mesh, the selction snaps back to "None (Mesh)"

    I'm thoroughly confused. I can't see how an asset is being modified without me saving my project.
     
  10. mstelzer4

    mstelzer4

    Joined:
    Apr 7, 2010
    Posts:
    9
    Seems that Changing:

    Resources.Load("...

    to

    Instantiate(Resources.Load(...

    Did the trick. I'm guessing I was somehow manipulating the original asset and not a clone of it, but I can't see how since I'm not actually manipulating the loaded resources, so I'd still like to hear some insights on this.
     
    GamerLordMat likes this.