Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to override Model importer inspector.

Discussion in 'Scripting' started by Cyber-Dog, Sep 18, 2020.

  1. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    I'm not sure if it is possible. But I really hope so.

    Basically I want to add a checkbox to the inspector, that will determine whether or not to execute something on import.



    I know I can write a script for OnPostprocessModel, but that would happen for every model I import. Which I don't want, just ones I specify.

    ...

    My issue is, no matter how I try, I can't get a perfect import from blender to Unity where rotation and scale of parent/child objects or default. No matter the fact the I have corrected it in a blender. Maybe a blender/unity version issue. One option will have an ok scale, but bad rotation; the other will have an ok rotation but bad scale. Different models respond differently to export settings. I have used custom exporter addons. Blender is hell for this!

    I wrote a custom script, but the problem is every time I change the asset's import settings, it gets reset.
    Plus having my project on GitHub will also cause issues as the Library folder gets ignored.
    Code (CSharp):
    1. public class MeshScaleCorrector : MonoBehaviour
    2. {
    3.     [MenuItem("Mesh/Set Scale to 1")]
    4.     static void SetScale()
    5.     {
    6.         Object selecteObject = Selection.activeObject;
    7.         string objectPath = AssetDatabase.GetAssetPath(selecteObject);
    8.  
    9.         if (!File.Exists(objectPath)){
    10.             Debug.Log($"Cannot find asset path for: {selecteObject.name}");
    11.             return;
    12.         }
    13.  
    14.         if (selecteObject.GetType() != typeof(GameObject)){
    15.             Debug.Log($"{selecteObject.name} is not a type of GameObject");
    16.             return;
    17.         }
    18.  
    19.         ScaleObject(((GameObject)selecteObject).transform);
    20.     }
    21.  
    22.     private static void ScaleObject(Transform obj)
    23.     {
    24.         obj.localScale = Vector3.one;
    25.         foreach (Transform child in obj){
    26.             ScaleObject(child);
    27.         }
    28.     }
    29. }
    I just want a way I can apply the above method, but only to objects of my choosing. Creating a scriptable object, then storing a reference seems like a possibility. But that is a bit hacky!
     
  2. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    I realised I can add a custom editor to the window... But is it possible to keep unity's custom editor view, and just add something at the end?

    Code (CSharp):
    1. [CustomEditor(typeof(ModelImporter))]
    2. public class ModelImporterEditor : Editor
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Yeah, there's a "draw default inspector" call you can make... check the APIs for it.
     
    Cyber-Dog likes this.
  4. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Yea, there is. But that will remove any dynamic customizations setup by unity's custom editor. That's why I was wondering if it's possible to merge.

    I don't think it is though, just thought it would be worth asking the questing. I think the only options is to have a reference to the ones I want in a scriptable object, then do a check when overriding the import function.

    Or stop using Blender haha
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    I think it is... you either do your custom stuff, then call the draw default, or vice-versa... depending on how you want it to stack.

    Perhaps I am not fully understanding what you are trying to do?

    Perhaps I'm misunderstanding what you mean here:

    "But that will remove any dynamic customizations setup by unity's custom editor."
     
    Last edited: Sep 19, 2020
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    For instance, in my Datasack project I have a custom inspector window that looks like:

    stuff.png

    This is the class that runs it:

    https://github.com/kurtdekker/datas...cks/Assets/Datasack/Core/DatasackInspector.cs

    .. just a few excerpted lines:

    Code (csharp):
    1.         public override void OnInspectorGUI()
    2.         {
    3.             Datasack ds = (Datasack)target;
    4.  
    5.             DrawDefaultInspector();
    6.  
    7.             EditorGUILayout.BeginVertical();
    8.  
    9.             if (GUILayout.Button( "CODEGEN"))
    10.             {
     
  7. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Hey,


    So I meant unity already has a CustomEditor for the ModelImporter class.


    So making a new custom inspector, and drawing default would result in the below.
    Losing everything unity has done, which is not really worth it in the long run.

    If only Unity's ModelImporterEditor class was accessible, I could inherit and override on it, then call base drawings. Allowing me to put a checkbox at the very top before their editor work is drawn. I did extensive googling, looks like it was available at one point, but has long been removed.
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Ah, I now understand... I hadn't tried it with an FBX importer importer override.

    That is a bummer! Thank you for setting me straight.
     
    Cyber-Dog likes this.
  9. Whatever560

    Whatever560

    Joined:
    Jan 5, 2016
    Posts:
    405
    I'm trying to isolate the AnimationClip Editor from the model importer but I can't manage to do so as well : /

    It would be great if individual parts of the importer (Animation Events, Curves, Textures, etc) where available
     
  10. Tristan-Moore

    Tristan-Moore

    Joined:
    Aug 22, 2014
    Posts:
    18
    I'm making an LOD tool at the moment and have had to do stuff like this a lot; it's totally doable and pretty easy. You just need to create and draw a separate editor, rather than extending a base class or drawing the default inspector.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System;
    4.  
    5. [CustomEditor(typeof(ModelImporter))]
    6. public class ModelImporterEditor : Editor
    7. {
    8.     Editor defaultEditor;
    9.  
    10.     void OnEnable()
    11.     {
    12.         defaultEditor = Editor.CreateEditor(targets, Type.GetType("UnityEditor.ModelImporterEditor, UnityEditor"));
    13.     }
    14.  
    15.     void OnDisable()
    16.     {
    17.         DestroyImmediate(defaultEditor);
    18.     }
    19.  
    20.     public override void OnInspectorGUI()
    21.     {
    22.         serializedObject.Update();
    23.  
    24.         defaultEditor.OnInspectorGUI();
    25.  
    26.         if(GUILayout.Button("CREATE LODs"))
    27.         {
    28.             //Do the LOD creation
    29.         }
    30.  
    31.         serializedObject.ApplyModifiedProperties();
    32.     }
    33. }
    Unity's
    DrawDefaultInspector
    simply draws Unity's basic configuration for an editor and its serialized fields, and you can't extend your class from the original editor because it's not directly accessible in your codebase. It still exists, though, so you can access it by using
    Type.GetType
    .

    Another useful application for this type of approach is if you're assigning a scriptable object to a public field. You can actually create and draw the inspector for that object inside the inspector you're working with, which offsets the main usability disadvantage that scriptable objects can introduce.

    Most of the classes have a pretty intuitive naming convention that corresponds to "ClassNameEditor," but it can also be helpful to look up a few resources, like this Unity C# Reference project on GitHub.
     
  11. Tristan-Moore

    Tristan-Moore

    Joined:
    Aug 22, 2014
    Posts:
    18
    There's also ways you can directly access certain internal classes by using Assemblies to place your class inside of an existing assembly; I've done this to directly access some of the internal material editor code in the URP/HDRP. I haven't tried it in this case, but there's definitely fancier options if you want to really dig into it.
     
  12. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    I tried this, but when inheriting from Editor I don't get the Apply and Revert buttons with that method (defaultEditor.OnInspectorGUI() does not seem to draw them).

    If I inherit from AssetImporterEditor instead, I can add the Apply Revert buttons using ApplyRevertGUI(); but I'm getting a lot of errors then about

    Code (CSharp):
    1. The previous instance of UnityEditor.ModelImporterEditor has not been disposed correctly. Make sure you are calling base.OnDisable() in your AssetImporterEditor implementation.
    2. UnityEditor.Editor:CreateEditor (UnityEngine.Object[],System.Type)
    Did you find a clean solution to this?
     
    Last edited: Aug 27, 2021
  13. Tristan-Moore

    Tristan-Moore

    Joined:
    Aug 22, 2014
    Posts:
    18
    EDIT: Noted that this does produce the same errors about disposing of the editor that you mentioned, despite displaying correctly. I have been investigating to see if I can get this to work with both reflection and non-reflection methods, but I also think I need to read up on what would cause an editor to not be properly disposed when all signs point to it working as intended.

    Hey, I actually noticed this after I posted but didn't find a solution for it and forgot to check back on this page. Your implementation of AssetImporterEditor actually allowed me to find the solution though, so thank you for that!

    Here's what I did:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System;
    4. using UnityEditor.Experimental.AssetImporters;
    5.  
    6.  
    7. [CustomEditor(typeof(ModelImporter))]
    8. public class ModelImporterEditor : AssetImporterEditor
    9. {
    10.     Editor defaultEditor;
    11.  
    12.     public override void OnEnable()
    13.     {
    14.         defaultEditor = Editor.CreateEditor(targets, Type.GetType("UnityEditor.ModelImporterEditor, UnityEditor"));
    15.  
    16.         base.OnEnable();
    17.     }
    18.  
    19.     public override void OnDisable()
    20.     {
    21.         DestroyImmediate(defaultEditor);
    22.         base.OnDisable();
    23.     }
    24.  
    25.     public override void OnInspectorGUI()
    26.     {
    27.         serializedObject.Update();
    28.  
    29.         defaultEditor.OnInspectorGUI();
    30.  
    31.         ApplyRevertGUI();
    32.  
    33.         if (GUILayout.Button("CREATE LODs"))
    34.         {
    35.             //Do the LOD creation
    36.         }
    37.  
    38.         serializedObject.ApplyModifiedProperties();
    39.     }
    40. }
    I just implemented this, so I'm not sure if there are any unexpected issues with it that could crop up, but it does seem like it does what we were both intending.
     
    Last edited: Dec 5, 2021
  14. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    289
    This still works (not) but it looks like defaultEditor.OnInspectorGUI and ApplyRevertGUI both draw Asset PostProcessor Info lists.
    Does anyone know how to draw this only once?

    Apart from that:
    The previous instance of ModelImporterEditor has not been disposed correctly. Make sure you are calling base.OnDisable() in your AssetImporterEditor implementation.
    UnityEditor.AssetImporters.AssetImporterEditor:InternalSetTargets (UnityEngine.Object[])

    And it no longer checks if properties have been changed when deselecting the asset :-/
     

    Attached Files:

    Last edited: Jan 20, 2022
  15. Blackfire-Studio

    Blackfire-Studio

    Joined:
    Dec 17, 2013
    Posts:
    178
    +1 for @fleity
    Is there a way to make it work again. Or maybe another approach would be better.
     
  16. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    141
    fleity likes this.