Search Unity

Question Skinned Mesh Renderer is invisible when istantiated

Discussion in 'Prefabs' started by AQAGA, Jun 3, 2020.

  1. AQAGA

    AQAGA

    Joined:
    Jan 11, 2020
    Posts:
    25
    I have a model, that has been exported from blender to unity (.fbx). All the closing are a separate GameObject that had been extruded from the original mesh and then separated (if it is relevant). Thus I have a skinned mesh renderer in unity. Everything is displayed as it should. But if I make a prefab of one of those objects, delete it from the parent, and readd it back to where it was (with the same root bone) = it suddenly is not visible anymore. The position matches, but the mesh is not visible anywhere. Why is that? What am i missing?
    I need this to work for the equipment system.
     
  2. arsalaan

    arsalaan

    Joined:
    Aug 27, 2020
    Posts:
    2
    were you able to find any solution ?
     
  3. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Bumping old topic since the same thing is happening here. I'm trying to create a skinned mesh + animator from code instead of dragging in a model, and not sure what's going wrong. It all works fine when I drag in the model, but if I try to recreate the exact same settings/references manually, it won't ever show up. The bounds and position appear correctly in the editor, it just doesn't render.
     
  4. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Looking at the serialized scene, the difference I see is the Animator component visible one has "m_HasTransformHierarchy: 0" and the invisible one has "m_HasTransformHierarchy: 1". I assume that's because it should be getting the bones from the avatar. That property is not settable, though.
     
  5. XenonFossil

    XenonFossil

    Joined:
    Sep 11, 2017
    Posts:
    1
    Okay I figured this out!! For some reason, trying to build a prefab from children of an imported-to-scene .blend or .fbx, doesn't work when you then take those prefabs made from the children, and re-add them to the base GameObject with the armature child.

    If you make make a GameObject child from scratch add a skinnedMeshRenderer (SkMR) component, and add/drag in in the Mesh you want, and apply the root transform- that also does not work. The mesh just straight up doesn't render in editor or game. This video is what you can watch which works:



    But also here's what to do in text tutorial format and what I'm gonna use for my game so you can change body parts and add/change clothing:

    1. Drag your model file from your project that contains the armature and all the meshes the armature effects (.blend, .fbx, etc) into your scene heirarchy.

    2. Unpack the Auto-Prefab. You can now safely Delete all the children that you won't need right now (duplicate hats, shirts, etc) - don't worry we can add them back later - as long as you have at least 1 GameObject with a working SkMR & visible working mesh in the editor/game view.

    3. Now you will have an unpacked prefab - so basically just a regular modifiable game object. It should be a root/base gameobject with the same name as your model filename, with children including all the gameobjects containing individual meshes/skinned mesh renderers, and another child that is the armature with all the bone children.
    You can rename it to whatever you like - PlayerModel, CharacterModel, whatever. Make the base GameObject (the parent of the Armature and all the mesh GOs) into a new Prefab if you want to modify, instantiate, duplicate, attach code, set up components, etc.
    Here's what my hierarchy now looks like:

    mfimg.PNG
    (I have a Parent GO, FurryChara, to hold code components and stuff, but i think you can just use the new prefab you made, in mine, FurryPrefab, as-is)

    4. Here's the main solution: So, in order to change body parts or add a new clothing, equipment, or accessories, you have to DUPLICATE one of the existing working SkMR game objects, and then you change the Mesh and/or Material on the duplicated one in the inspector/via code, and it will be properly hooked up to the armature with correct weights and also ACTUALLY SHOW UP!!

    skmr.PNG

    You can either duplicate in the Hierarchy (Ctrl+D when selected) or through code, quick and dirty modifiable example below.

    Code (CSharp):
    1.  
    2. //attach this component to the base/parent GO so the transform.Find() works properly
    3. public class ChangeEquipment : MonoBehaviour
    4. {
    5.  
    6.     public void AddEquipment()
    7.     {
    8.         //get all the meshes in the resources folder
    9.         //this should get all the meshes within all .blend, fbx files.
    10.         //probably the better way to do this is to cache them in a singleton,
    11.          //and make a dictionary with string keys for the names
    12.         Mesh[] meshes = Resources.FindObjectsOfTypeAll<Mesh>();
    13.         Mesh mesh = null;
    14.  
    15.         //but if you just wanna test this, just go through and find a mesh by name
    16.         for (int i = 0; i < meshes.Length; i++)
    17.         {
    18.             if (meshes[i].name == "Helmet")
    19.             {
    20.                 mesh = meshes[i];
    21.                 break;
    22.             }
    23.         }
    24.  
    25.         //grab an existing game object in the unpacked prefab
    26.         GameObject go = transform.Find("Head").gameObject;
    27.  
    28.         //then you can make a copy of it! and it should appear!
    29.         GameObject goCopy = Instantiate(go);
    30.         //dont forget to change the the mesh to the one we grabbed
    31.         goCopy.GetComponent<SkinnedMeshRenderer>().sharedMesh = mesh;
    32.         //if you need to change the material, do that also
    33.         goCopy.GetComponent<SkinnedMeshRenderer>().sharedMaterial =
    34. Resources.Load("Materials/Helmet_Material", typeof(Material)) as Material;
    35.  
    36.  
    37.     }
    38. }
    39.  
    This will not take into account the Bounds properties (it will just copy them from whatever gameobj you grab). I don't know if this will cause problems with certain things. But it should be easier to figure out now that your mesh actually appears hahaha.

    Hope this helps!!!
     
    Last edited: Nov 29, 2021
  6. RSolids

    RSolids

    Joined:
    May 19, 2021
    Posts:
    22
    Rezzing. I ran into something like this today. I don't have a solution, but what I found basically fits in with the posts above, including the proposed solution.

    What I found (in the prefab's YAML) was removing the mesh from the SkinnedMeshRenderer in the inspector cleared out a certain bones[] array. It kept the root bone reference, but all the other references to the rig/armature were cleared out. Setting the SkinnedMeshRenderer's mesh to something else did not automatically populate the bones.

    As a test, I manually filled in the bones via text editor/YAML and the SkinnedMeshRenderer once again showed the mesh inside the editor. Unfortunately, either I missed something, or I had the list of bones in the wrong order. I was able to see the mesh, but it was ~50% messed up. Either way, I could tell it was working to a point.

    Again, I don't know any other solution other than to never clear out the original mesh. It can be replaced, etc., but do not clear it out to "none" otherwise the bones get cleared out also.
     
    Deleted User likes this.
  7. Deleted User

    Deleted User

    Guest

    Using the information from @Garganturod I was able to make a simple script to be able to populate a bone array for a rig. I have a really hacky example, but I think with some love it could work for others!


    Code (CSharp):
    1. // Take the mesh you'd like to replace (either as a local variable or class variable)
    2. var toReplace = meshToReplace[0];
    3.  
    4. // Create an instance of what you'd like to replace the existing mesh with
    5. var instance = GameObject.Instantiate(availableArmor[0], toReplace.transform.position, toReplace.transform.rotation);
    6.  
    7. // Get the SkinnedMeshRenderer component
    8. var instanceSkinnedMesh = instance.GetComponent<SkinnedMeshRenderer>();
    9.  
    10. // Set the root bone (in this case; I have a class variable: public Transform rootBone; which I use to set the rig I need to populate from)
    11. instanceSkinnedMesh.rootBone = rootBone;
    12.  
    13. // Use a helper method, in the following code block, to populate the bone array for the instance's skinned mesh renderer
    14. SkinnedMeshBoneArrayPopulator.populateBoneArray(ref instanceSkinnedMesh);
    15.          
    16. // Either hide the base mesh if you will need it for something else or you can destroy it
    17. meshToReplace[0].SetActive(false);
    18.  
    19. // Set the transform parent of the instanced GameObject to the transform you have this component attached to
    20. instance.transform.SetParent(this.transform);
    And then here's my static helper, which is pretty basic & crude but should work!


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class SkinnedMeshBoneArrayPopulator {
    5.     public static void populateBoneArray(ref SkinnedMeshRenderer skinnedMesh) {
    6.         if (skinnedMesh.rootBone == null) {
    7.             throw new System.Exception(
    8.                 "Missing root bone; please ensure that the root bone is set before attempting"
    9.                 + " to populate the bone array for the skinned mesh."
    10.             );
    11.         }
    12.  
    13.         var boneArray = new List<Transform>();
    14.         var currentBone = skinnedMesh.rootBone;
    15.         recursiveAdd(currentBone, ref boneArray);
    16.  
    17.         skinnedMesh.bones = boneArray.ToArray();
    18.     }
    19.  
    20.     private static void recursiveAdd(Transform currentBone, ref List<Transform> boneArray) {
    21.         boneArray.Add(currentBone);
    22.         for (var i = 0; i < currentBone.childCount; i++) {
    23.             recursiveAdd(currentBone.GetChild(i), ref boneArray);
    24.         }
    25.     }
    26. }
    Thank you to everyone in this thread; I thought I was going insane when I first noticed the problem :)
     
    RSolids likes this.
  8. v01k

    v01k

    Joined:
    Sep 6, 2015
    Posts:
    2
    I had the same problem today. I wanted to copy/paste skinned mesh renderer center/extents and ran into model dissapearence. This happened when I copied smr component from one object to another. It looks like that bone references connected to the prefab where smr is instantiated. In my case I was able to discard this changes via git.
    upload_2022-3-28_9-55-6.png
     
  9. pointcache

    pointcache

    Joined:
    Sep 22, 2012
    Posts:
    579
    How is this still a thing, can anyone from unity shed a light on this issue?
    Anyone has a link to issue tracker on this one?
     
    ChrisP999 and Weidz_ like this.
  10. Weidz_

    Weidz_

    Joined:
    Feb 15, 2018
    Posts:
    41
    Cam across this issue today aswell, sent a bug report
     
  11. JVleeshouwer

    JVleeshouwer

    Joined:
    May 19, 2019
    Posts:
    1
    Ran into the same issue. Strangely enough calling ResetBounds() on the mesh (after updating the sharedMesh proprty) somehow fixed the issue for me. Although I am not yet sure what the side-effects will be...
     
  12. Explorasaurus

    Explorasaurus

    Joined:
    Jun 7, 2013
    Posts:
    2
    For anyone else having this issue, the problem is in the SkinnedMeshRenderer component bones transform array. This is not automatically populated when updating the root bone. You can fix it via a quick script that extracts the bones from the new root and updates the array-- just have to add a bit of code to do it in the correct order since oftentimes it is jumbled between meshes.

    I created an editor tool that would do this for me so I could quickly reassign meshes in the heirachy but it is easily modifiable to work at runtime (just swap Selection.GameObject with the mesh your are trying to reference). I call this after reassigning the root bone in scene. and it swaps it over.

    Hope this helps!
     

    Attached Files:

  13. ludwu

    ludwu

    Joined:
    Feb 3, 2018
    Posts:
    1
    I myself struggle with all this. Didn't find an answer for now, but you can repopulate in an easier way :

    Code (CSharp):
    1. skinMesh.bones = root.GetComponentsInChildren<Transform>();
    2.  
    3. // Where skinmesh is the one you want to repopulate and root the transform that contain the bones
    4.