Creating a prefab 'on fly'

Hello,

First of all, i’m new to unity so sorry if my questions sounds dull.

I am having existing asset files that I would like to import into unity. Those assets are some proprietary formats and I made a C# custom reader to load them into unity mesh.

What i am trying to do is to obtain a result similar to the one you get when importing an asset such as collada file, meaning: one container rendering the whole mesh and upon expanding that container all its individual meshes, skeleton, animations.

For that prupose i tried to create an asset and assigned my custom loaded mesh into it, using either a gameobject or a prefab as container. The result obtained is that I clearly have a container showing each individual mesh when expanding it, but the container is displayed as a cube and not using a thumbnail of the sum of its meshes and even more annoying, when i drag the container onto the scene, it does not create a hierarchy of my mesh but only create an “empty” node.

I would appreciate any help.

My current code is shown bellow:

  [MenuItem ("Assets/Load My Custom asset")]
    static void LoadCustomAsset () 
    {
                string assetPath = AssetDatabase.GenerateUniqueAssetPath("Assets/ImportedAsset.prefab");
	        Object prefab = PrefabUtility.CreateEmptyPrefab(assetPath);
		
	        Dictionary<string,string> meshMap = new Dictionary<string, string>();
		meshMap .Add("Face", @"c:\...\0000000000.lgo");
		meshMap .Add("Hair", @"c:\...\0000000001.lgo");
		meshMap .Add("Body", @"c:\...\0000000002.lgo");
		meshMap .Add("Hands", @"c:\...\0000000003.lgo");
		meshMap .Add("Feet", @"c:\...\0000000004.lgo");
		foreach (string entry in meshMap.Keys)
		{
			GameObject go = new GameObject(entry);
			MeshFilter meshFilter = (MeshFilter) go.AddComponent("MeshFilter");
			go.AddComponent("SkinnedMeshRenderer");
			
			CustomMeshLoader customMeshLoader = new CustomMeshLoader ();
			Mesh mesh = customMeshLoader.Load(meshMap[entry]);
                        mesh.name = entry;
			meshFilter.mesh = mesh;	
			
			AssetDatabase.AddObjectToAsset(mesh, assetPath);
		}
		AssetDatabase.SaveAssets();
    }

I replied to a similar question in another thread here http://forum.unity3d.com/threads/159950-Create-Prefab-from-some-gameobects but since you’ve got most of what’s covered in that post down already one thing I noted from your script is that while you create the prefab using CreateEmptyPrefab which creates a blank empty prefab in the assetPath I don’t see you actually connect it to your game object hierarchy using PrefabUtility.ReplacePrefab like it shows in the docs example at Unity - Scripting API: PrefabUtility.CreateEmptyPrefab

Thanks for your help. I had somehow already tried, but trying again I added a root node and I ended up with something way better.
Now, my prefab is displaying the whole model and upon expanding it, I can see in it all my meshes as well as all their associated gameobjects.

That led me to few other questions:

  • When I first tried, I saw that the prefab was added to the scene as well. I then removed it from scene by deleting the root GO. my question is, does it remove all the tree nicely or i have to parse the tree to remove each node ?
  • Is there a way to avoid having both mesh and go in the resulting prefab, like somehow merging GO and mesh, or do i have to stick to “duplicated” data ? I tried not adding the mesh individually to the asset but then my GO are just empty =P
  • When i drag a ‘part mesh’ from my prefab asset to scene, then it adds on the scene the dragged mesh, but when i drag out the corresponding go (ie the go holding my hand mesh) inspite of adding the hand go on the scene, it is adding the whole prefab but naming it ‘hands’. Is that pointing to an issue in my script or is that somehow a normal behavior ?

Anyway thanks a lot.

My script in case someone else want to do something similar:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class CustomAsset : MonoBehaviour {
 [MenuItem ("Assets/Load My Custom asset")]
    static void LoadCustomAsset () 
    {
        string assetPath = AssetDatabase.GenerateUniqueAssetPath("Assets/ImportedAsset.prefab");
        Object prefab = PrefabUtility.CreateEmptyPrefab(assetPath);
        GameObject root = new GameObject("Character");

        Dictionary<string,string> meshMap = new Dictionary<string, string>();
        meshMap.Add("Face", @"E:\Matt\Unity\test2\REF\data\0000000000.lgo");
        meshMap.Add("Hair", @"E:\Matt\Unity\test2\REF\data\0000000001.lgo");
        meshMap.Add("Body", @"E:\Matt\Unity\test2\REF\data\0000000002.lgo");
        meshMap.Add("Hands", @"E:\Matt\Unity\test2\REF\data\0000000003.lgo");
        meshMap.Add("Feet", @"E:\Matt\Unity\test2\REF\data\0000000004.lgo");
        

		
		foreach (string entry in meshMap.Keys)
        {
           GameObject go = new GameObject(entry);
           MeshFilter meshFilter = (MeshFilter) go.AddComponent("MeshFilter");
           MeshRenderer meshRenderer = (MeshRenderer) go.AddComponent("MeshRenderer");
           
           CustomMeshLoader customMeshLoader = new CustomMeshLoader ();
           Mesh mesh = customMeshLoader.Load(meshMap[entry]);
           mesh.name = entry;
           meshFilter.mesh = mesh; 
           
		   go.transform.parent = root.transform; 
			
		   AssetDatabase.AddObjectToAsset(mesh, assetPath);
        }
		PrefabUtility.ReplacePrefab(root, prefab, ReplacePrefabOptions.ConnectToPrefab);
		AssetDatabase.SaveAssets();
		GameObject.DestroyImmediate(root);

    }
}

You seem to be working under the impression that prefabs actually store the assets in them and this is not the case. A prefab is a bundle of data that is turned into game objects. Once you’ve dragged a prefab into the inspector you end up with objects that you can move around / copy / destroy what ever you want to do basically. Keeping this in mind I’ll try to answer your questions.

#1 : No if you delete an object from the hierarchy all children references will be deleted as well so there shouldn’t be any clean up needed as far as the hierarchy goes. Deleting objects in this way does not affect the underlying assets, it’s not actually going to delete files off your hard drive.

#2 : This is an apples / oranges kind of question. Meshes and GameObjects are not the same thing and cannot be merged. A game object stores references to assets, a mesh is a collection of 3d data so yes you do need to have a mesh reference in the game object if you expect the mesh to be visible.

#3: I’m not quite sure what you mean so I’ll post an example:
You have a prefab it contains references to two assets one the parent of the other.
A body mesh (with texture+renderer+positional data)
A hand mesh (with texture+renderer+positional data)

You drag this into the inspector which creates a new game object hierarchy from the metadata inside the prefab.
Body->
Hand

Now you drag that hand from the hierarchy and stick it on another object. At this point unity will likely prompt you with “You are breaking the prefab” which means… “By moving this transform I can no longer treat it as a collection of stuff called a prefab, can we treat it like a standard game object instead?” You say yes and end up with a hand in the the other hierarchy. Which would be the equivalent to setting up the hand mesh manually with texture and such by dragging them from the project folders.

Ok, i though that somehow dragging a game object from half-way of the hierarchy would have pulled only the sub tree and not the whole tree but i’m fine with it =)

Thanks again.