UnityWebRequestTexture nonReadable - 2017.3.1f1

The texture I’m downloading with this UnityWebRequestTexture class always seems to be nonReadable, even when specifying false as the argument to GetTexture.

Is this a known bug or am I missing something obvious?

var op = UnityWebRequest.GetTetxure(url, false);

In operation handler…

var texture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture;
texture.Compress(true);

Compress() always emits an exception: Texture ‘xyz’ is not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings.

Also, Dear Unity API developer, please don’t use negated variable names for bool parameters. I’ve second guessed the meaning of true and false too many times this afternoon! :slight_smile:

You’re missing something indeed. Textures aren’t readable by default because of optimizations.
Just RTFM: Unity - Scripting API: TextureImporter.isReadable

You linked to the wrong F manual.

What do you think the second parameter is meant to do then?

There was a bug where that second argument the opposite way than it’s name said. That has been fixed now.

Thanks Aurimas, I did stumble across that footnote in older versions of Unity but realized it shouldn’t be an issue in Unity 2017.

I found a fix for my issue though. The bug ended up being in my code. There were 2 places the texture requests were being generated and I had only updated one of them to have readable textures.

As for this API, a couple of additional features (in the form of GetTexture parameters) would be super helpful for my scenario:

  1. Allow compression to be specified as a flag to GetTetxure so that compression can be performed by the engine on a worker thread instead of in the Update loop.
  2. Allow for mip-maps to be generated from downloaded textures. Again, I imagine this would be specified via a bool parameter to GetTexture and generating mipmaps would be done on a worker thread.
  3. Allow for a flag to specify whether the texture is linear or sRGB. It appears the API assumes it is sRGB, which works for my case luckily. I could see this flag being super useful for folks who need to stream linear data, e.g. heightmaps.

My bad, sorry about that. I was too tired and didn’t read with proper precision.

In general I don’t care about negated parameters, however I understand that others are bothered by them.

And absolutely independent of these:

"Textures are not set as readable by default.

When a Texture is not readable, it consumes much less memory because an uncompressed copy of the texture data in system memory is not required after the texture is uploaded to the graphics API. Readable Textures require an uncompressed system memory copy of the texture data so that once edited, the updated texture data can be uploaded to the graphics API."

  • which is a good thing, regardless of the negated param.

Yeah, that’s good to point out the tradeoffs with readability. To your point, this is another reason why it would be nice for the engine to handle the compression and mip-map generation of these textures on a background thread where presumably Untiy would be able to preform all these not-so-lightweight operations and then shove the results into a non-Readable texture for the client (assuming the client requested the texture as non-Readable).

If you want such, use DownloadHandlerBuffer and ImageConversion. The specialized texture download is a simple shortcut for that.

I believe ImageConversion.LoadImage can’t be used on a worker thread though since it’s an extension method on the Texture class. Likewise, this wouldn’t address compression either (same threading restriction applies, I believe, to Texture.Compress())

In order to get this decoding workload on a background thread I would need to find a C# jpeg decoder that can decode into a byte/color array. Mip mapping could also be done on a worker thread after this image decoding is complete, although again it would mean finding/writing your own mipmap generator. (And then likewise with DXT compression.)

Once the bytes are decoded into whatever format you want then you can transfer the data to Unity’s thread and Load into a texture with a minimal slowdown to the update loop since all the heavy lifting was done on the worker.

Getting all that in place though is a lot of work. It would be nice if the engine handled it instead. All the decoding/compression algorithms are there in Unity, just not exposed in a way that can be used on a worker thread.