Рисовать часть MTLBuffer? - PullRequest
0 голосов
/ 26 мая 2019

Я рендеринг фрагментов из буфера с этим вызовом:

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 Ответ

0 голосов
/ 28 мая 2019

Вы не используете ни дескриптор вершины, ни параметр [[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]].Затем измените вызов draw на:

renderEncoder.drawPrimitives(type: .point,
                             vertexStart: emitter.currentParticles / 2,
                             vertexCount: emitter.currentParticles / 2)

По правде говоря, в этом случае они в основном ведут себя одинаково, но последний лучше представляет то, что вы делаете (и вызов draw проще, чтохорошо).

...