[toc]

# 为何要使用 Texture 传递数据

在工作的时候遇到一个问题,华为的 Mali 架构系统手机的 OpenGL ES3.0 实际上不支持使用 SSBO 的,但是 Vulkan 可以。
这就产生了一个问题,如果不支持 SSBO,就没法用 StructedBuffer, 而 ContantBuffer 只支持 64KB, 也就意味着 Shader 的参数数量会限制 GpuInstance 的数量,哪怕 Unity 限制每个 Draw 最多只能 Draw 可以支持 Shader 参数的数量,而且如果拆的很细,又会破坏掉 StructedBuffer 的连续性,所以在考虑到这些问题的影响后,思考能否可以使用 Texture 在不支持 SSBO 的时候代替 StructedBuffer。
于是开启了踩坑

# Unity 如何获取 Texture 的连续数据缓存区

首先,当我们使用 Texture 作为数据的参数时,需要把额外的信息剔除掉。且要生成以 float 为排布的数据。

1
2
dataCenter = new Texture2D(100,100,TextureFormat.RGBAFloat, 0,true);
dataCenter.filterMode = FilterMode.Point;

然后可以调用 GetRawTextureData 来获取原始的 TextureData

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.UI;

public unsafe class TestTexture : MonoBehaviour
{
public RawImage imgTarget;
private Texture2D dataCenter;
private NativeArray<Color> ptr;
private Random rad = new Random();
// Start is called before the first frame update
unsafe void Start()
{
dataCenter = new Texture2D(100,100,TextureFormat.RGBAFloat, 0,true);
dataCenter.filterMode = FilterMode.Point;
ptr = dataCenter.GetRawTextureData<Color>();

imgTarget.texture = dataCenter;
}
}

然后当我们在 CPU 端更改 Texture 的数据后,调用 Apply 方法就可以将数据更新到 GPU 上了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.UI;

public unsafe class TestTexture : MonoBehaviour
{
public RawImage imgTarget;
private Texture2D dataCenter;
private NativeArray<Color> ptr;
private Random rad = new Random();
// Start is called before the first frame update
unsafe void Start()
{
dataCenter = new Texture2D(100,100,TextureFormat.RGBAFloat, 0,true);
dataCenter.filterMode = FilterMode.Point;
ptr = dataCenter.GetRawTextureData<Color>();

imgTarget.texture = dataCenter;
}

// Update is called once per frame
void Update()
{
for (int i = 0; i < 100 * 100; ++i)
{
ptr[i] = new Color(Random.Range(0, 1.0f), Random.Range(0, 1.0f), Random.Range(0, 1.0f), 1);
}
dataCenter.Apply();
}
}