我有非常动态的数据,每一帧都会发生变化。数据本身比较小所以我使用
[commandEncoder setVertexBytes:_vertices.buffer() length:_vertices.size() * sizeof(float) atIndex:0];
设置顶点数据。
但是,在绘制时我还需要设置索引数据:
[commandEncoder drawIndexedPrimitives: ...];
如何更新在drawIndexedPrimitives
方法中提供的用于索引数据的MTLBuffer
?我需要能够有效地更新索引缓冲区。
最佳答案
This article包含对使用多个缓冲区在 CPU 和 GPU 之间同步数据而不强制它们锁步工作的深入解释。你应该仔细阅读它。我将在下面总结该方法。
- 为索引缓冲区选择一个足够大的大小,以容纳您可能需要绘制的最大索引数。
- 分配几个 (2-3) 个此大小的缓冲区并将它们放入一个数组(类型为
NSArray<id<MTLBuffer>>
)中。这是你的重用池;我将其称为indexBufferPool
下面。 - 初始化渲染器时,create a dispatch semaphore其值等于您放入重用池中的缓冲区数量。我将其称为
bufferSemaphore
下面。 - 创建一个缓冲区索引成员变量并将其初始化为0。我将其称为
bufferIndex
下面。 - 每次绘制时,通过调用
dispatch_semaphore_wait(bufferSemaphore, DISPATCH_TIME_FOREVER)
等待信号量. - 当信号量等待函数返回时,可以安全地将新索引数据复制到当前缓冲区索引处的缓冲区中。使用
memcpy
或其他一些复制技术,将索引数据复制到bufferPool[bufferIndex]
的内容中. - 使用
bufferPool[bufferIndex]
绘制您的基元作为索引缓冲区。 - 增量
bufferIndex
通过设置bufferIndex = (bufferIndex + 1) % ResourceCount
,其中ResourceCount
是重用池中缓冲区的数量。 - 在提交之前,将已完成的处理程序添加到当前命令缓冲区。完成的处理程序应调用
dispatch_semaphore_signal(bufferSemaphore)
。这让任何对绘制方法的挂起调用都知道可以安全地在当前缓冲区索引处写入缓冲区。
关于ios - 在 iOS 中使用 Metal 渲染时每帧更新索引缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59503060/