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

ModelImporter: how to modify fileScale in Unity?

Discussion in 'Scripting' started by FeastSC2, May 7, 2020.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    Depending on at which scale a model file is exported from a 3d package, Unity might have its child transforms's scale values not equal to 1.

    This can cause issues.
    Toying with Unity's ModelImporter settings like Scale Factor or Convert Units won't change the scale of the children of the mesh.
    The problem is that the children of the model have an incorrect scale value due to the FBX's fileScale. (this fileScale has been set the moment you create the FBX).

    (As you can see in the screenshot, these transform children have 0.01 scale, but they should have a scale of 1. Because this was their value in the 3d package.
    This means that during the FBX export, that scale was modified because the export measurement units picked were not accurate)
    https://i.imgur.com/seaWBqL.png

    This problem can be fixed by going in a 3d package and recreating a new FBX file with the proper fileScale.
    However, this is a process that takes time and I would like to modify the fileScale directly from Unity.

    How can I set the fileScale of a ModelImporter directly in Unity?
     
    Last edited: May 7, 2020
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
    I believe you are using the wrong thing... here's what I used, and I just verified it worked: one model imported at default scale and one imported at scale 22, as this code below does:

    Code (csharp):
    1. using UnityEditor;
    2.  
    3. public class ModelCustomImportSteps : AssetPostprocessor
    4. {
    5.     void OnPreprocessModel()
    6.     {
    7.         if (assetPath.Contains("@"))  // @-sign in the name triggers this step
    8.         {
    9.             ModelImporter modelImporter = assetImporter as ModelImporter;
    10.             modelImporter.useFileScale = false;
    11.             modelImporter.globalScale = 22.0f;
    12.         }
    13.     }
    14. }
    You could even base it on the location of the model, such as a particular folder.
     
  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    No we are using the same thing, it's just that what you're proposing does not fix my problem.
    My gameObject has the right size in the scene.

    It's something that I don't quite understand but when I pose the model in the scene its scale transform values are not 1.
    If I do what you're saying it simply changes the size of my object but the scale values of the transform remain the same.

    When I set the modelImporter to useFileScale = false or true, no changes occur. I don't know if it's a bug or anything, but it's always the same.

    I will make a video showing the problem.
     
  6. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    @Kurt-Dekker Here's a video showing the problem:


    This does not only occur on the assets shown here I have this all over my project.

    The fix to the problem like I said above, is to reimport the FBX from a 3d Package with the right units measurement because this will change the ModelImporter.fileScale value. This is why I was asking "How can I change the fileScale in Unity".
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
    Ah, I see what you mean. The scale I posted above actually transforms the internal verts.

    What you want to modify the Transform component of the GameObject that is produced on disk is this:

    Code (csharp):
    1.  
    2.     void OnPostprocessModel( GameObject go)
    3.     {
    4.         go.transform.localScale = Vector3.one;
    5.     }
    6.  
    You can use that to drive anything in the model, AFTER it gets sucked in from the original asset file.

    Make sure your code finishes compiling, then reimport the model. Code changes will NOT trigger a reimport, obviously.

    Also, the above has to go in a class like my first code snippet.
     
    FeastSC2 likes this.
  8. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    Ok this does the job. That's already great :)

    However, this problem occurs with more complex things as well: like characters and joints.
    It seems to me setting the localScale to a new value is dangerous.
    And especially doing postprocess on all models is dangerous.

    I think I should make an EditorWindow to scale uniformly all the gameobjects created by a ModelImporter by a same amount. I'll post it here once I made it. Thanks @Kurt-Dekker
     
  9. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    Mhh... Actually as soon as I reimport an asset the localScale is being overwritten anyway...

    here's what I was scripting up.
    I want to refrain from using AssetPostProcessing because I would rather do it per prop.

    If I reimport the gameObject's local scale will automatically be set to the default.

    @Kurt-Dekker any ideas?

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. public class ModelImporterEditor : EditorWindow
    6. {
    7.     [MenuItem("JeyTools/Model Importer/Editor")]
    8.     public static void Init()
    9.     {
    10.         var instance = (ModelImporterEditor)GetWindow(typeof(ModelImporterEditor), true, "Model Importer Editor");
    11.         instance.Show();
    12.     }
    13.  
    14.     private float MultiplierValue = 1f;
    15.     private bool KeepGlobalScale = true;
    16.     void OnGUI()
    17.     {
    18.         GUILayout.Label("Select in the project window the ModelImporters you wish to edit");
    19.  
    20.         KeepGlobalScale = EditorGUILayout.Toggle("Keep Global Scale", KeepGlobalScale);
    21.         MultiplierValue = EditorGUILayout.FloatField("Scale Multiplier Value", MultiplierValue);
    22.  
    23.         if (GUILayout.Button("Edit Models and Reimport"))
    24.         {
    25.             var modelImporters = LoadAssetImportersFromSelection();
    26.  
    27.             foreach (var mi in modelImporters)
    28.             {
    29. //                Undo.RegisterCompleteObjectUndo(mi, "ModelImporter Scale edit");
    30.  
    31.                 bool foundSomething = false;
    32.  
    33.                 var objects = AssetDatabase.LoadAllAssetsAtPath(mi.assetPath);
    34.  
    35.                 foreach (var obj in objects)
    36.                 {
    37.                     if (obj is GameObject go)
    38.                     {
    39.                         Debug.Log($"found transform {go.name}");
    40.                         foundSomething = true;
    41.                         go.transform.localScale *= MultiplierValue;
    42.                     }
    43.                 }
    44.  
    45.                 if (foundSomething)
    46.                 {
    47.                     mi.globalScale /= MultiplierValue;
    48.                 }
    49.  
    50.                 mi.SaveAndReimport();
    51.             }
    52.         }
    53.     }
    54.  
    55.     public static List<ModelImporter> LoadAssetImportersFromSelection()
    56.     {
    57.         var modelImporters = new List<ModelImporter>();
    58.         var guids = Selection.assetGUIDs;
    59.         foreach (var g in guids)
    60.         {
    61.             if (g != null)
    62.             {
    63.                 var assetPath = AssetDatabase.GUIDToAssetPath(g);
    64.                 Debug.Log($"assetPath: {assetPath}");
    65.  
    66.                 var assetImporter = AssetImporter.GetAtPath(assetPath);
    67.  
    68.                 if (assetImporter is ModelImporter model)
    69.                 {
    70.                     modelImporters.Add(model);
    71.                 }
    72.             }
    73.         }
    74.         return modelImporters;
    75.     }
    76. }
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
    Well I think at the end of the day, if your art data is inconsistent, it might be best to fix that first. Any other gross bandaid like this is going to be inherently limited to the two applications identified above: setting import scale and then post-changing the scale. Anything else will by necessity embed knowledge about the art data defects into some piece of import code. Being an engineer that might SEEM better, but it is going to be a scab just waiting to be knocked off in the future, and causing silent weird problems. Best fix the art!
     
  11. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    @Kurt-Dekker
    I thought about that but what I'm doing is essentially the same concept as modifying the globalScale.
    And since Unity allows to modify that, it doesn't make sense that I shouldn't be able to do modify the fileScale in Unity as well. In fact, I saw this was possible in early Unity versions (before Unity 5).

    And the nightmare it would be to go in assets from the asset store, and import/export everything. If they make an update or something I get to do the same thing again...

    I was close to find a solid solution thanks to Unity's userData in the ModelImporter.
    It works well for any meshes. However, it does not re-scale animations properly.
    Certainly because the fileScale is being used for that and not the globalScale :/

    I don't know that it's possible to do with Unity...
    I'm surprised this issue has not been adressed more by the community.
    I guess the 2nd best option is to batch edit the scales the FBX/Obj files.
     
  12. wetcircuit

    wetcircuit

    Joined:
    Jul 17, 2012
    Posts:
    1,409
    Kurt-Dekker likes this.
  13. MartinBarrette

    MartinBarrette

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    26
    The Scale Factor applies to all elements content but keeps local scale untouched.
    Which issues are you trying to avoid with non 1 values scale?
     
  14. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    974
    1) Mostly I was trying to avoid this issue. However the devs mentioned they might fix this in a later version.

    2) The rest is just me enjoying a clean hierarchy that doesn't have scales out of whack:
    It's to avoid dragging children objects beneath my meshes and seeing that minuscule or huge scaling happening.

    There are always ways to deal with that: like creating a parent to that mesh, ... But if that mesh is already a root prefab, it's a more involved process to fix it.

    So if I have a collection of meshes that don't have a scale of 1, it starts to become some work to create parents for each of them.
    It's the little things that add up or it's just me being a neat freak. Depends on the perspective :)



    I checked it out and at a first glance, I don't think that fixes my issue but I'm not certain of that. I'd rather avoid new assets.
     
  15. eaquino_unity

    eaquino_unity

    Joined:
    Aug 13, 2019
    Posts:
    13
    Hi @FeastSC2,

    Did you manage to fix it? I have a similar problem. I am using a library to import .obj and .fbx models, unfortunately not all models have a correct scala (some are bigger and some are not) however they keep the scale factor at 1.

    What I am trying to do is after the model is loaded into the scene, resize it based on a parent container
     
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
    This post is about the scale setting in the default model importer. If you are using a library to import OBJ / FBX files, you are by definition bypassing the default model importer so use caution what you take away from this post.