【问题标题】:Unity: Recalculate mesh on GPUUnity:在 GPU 上重新计算网格
【发布时间】:2017-03-22 01:12:55
【问题描述】:

我在网上搜索了一段时间,但无法为我当前的问题找到一个好的答案:统一的可见对象由网格组成。在 OpenGL 术语中,网格是一个 VertexBuffer,理想情况下传输一次到 GPU,然后馈入顶点着色器。

现在,在某个给定点,我想重新计算 GPU 上的给定网格。例如,如果我的 VertexBuffer 有空间容纳 200 个属于 Cube 的 Vector3<float>,我想调用一个 ComputeShader(?) 来更新每个 Vector3<float>,以便网格现在是一个球体。

我知道我可以使用 CPU 重新分配网格,但在我的场景中这太慢了。

所以问题是,我如何将 VertexBuffer 或 Mesh 统一传递到 ComputeShader 中?我想直接修改 VertexBuffer。

感谢您的想法、资源、提示!

【问题讨论】:

    标签: unity3d unity5


    【解决方案1】:

    计算着色器易于设置。

    像这样写一个计算着色器

    #pragma kernel CSMain
    
    #define thread_group_size_x 4
    #define thread_group_size_y 4
    
    //A struct that simple holds a position
    struct PositionStruct
    {
        float3 pos;
    };
    
    RWStructuredBuffer<PositionStruct> output;
    
    [numthreads(thread_group_size_x,thread_group_size_y,1)]
    
    void CSMain (uint3 id : SV_DispatchThreadID)
    {
       int idx = id.x + id.y * thread_group_size_x * 32;
       float spacing = 1.0;
    
       float3 pos = float3(id.x*spacing, id.y*spacing, id.z*spacing);
    
       pos = UpdateVertex(pos,idx);
    
       output[idx].pos = pos;
    }
    
    float3 UpdateVertex(float3 p, int idx)
    {
        //Do your stuff here
        return p;
    }
    

    现在创建分派此计算文件的 C# 文件。

    public class ComputeShaderScript: MonoBehaviour
    {
    public Shader shader;
    public ComputeShader computeShader;
    
    private ComputeBuffer outputBuffer;
    private int _kernel;
    private Material material;
    
    void Start()
    {
     RunShader();
    }
    
    void RunShader()
    {
      _Kernal = computeShader.FindKernal("CSMain");
    
      vector3 Array = new vector3[200];
      outputBuffer = new ComputeBuffer(Array.Length, 12); //Output buffer  contains      vertices (float3 = Vector3 -> 12 bytes)
      outputbuffer.SetData(Array);
    
      computeShader.SetBuffer(_Kernal,"output",outputBuffer);
    
      computeShader.Dispatch(_Kernal,array.Length,1,1);
    
      vector3 data= new vector3[200];
      outputbuffer.GetData(data);
    
      buffer.Dispose();
    
      material.SetPass(0);
      material.SetBuffer("buf_Points", outputBuffer);
      Graphics.DrawProcedural(MeshTopology.Points, data.Length);
    }
    

    【讨论】:

    • 这一步vector3 data= new vector3[200]; outputbuffer.GetData(data);有必要吗?它读起来像“将数据复制回cpu”。但是outputbuffer 是我的openGL VertexBuffer 可以这么说吗?因此,如果我知道缓冲区的长度,我可以直接将其交给网格而不复制回 cpu?
    • 为了获取您的数据,您必须让缓冲区将结果数据从自身复制到 CPU RAM 中的新位置。这是在调用调度后使用 GetData 方法完成的。
    • 好的,最后一个问题。在对SetBuffer() 的调用中,“buf_Points”来自哪里。
    • 您可以跳过该部分 metrial.SetBuffer(string name,ComputeBuffer value) 其中 name 是属性名称。 “buf_Points”是在着色器中定义的属性名称。也就是说,如果你已经编写了着色器来绘制它
    • 所以它工作。非常好。我想出了最后一个问题,我找不到任何关于它的信息:为什么是int idx = id.x + id.y * thread_group_size_x * 32; 为什么是*32。它是从哪里来的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-21
    • 2016-01-06
    • 2011-05-20
    • 1970-01-01
    • 2014-09-12
    • 2019-08-06
    相关资源
    最近更新 更多