Рисовать часть MTLBuffer?
Я рендеринг фрагментов из буфера с этим вызовом:
renderEncoder.drawPrimitives(type: .point,
vertexStart: 0,
vertexCount: 1,
instanceCount: emitter.currentParticles)
emitter.currentParticles
общее количество частиц в буфере. Можно ли как-то нарисовать только часть буфера?
Я пробовал это, но он рисует первую половину буфера:
renderEncoder.drawPrimitives(type: .point,
vertexStart: emitter.currentParticles / 2,
vertexCount: 1,
instanceCount: emitter.currentParticles / 2)
На самом деле, кажется, что vertexStart
не имеет никакого эффекта Кажется, я могу установить любое значение, и оно все еще начинается с 0.
Редактировать:
Конфигурация трубопровода:
private func buildParticlePipelineStates() {
do {
guard let library = Renderer.device.makeDefaultLibrary(),
let function = library.makeFunction(name: "compute") else { return }
// particle update pipeline state
particlesPipelineState = try Renderer.device.makeComputePipelineState(function: function)
// render pipeline state
let vertexFunction = library.makeFunction(name: "vertex_particle")
let fragmentFunction = library.makeFunction(name: "fragment_particle")
let descriptor = MTLRenderPipelineDescriptor()
descriptor.vertexFunction = vertexFunction
descriptor.fragmentFunction = fragmentFunction
descriptor.colorAttachments[0].pixelFormat = renderPixelFormat
descriptor.colorAttachments[0].isBlendingEnabled = true
descriptor.colorAttachments[0].rgbBlendOperation = .add
descriptor.colorAttachments[0].alphaBlendOperation = .add
descriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
descriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
descriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
descriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
renderPipelineState = try
Renderer.device.makeRenderPipelineState(descriptor: descriptor)
renderPipelineState = try Renderer.device.makeRenderPipelineState(descriptor: descriptor)
} catch let error {
print(error.localizedDescription)
}
}
Вершинный шейдер:
struct VertexOut {
float4 position [[ position ]];
float point_size [[ point_size ]];
float4 color;
};
vertex VertexOut vertex_particle(constant float2 &size [[buffer(0)]],
device Particle *particles [[buffer(1)]],
constant float2 &emitterPosition [[ buffer(2) ]],
uint instance [[instance_id]])
{
VertexOut out;
float2 position = particles[instance].position + emitterPosition;
out.position.xy = position.xy / size * 2.0 - 1.0;
out.position.z = 0;
out.position.w = 1;
out.point_size = particles[instance].size * particles[instance].scale;
out.color = particles[instance].color;
return out;
}
fragment float4 fragment_particle(VertexOut in [[ stage_in ]],
texture2d<float> particleTexture [[ texture(0) ]],
float2 point [[ point_coord ]]) {
constexpr sampler default_sampler;
float4 color = particleTexture.sample(default_sampler, point);
if ((color.a < 0.01) || (in.color.a < 0.01)) {
discard_fragment();
}
color = float4(in.color.xyz, 0.2 * color.a * in.color.a);
return color;
}
1 ответ
Вы не используете дескриптор вершины, ни [[stage_in]]
параметр для вашего вершинного шейдера. Итак, Metal не выбирает / собирает данные вершин для вас. Вы просто индексируете в буфер, который размечен вашими данными вершин уже в нужном вам формате. Все в порядке. Смотрите мой ответ здесь для получения дополнительной информации о дескрипторе вершины.
Учитывая, что, тем не менее, vertexStart
Параметр вызова draw влияет только на значение параметра вашей вершинной функции с [[vertex_id]]
приписывать. Ваша вершинная функция не имеет такого параметра, не говоря уже о его использовании. Вместо этого он использует [[instance_id]]
параметр для индексации в буфере данных вершин. Вы можете прочитать еще один из моих ответов здесь для быстрого ознакомления с вызовами отрисовки и с тем, как они приводят к вызовам вашей функции вершинного шейдера.
Есть несколько способов изменить положение вещей, чтобы нарисовать только половину точек. Вы можете изменить используемый вами розыгрыш:
renderEncoder.drawPrimitives(type: .point,
vertexStart: 0,
vertexCount: 1,
instanceCount: emitter.currentParticles / 2,
baseInstance: emitter.currentParticles / 2)
Это не потребует никаких изменений в вершинном шейдере. Это просто изменяет диапазон значений, подаваемых на instance
параметр. Однако, поскольку это не похоже на случай инстансинга, я рекомендую вам изменить шейдер и ваш вызов отрисовки. Для шейдера переименуйте instance
параметр для vertex
или же vid
и измените его атрибут с [[instance_id]]
в [[vertex_id]]
, Затем измените вызов ничьей на:
renderEncoder.drawPrimitives(type: .point,
vertexStart: emitter.currentParticles / 2,
vertexCount: emitter.currentParticles / 2)
По правде говоря, они в основном ведут себя одинаково в этом случае, но последний лучше отражает то, что вы делаете (и вызов отрисовки проще, что приятно).