Search Unity

PrefabUtility.SaveAsPrefabAsset() remove all overrides on its variants

Discussion in 'Prefabs' started by Kichang-Kim, Feb 20, 2019.

  1. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    Hi, I'm working on my own asset pipeline that automatically generates prefab from fbx when it is imported by using AssetPostprocessor.

    Here is my sample code:
    Code (CSharp):
    1. GameObject modelPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
    2.  
    3. if (modelPrefab != null)
    4. {
    5.     GameObject modelPrefabInstance = PrefabUtility.InstantiatePrefab(modelPrefab) as GameObject;
    6.  
    7.     string prefabVariantPath = Path.Combine(Path.GetDirectoryName(path), "Prefabs", Path.GetFileNameWithoutExtension(path) + ".prefab");
    8.  
    9.     PrefabUtility.SaveAsPrefabAsset(modelPrefabInstance, prefabVariantPath);
    10.  
    11.     Object.DestroyImmediate(modelPrefabInstance);
    12. }
    The problem is that when I modified fbx file and reimported it, all of variant of automatically generated prefab and instances on the scene which has overrides are reverted.

    Example situtation:
    Model.fbx : has two objects PartA, PartB
    Model.prefab : automatically generated prefab variant from Model.fbx. Some modification was added manually.
    ModelVariant.prefab : manually generated prefab variant from Model.prefab with additional modification.

    When I reimported Model.fbx, all changes of Model.prefab and ModelVariant.prefab is also reverted even the content of Model.fbx is not changed.

    How to preserve overrides of prefab variant and instances?
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    What's happening is that the asset postprocessor is running again when you reimport, causing your code to overwrite the generated prefab with a new generated prefab.

    So the fix is easy - check if the prefab exists, and don't replace it if it does. It's probably easiest to just check if the asset exists with the asset database. You could also write to the asset importer's userData field - it allows you to attach arbitrary strings to any asset, so you could add a "processed" tag to fbx models that you have processed. That sounds cumbersome, but it'd allow you to rename the model file without getting a new generated prefab.
     
  3. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    @Baste Thanks for reply. Here is more detailed description: My postprocessor generates minimum OBB by using mesh's vertices and add Box collider to prefab. So when designer modified FBX file, the collider should also be updated. So skipping processed fbx cannot be solution for my case.
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Right. I guess the answer is still a version of the same thing - if the prefab exists, load it and update the OBB. If not, generate it.
     
  5. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    I found potential solution.

    Modifying model prefab in OnPostprocessModel(), and generating Prefab variant only first time is works. Overrides on prefab variant are preserved without any problem and only changes of FBX are reflected to prefab variant automatically.
     
  6. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    It seems that PrefabUtility.ReplacePrefab with ReplacePrefabOptions.ReplaceNameBased should work for this purpose, but it is marked as deprecated and does not works correctly.
     
  7. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    @Kichang-Kim

    It is fine to use ReplacePrefab for now, we were too fast marking this obsolete without having a replacement ready.
     
  8. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    @SteenLund It seems that ReplacePrefab remove prefab variant relationship so there is no way for replacing prefab with preserving prefab variant relation.

    Initial state:
    Model.fbx -> Model.prefab (variant of Model.fbx)

    After ReplacePrefab:
    Model.prefab be top of prefab chain
     
  9. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
  10. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012
    It seems that Unity 2019.1.0b10 fix this issue.

    With that version, PrefabUtility.SaveAsPrefabAsset() on existing prefab preserve overrides on both self and its variants.
     
  11. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    Happy to hear it works for you now.
     
  12. Kichang-Kim

    Kichang-Kim

    Joined:
    Oct 19, 2010
    Posts:
    1,012