I am using the packed textures of a sprite atlas on mesh renderers and I was wondering if it is somehow possible to enable mip map streaming for these textures?
So far I could not find a regular public importer property / setting to achieve this. If someone is running the game on a lower than 4k resolution this feature would help the required memory amount quite a bit as far as I understand it.
I could possibly get some control with Texture2D.requestedMipmapLevel but that does not prevent loading / uploading the other mip map levels to the gpu?
My last resort would be to extract the atlas textures into regular textures and re-assign them in all materials using them (I already have those serialized in a list anyway).
Probably not possible out of the box. You’ll notice that if you change a texture’s type from Default to Sprite (2D and UI) it will not show you any of the mipmap level options besides Generate Mipmap.
Are you even having that problem right now, or are you trying to optimize before there’s even an issue with it?
I mean you can’t stop users from running at 4k resolution if they run low on memory. So from the user’s perspective it’s either “4k crashes the game” or “I can’t choose 4k whyyy?” if you somehow determine for the user that 4k is not an option for them.
I guess yes there is some truth to that, I am asking in order to be prepared for that situation, yes.
Yes on a pc that is at least theoretically able to start the game at 4k you can’t that control that that is correct. But if someone selects 1080p as resolution they should not pay the memory costs for 4k textures either. 1080p would run better without those mip 0 levels present on the gpu. So it is rather a question of enabling lower quality levels working at all on worse hardware.
And running the game on a steam deck probably benefits a lot from this optimization (but granted that is another build and we can probably strip those mip levels entirely from the build) - but running on that is what started this question in the first place for me.
Hm the memory profiler does at least show the streaming flag for the atlas texture.
For Sprites and SpriteAtlases there, mipmaps are disabled by default and generally have very limited use-cases. Hence streaming option is not available.
The above use-case seems to require just the packed texture and manual binding to materials. In this case the extract and export process to standard textures can be automated through AssetPostProcessors. Sample script below:
Ensure the SpriteAtlas has read/write enabled and the format is non-compressed like RGB24.
using UnityEngine;
using UnityEditor;
// This is just a simple demonstration for SpriteAtlas Post Processor.
public class SpriteAtlasPostProcessorDemonstration : AssetPostprocessor
{
// OnPostprocessAllAssets can be used to extract output from SpriteAtlas import and generate standard texture for mipmapStreaming.
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload)
{
foreach (var asset in importedAssets)
{
if (asset.Contains("spriteatlasv2"))
{
var textures = AssetDatabase.LoadAllAssetsAtPath(asset);
var index = 0;
foreach (var texture in textures)
{
var tex2D = texture as Texture2D;
if (null != tex2D && tex2D.name.Contains("sactx"))
{
byte[] _bytes = tex2D.EncodeToPNG();
var path = asset.Replace(".spriteatlasv2", index.ToString() + ".png");
System.IO.File.WriteAllBytes(path, _bytes);
index++;
}
}
}
}
AssetDatabase.Refresh();
}
// Ensure this is called last when there are multiple postprocessors.
public override int GetPostprocessOrder()
{
return int.MaxValue;
}
}
Admittedly the entire setup is a bit uncommon. I am using the sprite atlas as texture packer for meshes which have their textures projected from a fixed angle. In every regard rendering wise they are regular mesh renderers but the textures are pretty much sprites (hence using the sprite atlas with it’s efficient packing made sense). These meshes get scaled and placed all over the levels so mip maps seems reasonable (?).
Setting the atlas to readable… so easy… I completely did this with gpu readback already. Your solution is much better and especially doing it in an asset post processor feels really tight. Nice.