准备工作
在上一章中,我们学习了如何将自定义数据传递给Compute Shader Buffer并进行计算,在本章中,我们来学习如何获取Compute Shader Buffer中的数据在C#脚本中使用
首先创建一个C#脚本,名称为 StarsTrans
,创建一个Compute Shader脚本,名称为 OrbitingStars
这里,我们准备向Compute Shader传输多个Vecotr3的位置信息,经过Compute Shader计算,然后取回这些计算结果,每个Vecotr3对应一个场景中圆球的位置,让这些圆球像星球一样围绕着中心店转动,StarsTrans
代码如下:
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 34 35 36 37 38 39 40
| using UnityEngine;
public class StarsTrans : MonoBehaviour { //球的数量 public int starCount; public ComputeShader shader;
//球的预制体 public GameObject prefab;
private ComputeBuffer resultBuffer; private int kernelHandle; private uint threadGroupSizeX; private int groupSizeX; private Vector3[] output;
//球的实例 private Transform[] stars;
void Start() { kernelHandle = shader.FindKernel("OrbitingStars"); shader.GetKernelThreadGroupSizes(kernelHandle, out threadGroupSizeX, out _, out _); //根据圆球数量和线程组中的X线程数,计算出调用次数 groupSizeX = (int)((starCount + threadGroupSizeX - 1) / threadGroupSizeX);
//填充Buffer数据 resultBuffer = new ComputeBuffer(starCount, sizeof(float) * 3); shader.SetBuffer(kernelHandle, "Result", resultBuffer); output = new Vector3[starCount];
//根据圆球数量创建对应实例 stars = new Transform[starCount]; for (int i = 0; i < starCount; i++) { stars[i] = Instantiate(prefab, transform).transform; } } }
|
Compute Shader中可读写的buffer
C#脚本中的内容,与上一章的基本相同,都是创建buffer并填充。但在Compute Shader脚本中有些许不同
在上一章中我们只是将数据从C#脚本传输到了Compute Shader中,这里我们需要在Compute Shader中计算一些假随机值,然后在C#脚本中获取buffer中的结果
这里就要使用到 RWStructuredBuffer
,代码如下:
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
| #pragma kernel OrbitingStars
RWStructuredBuffer<float3> Result; float time;
float random(float value, float seed = 0.546) { float res = frac(sin(value + seed) * 143758.5453); return res; }
float3 random3(float value) { return float3(random(value, 3.9812), random(value, 7.1536), random(value, 5.7241)); }
[numthreads(64, 1, 1)] void OrbitingStars(uint3 id : SV_DispatchThreadID) { float3 sinDir = normalize(random3(id.x) - 0.5); float3 vec = normalize(random3(id.x + 7.1393) - 0.5); float3 cosDir = normalize(cross(sinDir, vec));
float scaledTime = time * 0.5 + random(id.x) * 712.131234;
float3 pos = sinDir * sin(scaledTime) + cosDir * cos(scaledTime);
Result[id.x] = pos * 2; }
|
这里要注意,我们使用了 RWStructuredBuffer
,这是一个可读写的缓冲区,可以让C#脚本获取到这个缓冲区中的计算结果数据
在 OrbitingStars
方法中,我们做了上一章中圆环相似的伪随机,实现了球形围绕中心点旋转的效果
获取Buffer的计算结果
回到C#脚本,在Update方法中,我们先要将数据传输给Compute Shader,然后使用 ComputeBuffer.GetData
方法从Compute Shader中获取计算结果数据,代码如下:
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
| using UnityEngine;
public class StarsTrans : MonoBehaviour { ...
private void Update() { shader.SetFloat("time", Time.time); //将数据传输给Compute Shader进行计算 shader.Dispatch(kernelHandle, groupSizeX, 1, 1); //获取计算结果 resultBuffer.GetData(output);
//将计算结果依次赋值给每个球形 for (int i = 0; i < stars.Length; i++) { stars[i].localPosition = output[i]; } }
private void OnDestroy() { resultBuffer.Dispose(); } }
|
此处要注意 OnDestroy
中要主动释放掉ComputeBuffer,不然会造成内存泄漏,Unity会有警告
至此我们就完成了若干个小球围绕着一个中心点运动的效果,如下图:
在下一章中,我们尝试使用这一章与前一章所了解的Compute Shader Buffer内容,制作一个球形与立方体之间变换的效果
相关链接
RWStructuredBuffer