OpenGL obtém o esboço de vários objetos sobrepostos


10

Eu só tive uma idéia para o meu jogo em andamento feito com opengl em c ++: eu gostaria de ter um grande contorno (5-6 pixels) em vários objetos sobrepostos quando o jogador ganhar alguma coisa.

Eu pensei que a melhor maneira é usar o buffer de estêncil, mas são poucas horas que estou tentando fazer uma renderização fora da tela do buffer de estêncil e não consigo obter nenhum tipo de resultado tão probab. existem outras técnicas!

Isto é o que eu quero obter:

insira a descrição da imagem aqui

Alguma ideia?


Use um filtro de detecção de arestas, preencha as arestas com linhas coloridas grossas e extraia as imagens renderizadas das formas e sobreponha-as sobre a camada de linhas coloridas?
Shotgun Ninja

o que você quer dizer com um filtro de detecção de borda? um shader? um filtro de processamento de imagem? como opencv (renderize para textura, aplique filtro na textura, empurre a textura modificada)?
Nkint

Eu não faço ideia; Não sou muito versado em renderização em 3D para começar.
Shotgun Ninja

você tem algum exemplo de um buffer de estêncil como este? Acho que usando o buffer estêncil seria a maneira mais limpa, mas eu não sou capaz de fazer qualquer trabalho stencil buffer
nkint

Respostas:


4
  1. Habilite e limpe o buffer de estêncil.
  2. Desenhe os objetos, configurando o buffer de estêncil. Os objetos podem ser semi-transparentes etc.
  3. Agora defina o modo de estêncil para gravar apenas pixels onde o estêncil não está definido.
  4. E desenhe cada objeto novamente, ligeiramente ampliado, na cor da borda desejada e sem texturas.
  5. Desative o buffer de estêncil.

Aqui está o código adaptado de algum código de estêncil do webGL que eu estou trabalhando:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

Acho que usei essa abordagem nos jogos RTS para desenhar halos em torno de unidades selecionadas, mas isso foi há muito tempo e não me lembro se existem truques e todas as nuances.


você tem algum exemplo de um buffer de estêncil como este? Acho que usando o buffer estêncil seria a maneira mais limpa, mas eu não sou capaz de fazer qualquer trabalho stencil buffer
nkint

7
Observe que a renderização de objetos levemente dimensionados não resultará em uma espessura de linha uniforme. As arestas mais distantes serão mais finas. Se você considerar isso ao dimensionar objetos, objetos longos que se estendem para longe terão espessura não uniforme. Há um pouco mais neste efeito para obter as linhas agradáveis ​​e uniformes.
23813 Sean Middleditch

2
Melhor do que simplesmente aumentar a escala de objetos é escrever um sombreador de vértice que compensa cada vértice a uma curta distância do normal. Isso funciona muito bem para objetos lisos, mas gera rachaduras nas arestas duras. Você pode tentar construir a malha com um conjunto alternativo de normais que são suavizados em todos os lugares e ver onde isso o leva.
22613 Nathan Reed

2

Comece encontrando todos os grupos de objetos, onde um grupo de objetos é uma coleção de objetos que se sobrepõem. A detecção de colisão padrão deve fazer o trabalho. Atribua a cada grupo uma cor única. Qualquer cor serviria.

Renderize todos os seus objetos como cores sólidas, usando a cor do grupo, em uma textura.

Crie uma nova textura de contorno com as mesmas dimensões que o destino de renderização. Examine cada texel do destino de renderização e determine se é uma cor diferente de qualquer texels ao redor. Se for, altere o texel correspondente na textura do contorno para a cor da linha desejada.

Por fim, pegue essa textura de contorno e renderize-a na parte superior da imagem que deseja desenhar na tela (é claro que você pode fazer isso ao mesmo tempo que a detecção de borda em um shader de fragmento e evitar criar a textura de borda no primeiro Lugar, colocar).

Se você executar esta etapa no processador usando um loop for para percorrer os texels do destino de renderização, isso será bem lento, mas provavelmente bom o suficiente para testar e até mesmo usar em alguns casos. Para usar isso em tempo real, seria melhor lidar com isso em um sombreador.

Um shader de fragmento para fazer essa detecção de borda pode se parecer com isso;

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

Onde o segundo valor na consulta texture2D é uma coordenada 2D em relação a v_texCoord. Você aplicaria isso renderizando o primeiro destino de renderização como a textura em um quad de tela cheia. É semelhante a como você aplicaria efeitos de desfoque em tela cheia, como um desfoque guassiano.

O motivo para usar o primeiro destino de renderização com cores sólidas é simplesmente garantir que não haja arestas percebidas entre os diferentes objetos que se sobrepõem. Se você simplesmente executasse a detecção de borda na imagem da tela, provavelmente descobriria que ela também detecta bordas nas sobreposições (assumindo que os objetos tenham cores / texturas / iluminação diferentes).


2
desculpe, mas o que você quer dizer com "Scan through each texel"? um loop for embora cada pixel? na cpu? então é algo como: renderizar com uma cor sólida em uma textura, transferir a imagem para a CPU, fazer a digitalização, colocá-las novamente na textura? ou fazê-lo em um shader?
Nkint

De preferência, faça isso em um sombreador renderizando um quad em tela cheia usando o destino de renderização como textura, de maneira semelhante a um efeito de desfoque pós-processo, mas você pode fazê-lo trabalhar na CPU primeiro com um loop for, apenas para ver se funcionar bem o suficiente.
OriginalDaemon
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.