- Home /
How to update import settings for newly created asset during OnPostprocessAllAssets
I am writing a custom importer for my own filetype. The output of the importer is several Unity assets, such as a PNG and a prefab. The issue is that during OnPostprocessAllAssets
I seem to be unable to refresh the asset database or import assets, so I can't set the import settings for the new asset.
Here is a standalone script that reproduces the issue. If you add a .foo file to your project, there will be an error setting the textureType since there is no asset found, and the import settings remain unchanged (the imported texture is compressed). If you use the "Test/CreateTestTexture()" menu item, the script works as expected (the imported texture is uncompressed). None of the available ImportAssetOptions
seem to help either.
What appears to be happening is that Unity is specifically preventing recursion in OnPostProcessAllAssets by preventing assets from being imported while assets are being imported. I realize that this limitation is probably in place to prevent accidental editor crashes, but it's very restrictive on what I can do as far as importing assets.
Note that if you don't use a random filename for the output texture, the script works the second time the .foo asset is imported, since the texture already exists.
Is there some way to force the import or otherwise get Unity to recognize the new file at some stage of the import process? There's currently no OnPreprocessAllAssets
so there's no way I could create the file ahead of time and hopefully have Unity recognize it in time to set the import settings when the texture is created.
public class MyPostProcessor : AssetPostprocessor
{
[MenuItem("Test/CreateTestTexture()")]
public static void CreateTestTexture()
{
Texture2D test = new Texture2D(128,128);
Color32[] colorData = new Color32[128*128];
for(int i = 0; i < colorData.Length; i++)
{
colorData[i] = new Color32((byte)(UnityEngine.Random.value*255),
(byte)(UnityEngine.Random.value*255),
(byte)(UnityEngine.Random.value*255),
(byte)(UnityEngine.Random.value*255));
}
test.SetPixels32(colorData);
test.Apply();
test.name = UnityEngine.Random.value.ToString();
string path = "Assets/" + test.name + ".png";
byte[] pngTex = test.EncodeToPNG();
File.WriteAllBytes(path, pngTex);
Texture2D.DestroyImmediate(test);
// Overwrite import settings
AssetDatabase.ImportAsset(path);
TextureImporter ti = (TextureImporter)TextureImporter.GetAtPath(path);
ti.textureType = TextureImporterType.Advanced;
ti.filterMode = FilterMode.Point;
ti.textureFormat = TextureImporterFormat.AutomaticTruecolor;
AssetDatabase.WriteImportSettingsIfDirty (path);
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
}
private static void OnPostprocessAllAssets(string[] importedAssets,
string[] deletedAssets, string[] movedAssets, string[] movedFromPath)
{
foreach(string asset in importedAssets)
{
string extension = Path.GetExtension(asset);
if (extension.ToLower() == ".foo")
{
CreateTestTexture();
}
}
}
}
Answer by Deivore · Sep 09, 2018 at 04:28 PM
For the peeps coming across this on google, the reason this isn't working for @phort99 is twofold:
As ModLunar mentions there's a call to AssetDatabase.Refresh(); that needs to be made and is missing in the code. It should be in the order they suggest: WriteAllBytes, AssetDatabase.Refresh(), then making a TextureImporter.
Unfortunately, AssetDatabase.Refresh() works by an OnPostprocessAllAssets() call. @phort99 is calling this import function from within OnPostprocessAllAssets, and Unity won't let you call this function recursively. Therefore phort99's CreateTestTexture() needs to be called some other way, such as through a delegate hooked onto the EditorApplication.update CallBackFunction:
private static EditorApplication.CallbackFunction _importDelegate;
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath) { foreach(string asset in importedAssets) { string extension = Path.GetExtension(asset); if (extension.ToLower() == ".foo") { if (_importDelegate == null) { _importDelegate = new EditorApplication.CallbackFunction(CreateTestTexture); } EditorApplication.update = Delegate.Combine(EditorApplication.update, _importDelegate) as EditorApplication.CallbackFunction; } } }
Additionally their CreateTestTexture() function will need the following first line:
EditorApplication.update = Delegate.Remove(EditorApplication.update, _importDelegate as EditorApplication.CallbackFunction) as EditorApplication.CallbackFunction;
If they eventually want to import a specific item rather than something totally randomly generated, they can save the filename to a static array in the OnPostProcessAllAssets call and reference the filenames and later delete them in the CreateTestTexture() call.
Answer by Jordi-Bonastre · Mar 07, 2016 at 11:24 AM
If you add the OnPreprocessTexture function, you can manage your new .png and change the texture settings after creating it.
Answer by ModLunar · Jun 16, 2017 at 12:19 PM
I'm not sure if this is what you were looking for, but I was coming across a similar problem. I was creating a new texture (.png) file, so I created the file first with something like this:
System.IO.File.WriteAllBytes("Assets/New Texture.png", originalTexture.EncodeToPNG());
What I found was then, to change the import settings of this newly created texture, I had to use this so Unity would recognize the newly created file:
AssetDatabase.Refresh();
Then, I could access the TextureImporter (the import settings, in this case, for a texture) by using
TextureImporter importer = (TextureImporter) AssetImporter.GetAtPath("Assets/New Texture.png");
Then, you're good to go with the importer to change whatever settings you'd like! This can all be in the same method -- you don't need any callbacks or waiting, so it's pretty convenient, but only works in the Editor. You also need to keep track of where the new file is located, and replace where I put my example path, "Assets/New Texture.png".
I hope this helps :)
Your answer
Follow this Question
Related Questions
Running AssetDatabase.ImportPackage on multiple packages 3 Answers
Package Import with Postprocessor - How to tell when all assets are imported 1 Answer
Rename a clip using AssetPostProcessor 1 Answer
Is there a way to get a unique hash for an asset? 1 Answer
AssetDataBase.ImportAsset not triggering AssetProcessor.PreProcessModel 0 Answers