Reputation: 453
Simple and short question,
I download a texture from a server (185MB texture atlas). But creating the texture out of the bytes using Texture2D.LoadImage
blocks the application for about 4 seconds. How can I create this texture asynchronously?
// Load texture atlas texture data
HttpWebRequest atlasTextureRequest = WebRequest.CreateHttp(EntityDatabase.ATLAS_TEXTURE_PATH);
WebResponse atlasTextureResponse = await atlasTextureRequest.GetResponseAsync();
byte[] atlasTextureData = await EntityDatabase.ReadStreamAsync(
atlasTextureResponse.GetResponseStream(),
(int)atlasTextureResponse.ContentLength
);
EntityDatabase.TextureAtlasTexture = new Texture2D(1, 1);
EntityDatabase.TextureAtlasTexture.LoadImage(atlasTextureData);
Upvotes: 5
Views: 7731
Reputation: 90639
Extending on Micky's answer
Currently the only built-in (without the need of additional native code) non-blocking way to load a texture would be using
UnityWebRequestTexture.GetTexture
in a Coroutine
Example from the API
void Start()
{
StartCoroutine(GetText(SOME_URL));
}
IEnumerator DownloadTexture(string url)
{
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url))
{
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.Log(uwr.error);
}
else
{
// Get downloaded asset bundle
var texture = DownloadHandlerTexture.GetContent(uwr);
}
}
}
This also works for local file paths on your device.
If this directly is not an option you could still download and store the file temporary on your device asynchronously and then use the UnityWebRequestTexture.GetTexture
in order to load that locally stored file and then delete the local file again.
Upvotes: 1
Reputation:
OP:
How can I create this texture asynchronously?
You can't, "The C# API's for Texture creation (E.g. new Texture2D
) must always be called on the main thread".
The async/await
support brought to us via .NET 4.x allows for asynchronous I/O and asynchronous compute. Generally there are no barriers to their use but in Unity 3D there is, particularly compute.
Your code below is I/O bound and is an example of asynchronous I/O and Unity should not have any qualms with it. The bit that will pose a problem will be your texture creation. Read on.
WebResponse atlasTextureResponse = await atlasTextureRequest.GetResponseAsync();
byte[] atlasTextureData = await EntityDatabase.ReadStreamAsync(
atlasTextureResponse.GetResponseStream(),
(int)atlasTextureResponse.ContentLength
);
Creating a texture in Unity is CPU-bound and is an example of a compute operation. To perform compute operations in the background you would normally do something like:
var stuff =
await Task.Run (() => ConstructSomethingThatTakesALongTimeSynchonosouly ();
...which is fine but we want to create a Texture2D
so we could try to do something like:
public class LoadTextureAsyncExample : MonoBehaviour
{
// Start runs in the main thread
private async void Start()
{
var textureBytes = await DownloadTextureAsync();
_texture = await Task.Run(() => CreateTexture2D(textureBytes));
}
private async Task<byte[]> DownloadTextureAsync()
{
// essentially your code above.
// This method will be a mixture of main/pool thread
}
private Texture2D CreateTexture2D(byte[] textureBytes)
{
// this method is running in a thread pool thread
var texture = new Texture2D(1, 1);
texture.LoadRawTextureData(textureBytes);
return texture;
}
...now whilst CreateTexture2D
will run in a thread-pool thread and won't block the main thread, the code will fail at the point of creating a Texture2D
due to it running in a thread different from the main thread.
Textures created by C# must be created in the main thread. You could try setting Texture.allowThreadedTextureCreation = true
but that won't work either. Unity says it best below.
Unity (my emphasis):
Texture.allowThreadedTextureCreation
Description
Allow Unity internals to perform Texture creation on any thread (rather than the dedicated render thread).
Note: The C# API's for Texture creation (E.g. new Texture2D) must always be called on the main thread. This setting does not alter that requirement.
Upvotes: 3