https://developer.unity.cn/projects/6482ba86edbc2a116e4f27c1
大部分的纹理,Unity都会保存两份像素数据的副本:
最常见的GPU像素数据处理操作,是在着色器里采集纹理样本;而在一些情况下,在CPU上调控纹理数据更合适,访问数据的方式会更灵活。
如何选择处理场景,可以参考以下问题:
SetPixel
for(var y = 0; y < m_TextureSize, ++y)
for(var x = 0; x < m_TextureSize, ++x)
m_TargetTexture.SetPixel(x, y, m_SourceTexture.GetPixel(x,y));
m_TargetTexture.Apply();
SetPixels
m_TargetTexture.SetPixels(m_SourceTexture.GetPixels(0), 0);
m_TargetTexture.Apply();
SetPixels32
m_TargetTexture.SetPixels32(m_SourceTexture.GetPixels32());
m_TargetTexture.Apply();
LoadRawTextureData
m_TargetTexture.LoadRawTextureData(m_SourceTexture.GetRawTextureData());
m_TargetTexture.Apply();
m_TargetTexture.LoadRawTextureData(m_SourceTexture.GetRawTextureData<byte>());
m_TargetTexture.Apply();
SetPixelData
m_TargetTexture.SetPixelData(m_SourceTexture.GetPixelData<byte>(0),0);
m_TargetTexture.Apply();
CopyTexture
Graphics.CopyTexture(m_SourceTexture, m_TargetTexture);
Blit
Graphics.Blit(m_SourceTexture, m_TargetTexture);
SetPixel
for(var y = 0; y < m_TextureSize, ++y)
for(var x = 0; x < m_TextureSize, ++x)
m_TargetTexture.SetPixel(x, y, ChangePixel());
SetPixels32
Color[] m_Colors32 = new Color[m_TextureSize * m_TextureSize];
var idx = 0;
for(var y = 0; y < m_TextureSize, ++y)
for(var x = 0; x < m_TextureSize, ++x)
m_Colors32[idx++] = ChangePixel();
m_TargetTexture.SetPixel32(m_Colors32, 0);
SetPixels
Color[] m_Colors = new Color[m_TextureSize * m_TextureSize];
var idx = 0;
for(var y = 0; y < m_TextureSize, ++y)
for(var x = 0; x < m_TextureSize, ++x)
m_Colors [idx++] = ChangePixel();
m_TargetTexture.SetPixel(m_Colors , 0);
结论:
还有几种特殊方法可能会对性能产生重大影响,需要谨慎使用。
GetPixel、GetPixelBilinear 、SetPixel 、GetPixels 、SetPixels、GetPixels32 、SetPixels32
这类方法能在不同程度上执行像素格式转换,其中Pixels32是里边性能最好的(但是如果纹理的底层格式不能完美匹配Color32结构,也会执行格式转换)。
在使用以上方法时,需要注意像素数量的增长。
GetRawTextureData 、LoadRawTextureData
这是两种只用于Texture2D的方法,可处理包含所有 mip 等级原始像素数据的数据组,并将 mip 按从大到小的顺序排序,每个 mip 带有“高度”数量的“宽度”像素值。
虽然能快速让 CPU 访问数据,但GetRawTextureData 有一个操作难点,就是不按模板写的派生方法会返回数据的副本。这种方式不仅更慢,还不能直接操纵Unity管理的底层缓冲区。GetPixelData没有这种特点,它只会返回指向底层缓冲区的NativeArray,该缓冲区在用户代码将控制权返回给 Unity 之前一直有效。
这是一种将纹理的 GPU 数据转移至另一张纹理的途径,源纹理和目标纹理不一定需要有同样的大小或格式。这种转换流程在各个情况下都会发挥最大效率,但是流程比较繁琐:
是否需要使用该接口,可以根据以下问题:
该函数会从激活的RenderTexture (RenderTexture.active) 同步下载 GPU 数据到 CPU 上的 Texture2D。可以用它来保存或处理某次渲染运算的输出。
从 GPU 下载数据是一个繁琐的流程。在下载开始前,ReadPixels 必须等待 GPU 完成之前的工作,并只会在请求的数据可用后返回,从而拖累性能。如果可以,使用AsynGPUReadback方法会更好。