Quick answer: Texture Streaming loads low-res mips first, then upgrades. If the Memory Budget is exhausted, textures stay blurry forever. Raise QualitySettings.streamingMipmapsMemoryBudget, set per-texture streamingMipmapsPriority, or call tex.requestedMipmapLevel = 0 to force full resolution.

Here is how to fix Unity textures that load blurry and never sharpen. You ship a build, walk up to a wall, and the wall texture is a muddy low-res blur. Stand there for ten seconds — still blurry. Quit and relaunch — same blur. Meanwhile the Editor renders it crisp. This is the Texture Streaming system doing its job badly: it loaded mip level 4 or 5 of your texture, ran out of budget, and never promoted it.

The Symptom

You see one or more of these:

What Causes This

Texture Streaming is opt-in but global. When QualitySettings.streamingMipmapsActive is enabled, Unity only loads the mip levels a texture currently needs based on screen coverage. A texture far from the camera loads mip 6; up close it loads mip 0. The system uses a shared memory budget across all streamed textures.

Memory Budget exhaustion. The default budget is 512 MB. In a scene with thousands of 2K and 4K textures, that budget is hit fast. When exhausted, Unity keeps lower mip levels loaded and refuses to upgrade to higher ones. Your wall stays blurry because there is no budget left to load mip 0.

Priority ties. When budget is tight, Unity decides which textures to promote based on streamingMipmapsPriority. All textures default to 0. Everything ties. The tie-breaker is arbitrary and can leave important textures low-res while background textures stream in.

No valid camera reference. Streaming uses Camera projection to compute screen coverage. If a texture is rendered by a camera with no StreamingController, or if the camera is marked as non-main at startup, the streaming system may fail to prioritize it correctly.

Missing Texture Streaming on import. The import setting must be on per-texture. A texture imported before you enabled streaming still has the flag off and is loaded at full resolution (or not at all if memory is tight).

The Fix

Step 1: Raise the Memory Budget. Project Settings > Quality > Texture Streaming > Memory Budget. Default is 512. Raise to 1024 or 2048 on PC/console. On mobile, keep it tight but profile first.

using UnityEngine;

public class StreamingConfig : MonoBehaviour
{
    void Awake()
    {
        QualitySettings.streamingMipmapsActive = true;
        QualitySettings.streamingMipmapsMemoryBudget = 2048; // MB
        QualitySettings.streamingMipmapsMaxLevelReduction = 2;
    }
}

streamingMipmapsMaxLevelReduction caps how aggressively Unity can reduce mips. A value of 2 means textures never drop more than 2 mip levels below full res, which prevents severe blur at the cost of higher memory.

Step 2: Set per-texture priority. Hero textures — character faces, weapon skins, signage — deserve higher priority than distant scenery.

Texture2D tex = material.GetTexture("_MainTex") as Texture2D;
if (tex != null)
{
    tex.streamingMipmapsPriority = 2; // higher = load first
}

Priority is an int. Higher values win ties. Set via code at runtime or via the TextureImporter.streamingMipmapsPriority field at import time.

Step 3: Force load critical textures. For textures that must always be full resolution — UI, loading screens, cinematics — bypass streaming entirely:

tex.requestedMipmapLevel = 0; // force mip 0

// or disable streaming on this texture:
tex.streamingMipmaps = false;

requestedMipmapLevel is a hint — the streaming system still manages memory but promotes this texture aggressively. streamingMipmaps = false takes it out of the system completely; it loads full resolution and stays there.

Step 4: Verify import settings. Select the texture in the Project window. Import Settings > Advanced > Streaming Mipmaps must be checked. If you enabled streaming after importing the texture, reimport it (right-click > Reimport).

Step 5: Add StreamingController to cameras. If you use non-main cameras (cutscene cameras, minimap cameras), attach UnityEngine.StreamingController to them. Otherwise the streaming system only considers Camera.main for mip calculation and other cameras render blurry.

Force Load All For Loading Screens

During loading screens or cutscene transitions, you may want to force all streamed textures to load before revealing the scene. Use Texture.streamingTextureForceLoadAll:

Texture.streamingTextureForceLoadAll = true;
yield return new WaitForSeconds(0.5f); // let mips load
Texture.streamingTextureForceLoadAll = false;

This overrides the budget temporarily and forces all textures to mip 0. Use only when hiding behind a loading screen — doing it mid-gameplay tanks framerate.

Debugging

Window > Analysis > Profiler > Memory > Texture section shows per-texture memory. Look for textures with “current mip” higher than 0 on textures that should be sharp. Texture.desiredTextureMemory vs Texture.currentTextureMemory tells you how much streaming is being held back by budget.

You can also log per-frame:

void Update()
{
    Debug.Log($"Desired: {Texture.desiredTextureMemory / 1024 / 1024}MB Current: {Texture.currentTextureMemory / 1024 / 1024}MB");
}

“Texture Streaming is budget-constrained. If textures never sharpen, the budget is too small or the priority is wrong. Profile first, tune second.”

Mobile Considerations

On mobile, memory is tight. A budget of 256 MB is common. Set streamingMipmapsMaxLevelReduction = 1 to keep textures from dropping more than one mip level, and mark UI and key gameplay textures as non-streaming so they are always sharp.

Raise the budget. Prioritize hero textures. Force load on loading screens.