What is the correct way to use AssetPostprocessor?

In my scene I have a gameObject with a MeshLoadingTesting script attached. When I originally tried to use it I get the (non error) message “Can’t add component ‘Rigidbody’ to prefabNameHere because the game object is a generated prefab and can only be modified through an AssetPostprocessor.” followed by a similar message about the MeshCollider, which itself was followed by a NullRefrenceException. So I looked up the documentation on the AssetPostprocessor class, and while it wasn’t as informative as I had hoped, it did explain its purpose and what the methods did (mostly). So I created a new script called MeshPostProcessing to inherit from AssetPostprocessor as the documentation example called for.

Unfortunately this hasn’t worked out as I had hoped. I still get the same message and error so I’m not sure what’s happening. I tried defining the MeshPostProcessing class inside the MeshLoadingTesting class, but that still gave me the same result.

public class MeshPostProcessing : AssetPostprocessor {

    void OnPostprocessModel(GameObject g){

        g.AddComponent<Rigidbody> ();
        g.AddComponent<MeshCollider> ();
    }
}

//MeshLoadingTesting is located in its own .cs file, btw
public class MeshLoadingTesting : MonoBehaviour {

    public string FilePath;
    public string FBXName,   AnimatorName, ColliderName;

    void Start () {
         GameObject go = AssetDatabase.LoadAssetAtPath<GameObject> (FilePath + FBXName + ".fbx");

        Animator anim = go.GetComponent<Animator> ();//AddComponent<Animator> ();

        Debug.Log (FilePath + AnimatorName + ".controller");

        anim.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController> (FilePath + AnimatorName + ".controller");

        Rigidbody rb = go.AddComponent<Rigidbody> ();

        MeshCollider mc = go.AddComponent<MeshCollider> ();

        mc.sharedMesh = AssetDatabase.LoadAssetAtPath<GameObject> (ColliderName + ".fbx").GetComponent<Mesh> ();
    }
}

AssetPostProcessor is a class that works directly on the Asset files as you import them in to unity or move them around. They are Editor Scripting classes and are not availible when you build the project. AsserPostProcessor scripts should be in their own files inside the Editor folder. and they are typically used to automatically set up imported/moved files.

For example:

  • All png files imported/moved into a specific folder will be turned into a sprite sheet of 8x8 sprites.
  • make sure that filetypes are only allowed in specific folder paths to keep the project space maintained
  • fbx animations imported into the project automatically configure their settings based on a naming convention you’ve set up and their animation clip names prefixed based on the file path it was imported into
  • imported static models can have their verts restitched so that they become one mesh and reduce draw calls.

they’re not really used at runtime in the game, but more to help speed up workflow in the Editor itself

1 Like

Thanks for the info. I just now realized that I had forgotten to remove the two AddComponents from the MeshLoadingTesting class and fix the file path of the collider, much to my embarrassment. Now the code is looking much better, I got get those errors, but it now tells me that GameObject go has no mesh collider, even though I instructed it to add one in the MeshPostProcessing class.

Okay, I’ve tried both creating a folder named “Editor” and placing the scrip in there, and placing the script in the same folder as the objects to be imported. Neither method works.

Which script are you putting where and which are you using to do which? MeshLoadingTesting is not a proper script as it will break the moment you try to build with it (it has UnityEditor classes in it). plus from what you’ve posted its still doing code that should only be done in OnPostProcessModel. Can you show what code you have now?

OnPostProcessModel() only runs the moment you import a model. If you wrote the code after you imported you’ll need to remove then reimport the model again. Also this code will run on EVERY model you import so be careful. Try limiting it to work only on files with specific names or extensions or in specific folders.

I first placed the MeshPostProcessing script in a new folder that I named Editor in the Resources folder (I might have misunderstood your comment), then I tried placing it in the same folder that contained the .fbx asset that I wanted to load, but no luck. I’m not exactly sure what you mean by the moment a model is imported. Do you mean the moment when Unity Editor detects an .fbx file, or when I hit the play button? I took you advice about limiting it to only models with a certain name, so that should help in the future. However, I still get the error. Here’s code, it hasn’t changed much aside from a few minor additions:

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

public class MeshLoadingTesting : MonoBehaviour {

    public string FilePath;
    public string FBXName, AnimatorName, ColliderName;

    void Start () {
        GameObject go = AssetDatabase.LoadAssetAtPath<GameObject> (FilePath + FBXName + ".fbx");

        Animator anim = go.GetComponent<Animator> ();

        Debug.Log (FilePath + AnimatorName + ".controller");

        anim.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController> (FilePath + AnimatorName + ".controller");

        BetterAnimationControl cont = go.GetComponent<BetterAnimationControl> ();

        if (!cont) {
            Debug.Log ("The improved animation controler (basicly just a MonoBehaviour script that dosent do anything) was not grabbed");
        }

        MeshCollider mc = go.GetComponent<MeshCollider> ();

        if (!mc) {
            Debug.Log ("The mesh collider was not grabbed.");
        }

        Rigidbody rb = go.GetComponent<Rigidbody> ();

        if (!rb) {
            Debug.Log ("The rigid body was not grabbed.");
        }

        mc.sharedMesh = AssetDatabase.LoadAssetAtPath<GameObject> (FilePath + ColliderName + ".fbx").GetComponent< MeshFilter> ().sharedMesh;
    }
}

Here’s what I have for MeshPostProcessing. I tried using OnPreprocessModel, but that only lets me set ModelImporter.addCollider to true, and even that dosen’t let me add a collider to the gameObject. Unfortunately there’s no way to access the game object itself in the OnPreprocessModel, so that prevents me from adding the rigid body and mesh collider there.

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

public class MeshPostProcessing : AssetPostprocessor {

    void OnPreprocessModel(){

        ModelImporter modImport = assetImporter as ModelImporter;

        if (modImport.name.Contains ("Test")) {
            modImport.addCollider = true;
        }
    }

    void OnPostprocessModel(GameObject g){

        if (g.name.EndsWith ("Test")) {

            g.AddComponent<Rigidbody> ();
            g.AddComponent<MeshCollider> ();
            g.AddComponent<BetterAnimationControl> ();
        }
    }
}

The reason it didn’t include the code for BetterAnimationControl is that it’s just a monoBehavour script that does nothing. I only used it to test if I could add a custom script.