C# HLSL中的3D缓冲区?

C# HLSL中的3D缓冲区?,c#,unity3d,gpgpu,hlsl,C#,Unity3d,Gpgpu,Hlsl,我想用unity以3D数组的形式向HLSL发送一系列整数。我已经尝试了几天了,但是没有任何收获。我试图将缓冲区相互打包(StructuredBuffer),但根本无法工作。我需要使这个东西可以调整大小,所以我不能在structs中使用数组。我该怎么办 编辑:为了进一步澄清我在这里要做的事情,这是一个医学项目。当你去扫描你的身体时,会生成一些文件。这些文件称为DICOM文件(.dcm)。那些档案交给了医生。医生应打开程序,选择所有DICOM文件并加载它们。每个DICOM文件包含一个图像。然而,这些

我想用unity以3D数组的形式向HLSL发送一系列整数。我已经尝试了几天了,但是没有任何收获。我试图将缓冲区相互打包(
StructuredBuffer
),但根本无法工作。我需要使这个东西可以调整大小,所以我不能在
struct
s中使用数组。我该怎么办


编辑:为了进一步澄清我在这里要做的事情,这是一个医学项目。当你去扫描你的身体时,会生成一些文件。这些文件称为DICOM文件(.dcm)。那些档案交给了医生。医生应打开程序,选择所有DICOM文件并加载它们。每个DICOM文件包含一个图像。然而,这些图像并不像我们日常生活中使用的正常图像。这些图像是灰度图像,每个像素的值范围在-1000到几千之间,因此每个像素保存为2个字节(或一个Int16)。我需要生成扫描身体的3D模型,所以我使用Marching Cubes算法来生成它(看一看)。问题是我过去常常在360个512*512大小的图像中循环每个像素,这花费了太多的时间。当我使用CPU时,一旦需要,我就从每个文件中读取像素数据。现在,我试图让这个过程在运行时发生。在处理之前,我需要将所有像素数据发送到GPU。那是我的问题。我需要GPU从磁盘读取数据。因为这是不可能的,我需要将360*512*512*4字节的数据以整数的3D数组的形式发送到GPU。我还计划将数据保存在那里,以避免重新传输大量内存。我该怎么办

在Unity中,我们目前拥有允许和的属性,为了让这更甜蜜,我们可以使用着色器静态帮助器和全局设置。我相信这些会帮助你


如果您更喜欢旧方法,请查看如何传递向量数组。

在Unity中,我们目前有允许和的,并且为了使这更甜蜜,我们可以使用着色器静态帮助器和全局设置。我相信这些会帮助你


如果您喜欢旧方法,请查看如何传递向量数组。

根据我的理解,我建议尝试以下方法:

  • 展平数据(嵌套缓冲区不是您在gpu上想要的)

  • 如有必要,将数据拆分到多个
    计算机缓冲区
    (当我在Nvidia Titan X上使用它们时,我可以在每个缓冲区存储大约1GB的数据。我正在渲染一个包含1.5GB数据或其他内容的3D点云,您提到的360MB数据应该不是问题)

  • 如果您需要多个缓冲区:让它们根据您的行进立方体算法的需要重叠

  • ComputeShader
    中执行所有计算(我认为需要DX11,如果您有多个缓冲区,请多次运行它并累积结果),然后在标准着色器中使用结果,您可以从
    OnPostRender
    函数调用该着色器(使用
    Graphics.DrawProcedural
    inside仅在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数据结构
    {
    ...
    }
    数据结构[]您的数据;
    yourData=loadStuff();
    ComputeBuffer tmpBuffer=新的ComputeBuffer(512,Marshal.SizeOf(typeof(DataStruct));
    ComputeBuffer gpuData=新的ComputeBuffer(最大大小,Marshal.SizeOf(typeof(DataStruct)),ComputeBufferType.Append);
    对于(int i=0;i使用512/8工作组
    }
    
    ComputeShader:

    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]);
    }
    
    struct DataStruct//在着色器中复制struct
    {
    ...
    }
    #pragma内核附加
    buffer中的StructuredBuffer;
    AppendStructuredBuffer appendBuffer;
    [numthreads(8,1,1)]
    void append(int-id:SV_DispatchThreadID){
    appendBuffer.Append(inBuffer[id]);
    }
    
    注:

    • 必须通过检查员分配AppendComputeShader
    • 512是一个任意的批处理大小,一次可以附加到gpu缓冲区的数据量有一个上限,但我认为这取决于硬件(对我来说似乎是65536*4字节)
    • 您必须为gpu缓冲区提供最大大小(在Titan X上,它似乎是~1GB)

    根据我的理解,我建议尝试以下方法:

  • 展平数据(嵌套缓冲区不是您在gpu上想要的)

  • 如有必要,将数据拆分到多个
    计算机缓冲区
    (当我在Nvidia Titan X上使用它们时,我可以在每个缓冲区存储大约1GB的数据。我正在渲染一个包含1.5GB数据或其他内容的3D点云,您提到的360MB数据应该不是问题)

  • 如果您需要多个缓冲区:让它们根据您的行进立方体算法的需要重叠

  • ComputeShader
    中执行所有计算(我认为需要DX11,如果您有多个缓冲区,请多次运行它并累积结果),然后在标准着色器中使用结果,您可以从
    OnPostRender
    函数调用该着色器(使用
    Graphics.DrawProcedural
    inside仅在gpu上绘制点或构建网格)