使用Metal时,顶点着色器会被调用多少次?

5

我正在学习一些基础的金属渲染,但是我卡在了一些基本概念上:

我知道我们可以使用以下方式将顶点数据发送到着色器:

renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)

然后我们可以在着色器中使用以下代码检索它:

vertex float4 basic_vertex(const device VertexIn* vertexIn [[ buffer(0) ]], unsigned int vid [[ vertex_id ]])

据我所知,顶点函数将每个顶点调用一次,并且vertex_id将在每次调用时更新以包含顶点索引。

问题是,vertex_id从哪里来?

我可以发送更多不同大小的数据到着色器:

renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.setVertexBuffer(vertexBuffer2, offset: 0, index: 1)

如果vertexBuffer有3个元素,而vertexBuffer2有10个元素...那么vertex函数会被调用多少次?是10次吗?
谢谢!
1个回答

8
这取决于在渲染命令编码器上进行的绘制调用。以最简单的绘制方法为例:
drawPrimitives(type:vertexStart:vertexCount:)

vertexCount决定了您的顶点函数被调用的次数。传递给顶点函数的顶点ID位于vertexStartvertexStart + vertexCount - 1范围内。

如果您考虑另一种绘制方法:

drawPrimitives(type:vertexStart:vertexCount:instanceCount:)

这涉及相同范围的顶点ID。然而,它调用您的顶点函数vertexCount * instanceCount次。将有instanceCount个调用,其中顶点ID为vertexStart。对于这些调用,实例ID将在[0..instanceCount-1]范围内变化。同样,将有instanceCount个调用,其中顶点ID为vertexStart + 1(假设vertexCount >= 2),每个实例ID都在[0..instanceCount-1]中。等等。

其他绘图方法有各种其他选项,但它们大多不影响调用顶点函数的次数。例如,baseInstance移动了实例ID的范围,但没有改变其大小。

各种drawIndexedPrimitives()方法从缓冲区获取特定的顶点ID,而不是枚举范围内的所有顶点ID。该缓冲区可能在多个位置包含给定的顶点ID。对于这种情况,我不认为定义了顶点函数是否可能多次为相同的顶点ID和实例ID调用。Metal可能会尽力避免重复努力,但如果多个这样的索引最终成为相同的顶点ID,则直接为索引缓冲区中的每个索引调用顶点函数可能实际上更快。

您传递给顶点处理阶段的缓冲区中的顶点和数据之间的关系完全由您决定。您不必传递任何缓冲区。例如,一个顶点函数可以完全计算地从顶点ID和实例ID生成顶点信息。

当然,至少有一些缓冲区可能包含按顶点索引的每个顶点数据数组。其他缓冲区可能是对于所有顶点都相同的统一数据(即,您不使用顶点ID索引该缓冲区)。Metal本身并不知道这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接