Tentando usar estênceis em 2D, mantendo a profundidade da camada

7

Esta é uma tela do que está acontecendo apenas para que você possa obter um quadro de referência.

insira a descrição da imagem aqui

O problema que estou enfrentando é que meu jogo está desacelerando devido à quantidade de trocas de textura que estou fazendo durante minha chamada de empate. Como paredes, caracteres, pisos e todos os objetos estão em suas respectivas folhas de sprite que contêm esses tipos, por desenho de ladrilho, a textura carregada é trocada não menos de 3 a 5 ou mais vezes, enquanto ele alterna e desenha os sprites para que sejam estratificados adequadamente.

Agora, tentei juntar todos os objetos comuns em suas respectivas listas e, em seguida, usando o layerDepth, desenhando-os dessa maneira, o que melhora as coisas, mas o novo problema em que estou lidando tem a ver com a maneira como minhas portas / janelas são desenhados nas paredes. Ou seja, eu estava usando estênceis para limpar um bloco nas paredes desenhadas no formato da porta / janela, para que, quando a parede fosse desenhada, tivesse um buraco do tamanho de uma porta / janela.

Foi assim que meu desenho foi criado para paredes quando eu estava passando lado a lado em vez de agrupar objetos comuns.

  1. primeiro, verificaria se havia uma porta / janela nessa parede. Caso contrário, pularia todas as etapas e desenharia normalmente. De outra forma
  2. finalizar o spriteBatch atual
  3. Limpe os buffers com uma cor transparente para preservar o que já foi desenhado
  4. iniciar um novo spritebatch com configurações de estêncil
  5. desenhe a área da porta
  6. terminar o spriteBatch
  7. inicie um novo spritebatch que leve em consideração o estêncil definido anteriormente
  8. desenhe a parede que agora será desenhada com um buraco
  9. terminar esse spritebatch
  10. inicie um novo spritebatch com as configurações normais para continuar desenhando blocos

No desenho lado a lado, limpar os buffers de profundidade / estêncil não importava, pois eu não estava usando nenhuma layerDepth para organizar o que desenha sobre o que.

Agora que estou desenhando a partir de listas de objetos comuns, em vez de lado a lado, acelerou consideravelmente minha chamada, mas não consigo descobrir uma maneira de manter o sistema de estêncil para mascarar a área de uma porta ou janela será atraído para uma parede. A raiz do problema é que, quando eu finalizo um spriteBatch para alterar o DepthStencilState, ele nivela o RenderTarget atual e não há mais nenhuma classificação de profundidade para qualquer coisa desenhada mais abaixo na linha. Isso significa que as paredes sempre são desenhadas em cima de tudo, independentemente da profundidade ou do posicionamento no mundo do jogo e até uma em cima da outra, pois o estêncil precisa acontecer uma vez para cada parede que tem uma porta ou janela.

Alguém sabe uma maneira de contornar isso? Para resumir, eu preciso de uma maneira de desenhar, classificando as coisas pela profundidade da camada, além de poder estêncil / mascarar partes de sprites específicos.

Steve
fonte
Não sei o suficiente sobre o XNA para postar uma resposta real, mas isso parece suspeito: "quando encerro um spriteBatch ... nivela o RenderTarget atual e não há mais nenhuma classificação de profundidade". Isso não deveria estar acontecendo se os sprites estiverem sendo atraídos para o buffer de profundidade (suponho que seja isso que "layerDepth" faz); alterar o estado do estêncil de profundidade não precisa limpar o buffer de profundidade. Portanto, pode valer a pena investigar se existe uma maneira de mudar esse comportamento.
Nathan Reed
Quando você diz "iniciar um novo spritebatch", não quer dizer que esteja criando uma nova instância do SpriteBatch, não é? Criar um novo lote toda vez que você desenha algo atrasaria bastante o seu jogo.
Mike Cluck

Respostas:

1

Não conheço XNA suficiente para lhe dar uma solução adequada, mas posso lhe dar uma resposta geral.

O problema que você está tendo é o algoritmo do pintor . Especificamente, você precisa solicitar todas as coisas que deseja desenhar antes de poder desenhá-las. A maneira mais comum de evitar esse problema é com um buffer de profundidade. Curiosamente, isso também é chamado de buffer z, porque armazena os valores z no espaço da câmera.

No entanto, como você não possui Z (porque está escrevendo um jogo em 2D), não pode usar esta técnica. Ou você pode?

Considere o seguinte: uma projeção ortográfica não altera a perspectiva dos pontos nos pontos 3D. Isso é útil para itens como elementos da interface do usuário, porque você sempre deseja que eles sejam da mesma maneira.

O que eu sugiro é que você escreva um shader personalizado que use matrizes 3D e um valor de profundidade por vértice. Esse valor de profundidade deve ser usado para buffer de profundidade, mas não para projeção.

No pseudo-shadercode:

[vertex shader]
pos_output = TransformOrthographic * TransformView * vec3(pos_vertex.x, pos_vertex.y, 0.0);
depth_output = depth_vertex;

[fragment shader]
depth_output = (depth_input - depth_min) / (depth_max - depth_min);

Depois de configurá-lo, você pode parar de se preocupar com a renderização dos objetos na ordem errada e, em vez disso, definir o valor da profundidade.

Agora você deve poder renderizar tudo em uma chamada de empate, sem se preocupar em criar seções da tela.

knight666
fonte