0
\$\begingroup\$

I'm trying to create an automation for our asset pipeline where an imported mesh will automatically be processed into prefabs for each instanced submesh. For example, when I import this FBX PipelineAsssets.fbx_Scene it creates the directory PipelineAssets.fbx_scene_PREFABS and then fills it with prefabs of each unique instanced submesh from that fbx.

enter image description here enter image description here

The code I have so far accomplishes this task with one major flaw, the MeshFilter components on each of these prefabs are empty.

enter image description here

Upon inspecting the documentation, I've discovered the problem with my simple attempt at achieving this goal.

Any references to game objects or meshes will become invalid after the import has been completed. Thus it is not possible to create a new Prefab in a different file from OnPostprocessModel that references meshes in the imported fbx file. https://docs.unity3d.com/ScriptReference/AssetPostprocessor.OnPostprocessModel.html

Nevertheless, I'd still like to accomplish my goal of automatically making prefabs on import of models. While the documentation declares it's not possible within the OnPostprocessModel method, maybe there's somewhere else in the AssetPostProcessing class where it is possible? Is there maybe another place in the asset importing process that I can hook in to do this?

How can I create prefabs of imported assets during the asset importing process?

For completeness and to help folks investigating this question out, I'm including my source code below.

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

public class FBXPrefabImport : AssetPostprocessor
{

    private static string MakeValidFileName(string name)
    {
        string invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
        string invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);

        return System.Text.RegularExpressions.Regex.Replace(name, invalidRegStr, "_");
    }

    private void OnPostprocessModel(GameObject gameObject)
    {
        String path = Path.Combine(Path.GetDirectoryName(assetPath),MakeValidFileName(gameObject.name) +  "_PREFABS");
        DirectoryInfo info =  System.IO.Directory.CreateDirectory(path);

        Stack<GameObject> stack = new Stack<GameObject>();
        Dictionary<Mesh, GameObject> prefabDict = new Dictionary<Mesh, GameObject>();
        stack.Push(gameObject);

        while(stack.Count > 0)
        {
            GameObject stackObject = stack.Pop();
            foreach (Transform childTransform in stackObject.transform)
            {
                MeshFilter meshfilter = childTransform.gameObject.GetComponent<MeshFilter>();
                if (meshfilter != null)
                {
                    if(!prefabDict.ContainsKey(meshfilter.sharedMesh))
                    {
                        prefabDict[meshfilter.sharedMesh] = childTransform.gameObject;
                    } 
                }
                stack.Push(childTransform.gameObject);
            }
        }
        foreach(Mesh mesh in prefabDict.Keys)
        {
            GameObject prefabObject = prefabDict[mesh];
            PrefabUtility.SaveAsPrefabAsset(prefabObject, Path.Combine(info.FullName , MakeValidFileName(prefabObject.name) + ".prefab"));
        }
    }
}

\$\endgroup\$
3
  • 2
    \$\begingroup\$ There may be a neater way to do this, but one approach might be to use the EditorCoroutines package to kick off a coroutine that waits until after an AssetDatabase.Refresh and then creates the prefabs. \$\endgroup\$
    – DMGregory
    Mar 11 at 10:43
  • \$\begingroup\$ I'm going to investigate this and see if it's at least workable. \$\endgroup\$
    – Echoleta
    Mar 12 at 17:51
  • 1
    \$\begingroup\$ I have found potentially another option in this thread on the unity forums that I'll pursue further. forum.unity.com/threads/… In it, EditorCoroutines are mentioned as a solution, but the discussion focuses on the more promising solution of using OnPostprocessAllAssets() in combination with asset caching things I have yet to understand fully. \$\endgroup\$
    – Echoleta
    Mar 16 at 1:50

0

You must log in to answer this question.

Browse other questions tagged .