Search Unity

Bug Error Creating Assets from Code! (bug for Sure)

Discussion in 'Editor & General Support' started by Opeth001, Jul 17, 2020.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    Hello Everyone,

    I am faced with a weird bug again which prevent me from creating Assets via Code using the AssetDatabase.CreateAsset API.

    My function to create a Material. (snipped from unity Documentation)

    Code (CSharp):
    1.  
    2. public void CreateMaterial()
    3.         {
    4.             GeneratedMaterial = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
    5.             GeneratedMaterial.SetTexture("_MainTex", TextureAtlas);
    6.             var materialPath = FoldersPaths.RenderingAssetsHoldersPath + $"\\{SceneName}_Material.mat";
    7.             AssetDatabase.CreateAsset(GeneratedMaterial, materialPath);
    8.  
    9.             // Print the path of the created asset
    10.             Debug.Log(AssetDatabase.GetAssetPath(GeneratedMaterial));
    11.         }
    12.  
    error:
    Code (CSharp):
    1. UnityException: Creating asset at path Assets\Scripts\ScriptableObjects\Map Asset Holders\Instances\Map5_Material.mat failed.
    2.  

    note:
    calling this same function from the Editor using [MenuItem("MyMenu/Do Something")] works.
     
  2. DiegoDePalacio

    DiegoDePalacio

    Unity Technologies

    Joined:
    Oct 28, 2009
    Posts:
    507
    Hello @Opeth001,

    The AssetDatabase.CreateAsset is an Editor-only method and can't be called from GameObject.

    Could you please check if you're calling your 'CreateMaterial' method not in runtime and not from a GameObject?


    Thank you!
     
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    Hello @DiegoDePalacio,
    Thank you for the reply!
    can you please clarify what you mean by not from a Gameobject?

    im trying to generate a single material by packaging all the textures of Material using the same Shader type and updating all the concerned meshes UVs .
    this process is performed when a SubScene is closed (Edit Time) using GameObjectConversionSystem.
    is it considered a as calling from a GameObject?

    My Test code.
    Code (CSharp):
    1.  [UpdateInGroup(typeof(GameObjectBeforeConversionGroup))]
    2.     public class SceneRenderingAssetsCollectorSystem : GameObjectConversionSystem
    3.     {
    4.         public int MaxOriginalTextureResolution = 512;
    5.  
    6.         RenderingAssetsHolder renderingAssetsHolder;
    7.  
    8.         private List<Material> materialsWithoutTexture;
    9.  
    10.         protected override void OnStartRunning()
    11.         {
    12.             base.OnStartRunning();
    13.  
    14.             //Generate the RenderingAssetsHolder if not existing
    15.             var (renderingAssetsHolders,_) = ScriptableObjectUtils.GetAllInstances<RenderingAssetsHolder>(new string[] {FoldersPaths.RenderingAssetsHoldersPath});
    16.  
    17.             /* // Not Working so im creating the Scriptable Object Manually from the Editor
    18.             bool rahExists = false;
    19.             var activeSceneName = SceneManager.GetActiveScene().name;
    20.  
    21.             Debug.Log($"activeSceneName : {activeSceneName}");
    22.             for (var i = 0; i < renderingAssetsHolders.Length; i++)
    23.             {
    24.                 if (renderingAssetsHolders[i].SceneName == activeSceneName)
    25.                 {
    26.                     rahExists = true;
    27.                     renderingAssetsHolder = renderingAssetsHolders[i];
    28.                 }
    29.             }
    30.  
    31.  
    32.             if (rahExists == false)
    33.             {
    34.                 //FIXME: The Editor is not Able to Create the ScriptableObject Asset
    35.                 renderingAssetsHolder = ScriptableObject.CreateInstance<RenderingAssetsHolder>();
    36.  
    37.                 renderingAssetsHolder = ScriptableObjectUtils.CreateScriptableObject<RenderingAssetsHolder>(FoldersPaths.RenderingAssetsHoldersPath+"\\"+ renderingAssetsHolders.Length + "_Asset_Holder.asset");
    38.                 Debug.Log("New RenderingAssetsHolder Created for this Scene");
    39.             }
    40.             else
    41.             {
    42.                 Debug.Log("RenderingAssetsHolder already Existing for this Scene");
    43.             }*/
    44.          
    45.             if(renderingAssetsHolders.Length > 0)
    46.             {
    47.                 renderingAssetsHolder = renderingAssetsHolders[0];
    48.                 Debug.Log($"Rendering Assets Holder Found : {renderingAssetsHolder.SceneName}");
    49.             }
    50.  
    51.             materialsWithoutTexture = new List<Material>();
    52.         }
    53.  
    54.         /// <summary>
    55.         /// Pack All Collected Texture to a single Atlas
    56.         /// </summary>
    57.         public void PackTextures(ref RenderingAssetsHolder rah)
    58.         {
    59.             var atlas = new Texture2D(rah.AtlasResolution, rah.AtlasResolution);
    60.  
    61.             var tempTexturesArray = new Texture2D[rah.OriginalTextures.Count];
    62.  
    63.             for (var i = 0; i < rah.OriginalTextures.Count; i++)
    64.                 tempTexturesArray[i] = duplicateTexture(rah.OriginalTextures[i]);
    65.  
    66.             rah.AtlasUvs = atlas.PackTextures(tempTexturesArray, 2, rah.AtlasResolution);
    67.  
    68.             var path = FoldersPaths.RenderingAssetsHoldersPath + $"\\{rah.SceneName}_Atlas.png";
    69.             //AssetDatabase.CreateAsset(atlas, path); // Not working as workaround i use the line above
    70.             File.WriteAllBytes(path, atlas.EncodeToPNG());
    71.             AssetDatabase.ImportAsset(path);
    72.             AssetDatabase.SaveAssets();
    73.             AssetDatabase.Refresh();
    74.  
    75.             rah.TextureAtlas = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
    76.  
    77.  
    78.             rah.GeneratedMaterial.SetTexture("_MainTex", rah.TextureAtlas);
    79.  
    80.             EditorUtility.SetDirty(rah);
    81.             AssetDatabase.SaveAssets();
    82.             AssetDatabase.Refresh();
    83.         }
    84.  
    85.         // Im using this Function as workaround cause  Enabling/Disabling Textures Assets IsReadable field from script is not allowed. (maybe the Same Bug)
    86.         Texture2D duplicateTexture(Texture2D source)
    87.         {
    88.             RenderTexture renderTex = RenderTexture.GetTemporary(
    89.                         source.width,
    90.                         source.height,
    91.                         0,
    92.                         RenderTextureFormat.Default,
    93.                         RenderTextureReadWrite.Linear);
    94.  
    95.             Graphics.Blit(source, renderTex);
    96.             RenderTexture previous = RenderTexture.active;
    97.             RenderTexture.active = renderTex;
    98.             Texture2D readableText = new Texture2D(source.width, source.height);
    99.             readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
    100.             readableText.Apply();
    101.             RenderTexture.active = previous;
    102.             RenderTexture.ReleaseTemporary(renderTex);
    103.             return readableText;
    104.         }
    105.  
    106.  
    107.         public void CreateMaterial(ref RenderingAssetsHolder rah)
    108.         {
    109.             rah.GeneratedMaterial = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
    110.  
    111.             var materialPath = FoldersPaths.RenderingAssetsHoldersPath + $"\\{rah.SceneName}_Material.mat";
    112.             AssetDatabase.CreateAsset(rah.GeneratedMaterial, materialPath);
    113.  
    114.             // Print the path of the created asset
    115.             Debug.Log(AssetDatabase.GetAssetPath(rah.GeneratedMaterial));
    116.         }
    117.  
    118.         protected override void OnUpdate()
    119.         {
    120.          
    121.             materialsWithoutTexture.Clear();
    122.  
    123.  
    124.             Entities.ForEach((MeshRenderer meshRenderer, MeshFilter meshFilter) =>
    125.             {
    126.                 var sharedMaterial = meshRenderer.sharedMaterial;
    127.  
    128.  
    129.                 if (sharedMaterial == null)
    130.                 {
    131.                     Debug.Log($"this GameObject '{meshRenderer.name}'  do not Contain a sharedMaterial");
    132.                     return;
    133.                 }
    134.  
    135.                 if (sharedMaterial.shader.name != "Universal Render Pipeline/Simple Lit")
    136.                     return;
    137.  
    138.  
    139.  
    140.                 var mainTexture = meshRenderer.sharedMaterial.GetTexture("_MainTex") as Texture2D;
    141.  
    142.  
    143.  
    144.                 if (null == mainTexture)
    145.                 {
    146.                     if (materialsWithoutTexture.Contains(sharedMaterial))
    147.                         return;
    148.  
    149.                     Debug.Log($"The material Linked to this GameObject '{meshRenderer.name}' do not Contain a '_MainTex'");
    150.                     materialsWithoutTexture.Add(sharedMaterial);
    151.                     // Debug.Log("Path Added!");
    152.                     return;
    153.                 }
    154.  
    155.                 /*
    156.                 if (mainTexture == null)
    157.                 {
    158.                     Debug.Log($"The material Linked to this GameObject '{meshRenderer.name}' do not Contain a mainTexture");
    159.                     return;
    160.                 }
    161.                 */
    162.  
    163.                 if (!renderingAssetsHolder.OriginalTextures.Contains(mainTexture))
    164.                 {
    165.                     if (mainTexture.width > MaxOriginalTextureResolution)
    166.                     {
    167.                         Debug.Log($"the material {sharedMaterial.name} with Texture '{mainTexture.name}' has a resolution is higher of {mainTexture.width} which is higher than the threshhold {MaxOriginalTextureResolution} ");
    168.                     }
    169.                     renderingAssetsHolder.OriginalTextures.Add(mainTexture);
    170.                 }
    171.  
    172.  
    173.                 var sharedMesh = meshFilter.sharedMesh;
    174.                 if (sharedMesh == null)
    175.                 {
    176.                     Debug.Log($"this GameObject '{meshRenderer.name}'  do not Contain a sharedMesh");
    177.                     return;
    178.                 }
    179.  
    180.                 if (!renderingAssetsHolder.SharedMeshes.Contains(sharedMesh))
    181.                 {
    182.                     renderingAssetsHolder.SharedMeshes.Add(sharedMesh);
    183.                 }
    184.             });
    185.  
    186.           //  CreateMaterial(ref renderingAssetsHolder);
    187.             PackTextures(ref renderingAssetsHolder);
    188.             EditorUtility.SetDirty(renderingAssetsHolder);
    189.             AssetDatabase.SaveAssets();
    190.             AssetDatabase.Refresh();
    191.  
    192.  
    193.             materialsWithoutTexture.Clear();
    194.             Debug.Log("SceneRenderingAssetsCollectorSystem end!");
    195.         }
    196.     }
     
    Last edited: Jul 17, 2020
  4. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    btw event calling ScriptableObjectUtils.CreateScriptableObject api is giving the same error.
    calling this function from the Mono.Start Methode works.
    i'm really confused.
     
    Last edited: Jul 17, 2020