É possível descobrir quantos fragmentos passaram pelo teste de estêncil?


11

Eu tenho um aplicativo OpenGL que usa testes de estêncil bastante para renderizar formas irregulares (um pouco como um simples CSG 2-D ). Se eu descobrisse quantos fragmentos passaram no teste de estêncil e foram realmente renderizados, isso seria muito útil para simplificar alguns cálculos na linha. Especificamente, me permitiria determinar a área da forma renderizada de graça, em vez de precisar aproximá-la com uma simulação de Monte Carlo posteriormente.

Eu sei que existe um conceito semelhante para primitivas emitidas a partir do shader de geometria, chamado feedback de transformação . Gostaria de saber se existe um conceito semelhante para fragmentos e para o teste de estêncil.


Uma solução grosseira seria pintar uma cor contrastante em outra através do estêncil, salvar esse buffer e contar o número de pixels que foram alterados.
TheBuzzSaw

Hmm, a especificação diz que as consultas de ocultação contam o número de fragmentos que passam no teste de profundidade , mas no topo da minha cabeça não tenho certeza de como isso interage com o teste de estêncil agora.
Chris diz Reinstate Monica

@ChristianRau Parece que apenas os fragmentos que passarem nos testes de profundidade serão contados, mas os testes de estêncil, descarte e alfa são ignorados.
Maurice Laveaux

2
@ChristianRau e Maurice, a especificação ARB_occlusion_query original diz explicitamente que conta amostras que passam nos testes de profundidade e estêncil. Veja também esta pergunta StackOverflow .
Nathan Reed

@NathanReed Parece que você está prestes a escrever uma resposta.
Chris diz Reinstate Monica

Respostas:


10

Uma abordagem possível poderia ser o uso da consulta de oclusão de hardware.

Você pode usar os fatos de que, por especificação, o Teste de Estêncil é executado antes do teste de profundidade, e apenas os fragmentos que passam no teste de profundidade são contados pela Consulta de Oclusão.

Um exemplo simples (não testado) seria como:

    GLuint samples_query = 0;
    GLuint samples_passed = 0;
    glGenQueries(1, &samples_query);
    // Initialize your buffers and textures ...
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);

    // Set up the values on the stencil buffer ...

    // Now we count the fragments that pass the stencil test
    glDepthFunc(GL_ALWAYS); // Set up the depth test to always pass
    glBeginQuery(GL_SAMPLES_PASSED, samples_query);
    // Render your meshes here
    glEndQuery(GL_SAMPLES_PASSED);
    glGetQueryObjectuiv(samples_query, GL_QUERY_RESULT, &samples_passed);
    // samples_passed holds the number of fragments that passed the stencil test (if any)

    // Release your resources ...
    glDeleteQueries(1, &samples_query);

Observe que a chamada para obter o número de amostras chamará forçosamente a liberação do pipeline e aguardará a conclusão da consulta. Se você precisar de uma abordagem mais assíncrona, poderá consultar se a consulta de oclusão foi feita ou não usando:

    GLuint query_done = 0;
    glGetQueryObjectuiv(samples_query, GL_QUERY_RESULT_AVAILABLE, &query_done);
    if (query_done != 0)
        // Your query result is ready
    else
        // Maybe check the next frame?

2

Se você estiver interessado na área, poderá reduzir o tamanho do buffer de estêncil até atingir um pixel e deduzir essa área de sua cor.

Os passos seriam:

  • Copie o estêncil para uma textura, usando um formato com precisão suficiente.
  • Carregue um sombreador que produza uma cor proporcional ao número de texels com uma determinada cor.
  • Pingue-pongue entre os framebuffers para reduzir o tamanho pela metade até atingir um pixel.
  • A cor do pixel é a porcentagem da viewport coberta pela área: basta multiplicá-la pela área da viewport.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.