Сколько раз вызывается вершинный шейдер с металлом?
Я изучил некоторые основные металлические рендеринга, и я застрял с некоторыми основными понятиями:
Я знаю, что мы можем отправлять данные вершин в шейдер, используя:
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?
Спасибо!
1 ответ
Это определяется вызовом отрисовки, который вы делаете в кодере команд рендеринга. Возьмите самый простой метод розыгрыша:
drawPrimitives(type:vertexStart:vertexCount:)
vertexCount
определяет, сколько раз вызывается ваша вершинная функция. Идентификаторы вершин, переданные функции вершин, находятся в диапазоне от vertexStart
в vertexStart + vertexCount - 1
,
Если вы рассматриваете другой метод рисования:
drawPrimitives(type:vertexStart:vertexCount:instanceCount:)
Это распространяется на тот же диапазон идентификаторов вершин. Тем не менее, он вызывает вашу функцию вершины vertexCount * instanceCount
раз. Будут instanceCount
звонки с идентификатором вершины vertexStart
, ID экземпляра будет в диапазоне от 0 до instanceCount - 1
для этих звонков. Также будет instanceCount
звонки с идентификатором вершины vertexStart + 1
(при условии, vertexCount >= 2
), один с каждым идентификатором экземпляра в [0..instanceCount-1]
, И т.п.
Другие методы рисования имеют различные другие опции, но они в основном не влияют на то, сколько раз вызывается функция вершины. Например, baseInstance
смещает диапазон идентификаторов экземпляра, но не его размер.
Различные drawIndexedPrimitives()
методы получают конкретные идентификаторы вершин из буфера вместо перечисления всех идентификаторов вершин в диапазоне. Этот буфер может содержать заданный идентификатор вершины в нескольких местах. В этом случае я не думаю, что определено, может ли функция вершины вызываться несколько раз для одного и того же идентификатора вершины и идентификатора экземпляра. Предположительно, Metal будет пытаться избежать дублирования, но на самом деле может оказаться, что быстрее будет просто вызывать функцию вершины для каждого индекса в буфере индекса, даже если несколько таких индексов заканчиваются тем же идентификатором вершины.
Отношение между вершинами и данными в буферах, которые вы передаете на этап обработки вершин, полностью зависит от вас. Вам не нужно передавать какие-либо буферы, вообще. Например, функция вершины может генерировать информацию вершины полностью вычислительно только из идентификатора вершины и идентификатора экземпляра.
Конечно, довольно часто, по крайней мере, некоторые из буферов содержат массивы данных для каждой вершины, которые индексируются с использованием идентификатора вершины. Другие буферы могут быть единообразными данными, которые одинаковы для всех вершин (то есть вы не индексируете этот буфер, используя идентификатор вершины). Хотя сам металл этого не знает.