HLSL 中的 3D 缓冲区?
3D Buffers in HLSL?
我想使用 unity 以 3D 数组的形式将一系列整数发送到 HLSL。几天来我一直在尝试这样做,但没有任何收获。我试图将缓冲区相互打包 (StructuredBuffer<StructuredBuffer<StructuredBuffer<int>>>
),但它根本行不通。而且我需要使这个东西可以调整大小,所以我不能在 struct
中使用数组。我该怎么办?
编辑:为了更清楚地说明我在这里要做什么,这是一个医疗程序。当您扫描 body 时,会生成一些文件。这些文件称为 DICOM 文件 (.dcm)。这些文件交给医生。医生应该打开程序,select 所有 DICOM 文件并加载它们。每个 DICOM 文件都包含一个图像。然而,这些图像与我们日常生活中使用的正常图像不同。这些图像是灰度图像,每个像素的值介于 -1000 到几千之间,因此每个像素都保存为 2 个字节(或 Int16)。我需要生成已扫描的 body 的 3D 模型,因此我使用 Marching Cubes 算法生成它(查看 Polygonising a Scalar Field). The problem is I used to loop over each pixel in about 360 512*512 sized images, which took too much time. I used to read the pixel data from each file once I needed it when I used the CPU. Now I'm trying to make this process occur at runtime. I need to send all of the pixel data to the GPU before processing it. That's my problem. I need the GPU to read data from disk. Because that ain't possible, I need to send 360*512*512*4 bytes of data to the GPU in the form of 3D array of Ints. I'm also planning to keep the data there to avoid retransfer of that huge amount of memory. What should I do? Refer to this link to know more about what I'm doing
在 Unity 中,我们目前有 MaterialPropertyBlock that allows SetMatrixArray and SetVectorArray, and to make this even sweeter, we can set globally using the Shader static helpers SetGlobalVectorArray and SetGlobalMatrixArray。相信这些会对你有所帮助。
如果您更喜欢旧方法,请查看显示如何传递向量数组的this quite nice article。
据我了解,我建议尝试以下操作:
展平你的数据(嵌套缓冲区不是你想要的 gpu)
如有必要,将您的数据拆分到多个 ComputeBuffers
中(当我在 Nvidia Titan X 上使用它们时,我可以为每个缓冲区存储大约 1GB 的数据。我正在渲染 3D 点云有1.5GB的数据什么的,你说的360MBytes的数据应该不是问题)
如果您需要多个缓冲区:让它们根据行进立方体算法的需要重叠
在 ComputeShader
中完成所有计算(我认为需要 DX11,如果你有多个缓冲区,运行 多次计算并累积你的结果)然后使用您从 OnPostRender
函数调用的标准着色器中的结果(在内部使用 Graphics.DrawProcedural
来绘制点或在 gpu 上构建网格)
编辑(您可能会感兴趣)
如果你想将数据追加到一个gpu缓冲区(因为你不知道确切的大小或者你不能立即将它写入gpu),你可以使用AppendBuffers
和一个ComputeShader
.
C# 脚本片段:
struct DataStruct
{
...
}
DataStruct[] yourData;
yourData = loadStuff();
ComputeBuffer tmpBuffer = new ComputeBuffer(512, Marshal.SizeOf(typeof(DataStruct)));
ComputeBuffer gpuData = new ComputeBuffer(MAX_SIZE, Marshal.SizeOf(typeof(DataStruct)), ComputeBufferType.Append);
for (int i = 0; i < yourData.Length / 512; i++) {
// write data subset to temporary buffer on gpu
tmpBuffer.SetData(DataStruct.Skip(i*512).Take((i+1)*512).ToArray()); // Use fancy Linq stuff to select data subset
// set up and run compute shader for appending data to "gpuData" buffer
AppendComputeShader.SetBuffer(0, "inBuffer", tmpBuffer);
AppendComputeShader.SetBuffer(0, "appendBuffer", gpuData);
AppendComputeShader.Dispatch(0, 512/8, 1, 1); // 8 = gpu work group size -> use 512/8 work groups
}
计算着色器:
struct DataStruct // replicate struct in shader
{
...
}
#pragma kernel append
StructuredBuffer<DataStruct> inBuffer;
AppendStructuredBuffer<DataStruct> appendBuffer;
[numthreads(8,1,1)]
void append(int id: SV_DispatchThreadID) {
appendBuffer.Append(inBuffer[id]);
}
注:
- 必须通过 Inspector 分配 AppendComputeShader
- 512 是任意批量大小,一次可以向 gpu 缓冲区附加多少数据有上限,但我认为这取决于硬件(对我来说似乎是 65536 * 4 字节)
- 您必须为 gpu 缓冲区提供最大大小(在 Titan X 上它似乎是 ~1GB)
我想使用 unity 以 3D 数组的形式将一系列整数发送到 HLSL。几天来我一直在尝试这样做,但没有任何收获。我试图将缓冲区相互打包 (StructuredBuffer<StructuredBuffer<StructuredBuffer<int>>>
),但它根本行不通。而且我需要使这个东西可以调整大小,所以我不能在 struct
中使用数组。我该怎么办?
编辑:为了更清楚地说明我在这里要做什么,这是一个医疗程序。当您扫描 body 时,会生成一些文件。这些文件称为 DICOM 文件 (.dcm)。这些文件交给医生。医生应该打开程序,select 所有 DICOM 文件并加载它们。每个 DICOM 文件都包含一个图像。然而,这些图像与我们日常生活中使用的正常图像不同。这些图像是灰度图像,每个像素的值介于 -1000 到几千之间,因此每个像素都保存为 2 个字节(或 Int16)。我需要生成已扫描的 body 的 3D 模型,因此我使用 Marching Cubes 算法生成它(查看 Polygonising a Scalar Field). The problem is I used to loop over each pixel in about 360 512*512 sized images, which took too much time. I used to read the pixel data from each file once I needed it when I used the CPU. Now I'm trying to make this process occur at runtime. I need to send all of the pixel data to the GPU before processing it. That's my problem. I need the GPU to read data from disk. Because that ain't possible, I need to send 360*512*512*4 bytes of data to the GPU in the form of 3D array of Ints. I'm also planning to keep the data there to avoid retransfer of that huge amount of memory. What should I do? Refer to this link to know more about what I'm doing
在 Unity 中,我们目前有 MaterialPropertyBlock that allows SetMatrixArray and SetVectorArray, and to make this even sweeter, we can set globally using the Shader static helpers SetGlobalVectorArray and SetGlobalMatrixArray。相信这些会对你有所帮助。
如果您更喜欢旧方法,请查看显示如何传递向量数组的this quite nice article。
据我了解,我建议尝试以下操作:
展平你的数据(嵌套缓冲区不是你想要的 gpu)
如有必要,将您的数据拆分到多个
ComputeBuffers
中(当我在 Nvidia Titan X 上使用它们时,我可以为每个缓冲区存储大约 1GB 的数据。我正在渲染 3D 点云有1.5GB的数据什么的,你说的360MBytes的数据应该不是问题)如果您需要多个缓冲区:让它们根据行进立方体算法的需要重叠
在
ComputeShader
中完成所有计算(我认为需要 DX11,如果你有多个缓冲区,运行 多次计算并累积你的结果)然后使用您从OnPostRender
函数调用的标准着色器中的结果(在内部使用Graphics.DrawProcedural
来绘制点或在 gpu 上构建网格)
编辑(您可能会感兴趣)
如果你想将数据追加到一个gpu缓冲区(因为你不知道确切的大小或者你不能立即将它写入gpu),你可以使用AppendBuffers
和一个ComputeShader
.
C# 脚本片段:
struct DataStruct
{
...
}
DataStruct[] yourData;
yourData = loadStuff();
ComputeBuffer tmpBuffer = new ComputeBuffer(512, Marshal.SizeOf(typeof(DataStruct)));
ComputeBuffer gpuData = new ComputeBuffer(MAX_SIZE, Marshal.SizeOf(typeof(DataStruct)), ComputeBufferType.Append);
for (int i = 0; i < yourData.Length / 512; i++) {
// write data subset to temporary buffer on gpu
tmpBuffer.SetData(DataStruct.Skip(i*512).Take((i+1)*512).ToArray()); // Use fancy Linq stuff to select data subset
// set up and run compute shader for appending data to "gpuData" buffer
AppendComputeShader.SetBuffer(0, "inBuffer", tmpBuffer);
AppendComputeShader.SetBuffer(0, "appendBuffer", gpuData);
AppendComputeShader.Dispatch(0, 512/8, 1, 1); // 8 = gpu work group size -> use 512/8 work groups
}
计算着色器:
struct DataStruct // replicate struct in shader
{
...
}
#pragma kernel append
StructuredBuffer<DataStruct> inBuffer;
AppendStructuredBuffer<DataStruct> appendBuffer;
[numthreads(8,1,1)]
void append(int id: SV_DispatchThreadID) {
appendBuffer.Append(inBuffer[id]);
}
注:
- 必须通过 Inspector 分配 AppendComputeShader
- 512 是任意批量大小,一次可以向 gpu 缓冲区附加多少数据有上限,但我认为这取决于硬件(对我来说似乎是 65536 * 4 字节)
- 您必须为 gpu 缓冲区提供最大大小(在 Titan X 上它似乎是 ~1GB)