2017-10-07 43 views
1

我一直在学习了一些基本金属呈现和我坚持一些基本概念:用金属调用顶点着色器多少次?

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

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个元素......多少次被称为顶点功能? 10?

谢谢!

回答

3

这是由您在渲染命令编码器上绘制的调用确定的。就拿最简单的绘制方法:

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),其中一个具有[0..instanceCount-1]中的每个实例ID。等

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

各种drawIndexedPrimitives()方法从缓冲区获取特定的顶点ID,而不是枚举范围内的所有顶点ID。该缓冲区可能包含多个位置中的给定顶点ID。对于这种情况,我认为它没有定义顶点函数是否可以针对相同的顶点ID和实例ID多次调用。 Metal可能会尝试避免重复工作,但即使多个这样的索引最终成为相同的顶点ID,它可能最终只会为索引缓冲区中的每个索引调用顶点函数。

您传递给顶点处理阶段的缓冲区中的顶点和数据之间的关系完全取决于您。你根本不需要传递任何缓冲区。例如,顶点函数可以从顶点ID和实例ID完全计算生成顶点信息。

当然,至少某些缓冲区包含使用顶点ID索引到的每个顶点数据的数组是很常见的。其他缓冲区可能是统一的数据,对于所有顶点都是相同的(也就是说,您不使用顶点ID将其索引到该缓冲区中)。不过,金属本身并不知道这一点。