Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Material asset keeps references to assets that are not used

Discussion in 'Editor & General Support' started by TinyU-9527ShouldBeUnique, Mar 23, 2018.

  1. TinyU-9527ShouldBeUnique

    TinyU-9527ShouldBeUnique

    Joined:
    Jan 12, 2018
    Posts:
    10
    It seems that a material asset may keep references to textures that it does not use.
    This is true at least when assets are serialized to texts.
    Reimport the shader or the material does not remove those deprecated references.
    How do I fix this systematically instead of manually editing the text file of the material asset?
     
  2. TinyU-9527ShouldBeUnique

    TinyU-9527ShouldBeUnique

    Joined:
    Jan 12, 2018
    Posts:
    10
    This is pretty annoying because AssetDatabase.GetDependencies seems to be affected by those references which are actually not used at all.
     
  3. TinyU-9527ShouldBeUnique

    TinyU-9527ShouldBeUnique

    Joined:
    Jan 12, 2018
    Posts:
    10
    At the end I created a script to clean up unused textures from the material.
    It seems to solve my problem, but I think this is somewhat a workaround.
    It would be much better if Unity explicitly informs users what unused information is still lingering in material assets and provides an official way to discard it.

    Code (CSharp):
    1.    
    2.     using System.Collections.Generic;
    3.     using System.Linq;
    4.     using UnityEngine;
    5.     using UnityEditor;
    6.    
    7.     public static class CleanUpMaterials
    8.     {
    9.         [MenuItem("Asset Tools/Clean Materials")]
    10.         private static void _CleanProjectMaterials()
    11.         {
    12.             var paths =
    13.                 AssetDatabase.FindAssets("t:Material")
    14.                 .Select(AssetDatabase.GUIDToAssetPath);
    15.  
    16.             foreach (var path in paths)
    17.             {
    18.                 CleanUnusedTextures(path);
    19.             }
    20.  
    21.             AssetDatabase.SaveAssets();
    22.             AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
    23.         }
    24.  
    25.         public static void CleanUnusedTextures(string materialPath)
    26.         {
    27.             var mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
    28.  
    29.             var so = new SerializedObject(mat);
    30.  
    31.             var shader = mat.shader;
    32.             var activeTextureNames =
    33.                 Enumerable.Range(0, ShaderUtil.GetPropertyCount(shader))
    34.                 .Where(
    35.                     index =>
    36.                     ShaderUtil.GetPropertyType(shader, index)
    37.                     == ShaderUtil.ShaderPropertyType.TexEnv)
    38.                 .Select(index => ShaderUtil.GetPropertyName(shader, index));
    39.  
    40.             var activeTextureNameSet = new HashSet<string>(activeTextureNames);
    41.  
    42.  
    43.             var texEnvsSp = so.FindProperty("m_SavedProperties.m_TexEnvs");
    44.             for (var i = texEnvsSp.arraySize - 1; i >= 0; i--)
    45.             {
    46.                 var texSp = texEnvsSp.GetArrayElementAtIndex(i);
    47.                 var texName = texSp.FindPropertyRelative("first").stringValue;
    48.                 if (!string.IsNullOrEmpty(texName))
    49.                 {
    50.                     if (!activeTextureNameSet.Contains(texName))
    51.                     {
    52.                         texEnvsSp.DeleteArrayElementAtIndex(i);
    53.                     }
    54.                 }
    55.             }
    56.  
    57.             so.ApplyModifiedProperties();
    58.         }
    59.     }
     
    Last edited: Mar 23, 2018
    viceca, yusjoel and paxtonmason like this.
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,227
    This is a known issue. It's by design. It's what let's you switch between shaders and keep the same textures. The fact that the get dependency returns it has been discussed internally before. While it is a dependency in the editor, when you build we do a deeper inspection and discard these textures if they are not used by the current shader. The actual deep inspection is very slow so we did not change the get dependency function as it also loads all the assets and walks through them.
    So if you are worried that they get included into a build, they do not.
     
  5. TinyU-9527ShouldBeUnique

    TinyU-9527ShouldBeUnique

    Joined:
    Jan 12, 2018
    Posts:
    10
    How about exposing the deep inspection method to users and let us choose which to use according to our needs?

    What about AssetBundles?
    I created a shader, a material (referencing one used texture and one unused texture), and two textures (one used, one is not) and did some tests with them trying to figure it out.
    By "used" I mean a texture is used in the shader of a material.

    Case I:
    Only the material is marked with a bundle name.
    Judging from the size of the bundle, it seems that the unused texture does not get included in the generated bundle.

    Case II:
    In addition to marking the material with a bundle name, I also marked each texture as a standalone bundle on its own.
    That is, there were three bundles. One for the material, one for the used texture, and one for the unused texture.
    In this case, AssetBundleManifest seems to report that the material bundle depends on both the used and unused texture bundles.
     
    Last edited: Mar 26, 2018
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,227
    It is. I believe it is this https://docs.unity3d.com/ScriptReference/EditorUtility.CollectDependencies.html

    Im not sure about this use case, it's possible that the asset bundles dependencies are calculated differently. Its all going through improvements at the moment so probably worth waiting to see how the new Addressables and Resources system handles it.
     
  7. TinyU-9527ShouldBeUnique

    TinyU-9527ShouldBeUnique

    Joined:
    Jan 12, 2018
    Posts:
    10
    Okay, it explains why there are two similar methods from two classes that do the same task.
    I am pretty surprised that EditorUtility.CollectDependencies behaves differently from how the Unity Editor menu item "Assets/Select Dependencies" behaves.
    I thought the class name "EditorUtility" means that it is mainly used in Unity Editor.

    Thanks for the info. Hope it will behave correctly in the future.
     
    karl_jones likes this.
  8. paxtonmason

    paxtonmason

    Joined:
    Sep 17, 2012
    Posts:
    8
    Thank you. I was about to write the same tool myself.