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)
public void CreateMaterial()
{
GeneratedMaterial = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
GeneratedMaterial.SetTexture("_MainTex", TextureAtlas);
var materialPath = FoldersPaths.RenderingAssetsHoldersPath + $"\\{SceneName}_Material.mat";
AssetDatabase.CreateAsset(GeneratedMaterial, materialPath);
// Print the path of the created asset
Debug.Log(AssetDatabase.GetAssetPath(GeneratedMaterial));
}
error:
UnityException: Creating asset at path Assets\Scripts\ScriptableObjects\Map Asset Holders\Instances\Map5_Material.mat failed.
note:
calling this same function from the Editor using [MenuItem(âMyMenu/Do Somethingâ)] works.
Hello @DiegoDePalacio_1 ,
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.
[UpdateInGroup(typeof(GameObjectBeforeConversionGroup))]
public class SceneRenderingAssetsCollectorSystem : GameObjectConversionSystem
{
public int MaxOriginalTextureResolution = 512;
RenderingAssetsHolder renderingAssetsHolder;
private List<Material> materialsWithoutTexture;
protected override void OnStartRunning()
{
base.OnStartRunning();
//Generate the RenderingAssetsHolder if not existing
var (renderingAssetsHolders,_) = ScriptableObjectUtils.GetAllInstances<RenderingAssetsHolder>(new string[] {FoldersPaths.RenderingAssetsHoldersPath});
/* // Not Working so im creating the Scriptable Object Manually from the Editor
bool rahExists = false;
var activeSceneName = SceneManager.GetActiveScene().name;
Debug.Log($"activeSceneName : {activeSceneName}");
for (var i = 0; i < renderingAssetsHolders.Length; i++)
{
if (renderingAssetsHolders[i].SceneName == activeSceneName)
{
rahExists = true;
renderingAssetsHolder = renderingAssetsHolders[i];
}
}
if (rahExists == false)
{
//FIXME: The Editor is not Able to Create the ScriptableObject Asset
renderingAssetsHolder = ScriptableObject.CreateInstance<RenderingAssetsHolder>();
renderingAssetsHolder = ScriptableObjectUtils.CreateScriptableObject<RenderingAssetsHolder>(FoldersPaths.RenderingAssetsHoldersPath+"\\"+ renderingAssetsHolders.Length + "_Asset_Holder.asset");
Debug.Log("New RenderingAssetsHolder Created for this Scene");
}
else
{
Debug.Log("RenderingAssetsHolder already Existing for this Scene");
}*/
if(renderingAssetsHolders.Length > 0)
{
renderingAssetsHolder = renderingAssetsHolders[0];
Debug.Log($"Rendering Assets Holder Found : {renderingAssetsHolder.SceneName}");
}
materialsWithoutTexture = new List<Material>();
}
/// <summary>
/// Pack All Collected Texture to a single Atlas
/// </summary>
public void PackTextures(ref RenderingAssetsHolder rah)
{
var atlas = new Texture2D(rah.AtlasResolution, rah.AtlasResolution);
var tempTexturesArray = new Texture2D[rah.OriginalTextures.Count];
for (var i = 0; i < rah.OriginalTextures.Count; i++)
tempTexturesArray[i] = duplicateTexture(rah.OriginalTextures[i]);
rah.AtlasUvs = atlas.PackTextures(tempTexturesArray, 2, rah.AtlasResolution);
var path = FoldersPaths.RenderingAssetsHoldersPath + $"\\{rah.SceneName}_Atlas.png";
//AssetDatabase.CreateAsset(atlas, path); // Not working as workaround i use the line above
File.WriteAllBytes(path, atlas.EncodeToPNG());
AssetDatabase.ImportAsset(path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
rah.TextureAtlas = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
rah.GeneratedMaterial.SetTexture("_MainTex", rah.TextureAtlas);
EditorUtility.SetDirty(rah);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
// Im using this Function as workaround cause Enabling/Disabling Textures Assets IsReadable field from script is not allowed. (maybe the Same Bug)
Texture2D duplicateTexture(Texture2D source)
{
RenderTexture renderTex = RenderTexture.GetTemporary(
source.width,
source.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
Graphics.Blit(source, renderTex);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = renderTex;
Texture2D readableText = new Texture2D(source.width, source.height);
readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
readableText.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(renderTex);
return readableText;
}
public void CreateMaterial(ref RenderingAssetsHolder rah)
{
rah.GeneratedMaterial = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
var materialPath = FoldersPaths.RenderingAssetsHoldersPath + $"\\{rah.SceneName}_Material.mat";
AssetDatabase.CreateAsset(rah.GeneratedMaterial, materialPath);
// Print the path of the created asset
Debug.Log(AssetDatabase.GetAssetPath(rah.GeneratedMaterial));
}
protected override void OnUpdate()
{
materialsWithoutTexture.Clear();
Entities.ForEach((MeshRenderer meshRenderer, MeshFilter meshFilter) =>
{
var sharedMaterial = meshRenderer.sharedMaterial;
if (sharedMaterial == null)
{
Debug.Log($"this GameObject '{meshRenderer.name}' do not Contain a sharedMaterial");
return;
}
if (sharedMaterial.shader.name != "Universal Render Pipeline/Simple Lit")
return;
var mainTexture = meshRenderer.sharedMaterial.GetTexture("_MainTex") as Texture2D;
if (null == mainTexture)
{
if (materialsWithoutTexture.Contains(sharedMaterial))
return;
Debug.Log($"The material Linked to this GameObject '{meshRenderer.name}' do not Contain a '_MainTex'");
materialsWithoutTexture.Add(sharedMaterial);
// Debug.Log("Path Added!");
return;
}
/*
if (mainTexture == null)
{
Debug.Log($"The material Linked to this GameObject '{meshRenderer.name}' do not Contain a mainTexture");
return;
}
*/
if (!renderingAssetsHolder.OriginalTextures.Contains(mainTexture))
{
if (mainTexture.width > MaxOriginalTextureResolution)
{
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} ");
}
renderingAssetsHolder.OriginalTextures.Add(mainTexture);
}
var sharedMesh = meshFilter.sharedMesh;
if (sharedMesh == null)
{
Debug.Log($"this GameObject '{meshRenderer.name}' do not Contain a sharedMesh");
return;
}
if (!renderingAssetsHolder.SharedMeshes.Contains(sharedMesh))
{
renderingAssetsHolder.SharedMeshes.Add(sharedMesh);
}
});
// CreateMaterial(ref renderingAssetsHolder);
PackTextures(ref renderingAssetsHolder);
EditorUtility.SetDirty(renderingAssetsHolder);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
materialsWithoutTexture.Clear();
Debug.Log("SceneRenderingAssetsCollectorSystem end!");
}
}
btw event calling ScriptableObjectUtils.CreateScriptableObject api is giving the same error.
calling this function from the Mono.Start Methode works.
iâm really confused.