【转载】Unity3D学习笔记9 —— 加载纹理

95 阅读3分钟

原文链接

Unity3D学习笔记9——加载纹理  

1. 概述

理论上,Unity 中加载纹理并没有什么难度,只需要将图片放置在 Assets 文件夹内,就会被识别成纹理,从而可以加载到场景中。但是一旦有一些额外的需求的时候,就得使用其他的方式进行纹理加载。

2. 详论

2.1. Resources 方式

使用 Resources 机制来加载 Unity 的各种资源,包括纹理:

Texture2D texture = Resources.Load<Texture2D>("ImageDemo");

Resources 是 Unity 程序自带的的资源管理。Resources 这个机制特别适用于游戏,对于游戏来说,所有的纹理、材质、Shader 等都可以作为游戏的内置资源。

2.2. API方式

考虑这个情况:如果我们要处理的数据来自资源之外,也就是存在操作系统的资源文件夹中。这种情况 Resources 就无法使用了。这种情况我们应该了解一下纹理的使用原理:纹理图片首先是存在硬盘空间中,然后通过 CPU 读取到内存,最后数据交换到 GPU 的显存中。

一种方法是可以借鉴图像处理的办法,如 GDALOpenCV 等(甚至可以自己通过 File 实现)组件,将图像读取到内存中,组织成 Unity 脚本类 Texture2d 需要的 buffer:

int width = 512;
int height = 512;
texture = new Texture2D(width, height, TextureFormat.RGB24, false);

byte[] imgData = new byte[width * height * 3];

for(int yi = 0; yi< 128; yi++)
{
    for(int xi = 0; xi < 128; xi++)
    {
        int m = width * 3 * yi + 3 * xi;
        imgData[m] = 135;
        imgData[m+1] = 206;
        imgData[m+2] = 235;
    }
}

texture.SetPixelData(imgData, 0, 0);
texture.Apply(false, false);

我将内存 buffer 前 128*128 个像素 buffer 填充成蓝色,最终显示为:
imglink1

也就是纹理 buffer 也是按照左下角起点的。

Apply() 这个函数不能少,因为这个函数是将内存的纹理数据上传到 GPU 的显存中,而且比较耗费性能。最好在更改像素值完成之后,才调用一次 Apply() 上传到 GPU。

2.3. Web 方式

除了本地,资源有时候也会被放置到远端服务器上。对此 Unity 提供了 WWW 类作为访问的接口,但是已经 废弃。现在 Unity 提供 UnityWebRequest 类作为与 Web 服务器进行通信的接口,与访问远端 Texture 相关的类还有 UnityWebRequestTexture。简单研究了这一套接口,似乎还提供异步方法。

不过实际使用中我并没有使用这套接口。因为我想把一部分工作放到 多线程 中。我们知道 Unity 与渲染或者资源相关的内容是 不能 放置到多线程的,但是访问远端数据、并且读取到内存这部分内容是可以放置到多线程的。所以改进方式也很简单:

  1. 使用 C# 的 WebRequest 接口(其他网络传输接口也行),一般网络传输的接口是可以放置在多线程中的。
  2. 将获取到的文件流进行解析,获取 RGB 格式的内存 Buffer。这一步也可以放置在多线程中。
  3. 在主线程将内存 Buffer 塞入到 Texture2D 中。

代码地址