我正在为 Android 构建一个 Unity 应用程序,它处理动态加载大量大纹理(所有图像的大小都超过 6MB,如 png)。这些纹理可以来自 Amazon S3 服务器,在这种情况下它们作为流到达,也可以来自用户的设备本身。
在这两种情况下,我都能够毫无问题地异步获取原始数据或纹理。在第一个中,我查询服务器并获得数据流回调,在第二个中,我使用 WWW 类通过“file://”协议(protocol)获取纹理。
当我想将此数据复制到 Texture2D 到我可以使用的某个地方时,例如复制到 Texture2D 私有(private)成员上,问题就会发生。
对于流,我将其转换为 byte[] 并尝试调用 LoadImage(),对于 WWW 类,我只是尝试使用 myTexture = www.texture 复制它。两次我都在加载或复制纹理时得到一个巨大的框架。我想消除这个框架,因为该应用程序无法随附它。
using (var stream = responseStream)
{
byte[] myBinary = ToByteArray(stream);
m_myTexture.LoadImage(myBinary); // Commenting this line removes frame out
}
...
WWW www = new WWW("file://" + filePath);
yield return www;
m_myTexture = www.texture; // Commenting this line removes frame out
不幸的是,Unity 似乎不喜欢在与主线程不同的线程上运行这些操作,因此当我尝试时会抛出异常。
是否有任何方法可以将这些操作分块以便它需要多个帧?或者做一些不会拖延主线程的快速内存复制操作?
提前致谢!
PS:我在以下存储库中创建了一个问题的工作示例:https://github.com/NeoSouldier/Texture2DTest/
最佳答案
www.texture
已知在下载大型纹理时会导致打嗝。
你应该尝试的事情:
1。使用WWW 的
LoadImageIntoTexture
函数用下载数据中的图像替换现有 Texture2D
的内容。如果问题仍未解决,请继续阅读。
WWW www = new WWW("file://" + filePath);
yield return www;
///////m_myTexture = www.texture; // Commenting this line removes frame out
www.LoadImageIntoTexture(m_myTexture);
2。使用www.textureNonReadable
变量
使用 www.textureNonReadable
而不是 www.texture
还可以加快您的加载时间。我时常看到这种情况发生。
3.使用函数Graphics.CopyTexture
从一个纹理复制到另一个。这应该很快。如果问题仍然没有解决,请继续阅读。
//Create new Empty texture with size that matches source info
m_myTexture = new Texture2D(www.texture.width, www.texture.height, www.texture.format, false);
Graphics.CopyTexture(www.texture, m_myTexture);
4.使用Unity的UnityWebRequest
应用程序接口(interface)。这取代了 WWW
类(class)。您必须拥有 Unity 5.2 及更高版本才能使用它。它有 GetTexture
为下载纹理而优化的函数。
using (UnityWebRequest www = UnityWebRequest.GetTexture("http://www.my-server.com/image.png"))
{
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
m_myTexture = DownloadHandlerTexture.GetContent(www);
}
}
如果上述三个选项都没有解决卡住问题,另一种解决方案是使用 GetPixel
在协程函数中一个一个地复制像素。和 SetPixel
功能。您添加一个计数器并设置您希望它等待的时间。随着时间的推移,它间隔纹理复制。
5。使用 GetPixel
逐一复制 Texture2D
像素和 SetPixel
功能。示例代码包括来自 Nasa 的 8K 纹理,用于测试目的。复制 Texture
时不会阻塞。如果是,请减小 copyTextureAsync
函数中的 LOOP_TO_WAIT
变量的值。您还可以选择提供一个函数,该函数将在完成复制 Texture
时调用。
public Texture2D m_myTexture;
void Start()
{
//Application.runInBackground = true;
StartCoroutine(downloadTexture());
}
IEnumerator downloadTexture()
{
//http://visibleearth.nasa.gov/view.php?id=79793
//http://eoimages.gsfc.nasa.gov/images/imagerecords/79000/79793/city_lights_africa_8k.jpg
string url = "http://eoimages.gsfc.nasa.gov/images/imagerecords/79000/79793/city_lights_africa_8k.jpg";
//WWW www = new WWW("file://" + filePath);
WWW www = new WWW(url);
yield return www;
//m_myTexture = www.texture; // Commenting this line removes frame out
Debug.Log("Downloaded Texture. Now copying it");
//Copy Texture to m_myTexture WITHOUT callback function
//StartCoroutine(copyTextureAsync(www.texture));
//Copy Texture to m_myTexture WITH callback function
StartCoroutine(copyTextureAsync(www.texture, false, finishedCopying));
}
IEnumerator copyTextureAsync(Texture2D source, bool useMipMap = false, System.Action callBack = null)
{
const int LOOP_TO_WAIT = 400000; //Waits every 400,000 loop, Reduce this if still freezing
int loopCounter = 0;
int heightSize = source.height;
int widthSize = source.width;
//Create new Empty texture with size that matches source info
m_myTexture = new Texture2D(widthSize, heightSize, source.format, useMipMap);
for (int y = 0; y < heightSize; y++)
{
for (int x = 0; x < widthSize; x++)
{
//Get color/pixel at x,y pixel from source Texture
Color tempSourceColor = source.GetPixel(x, y);
//Set color/pixel at x,y pixel to destintaion Texture
m_myTexture.SetPixel(x, y, tempSourceColor);
loopCounter++;
if (loopCounter % LOOP_TO_WAIT == 0)
{
//Debug.Log("Copying");
yield return null; //Wait after every LOOP_TO_WAIT
}
}
}
//Apply changes to the Texture
m_myTexture.Apply();
//Let our optional callback function know that we've done copying Texture
if (callBack != null)
{
callBack.Invoke();
}
}
void finishedCopying()
{
Debug.Log("Finished Copying Texture");
//Do something else
}
关于c# - 在 C# for Unity 中非阻塞加载和复制大型 Texture2D,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40450867/