Gráfico de cena para o mecanismo de renderização adiada

10

Como exercício de aprendizado, escrevi um mecanismo de renderização diferida. Agora eu gostaria de adicionar um gráfico de cena a esse mecanismo, mas estou um pouco confuso sobre como fazer isso.

Em um normal (mecanismo de renderização direta), basta adicionar todos os itens (Todos implementando IDrawable e IUpdateAble) ao meu gráfico de cena, do que percorrer primeiro a largura do gráfico de cena e chamar Draw () em todos os lugares.

No entanto, em um mecanismo de renderização diferida, tenho que separar as chamadas de draw. Primeiro tenho que desenhar a geometria, depois os lançadores de sombras e depois as luzes (todas para diferentes alvos de renderização), antes de combinar todas elas. Portanto, neste caso, não posso simplesmente percorrer o gráfico da cena e apenas chamar draw. Do jeito que eu vejo, eu tenho que percorrer o gráfico de cena inteiro três vezes, verificando que tipo de objeto é esse que precisa ser desenhado ou preciso criar três gráficos de cena separados que, de alguma forma, estão conectados um ao outro. Ambas parecem soluções ruins, eu gostaria de lidar com objetos de cena mais transparentes.

Uma outra solução que pensei em viajar pelo gráfico de cena como normal e adicionar itens a 3 listas separadas, separando geometria, rodízios de sombras e luzes, e depois iterando essas listas para desenhar as coisas corretas, é melhor e é isso? sábio repovoar 3 listas de cada quadro?

Roy T.
fonte

Respostas:

6

Uma abordagem que usei em um projeto C ++ é que o gráfico de cena (que possui o índice espacial) preenche um vetor std :: vetor 'visível' de hits com base no perfil de visualização atual. Essa lista visível é gerenciada pelo gráfico de cena e só é recalculada quando a câmera se move - objetos em movimento no gráfico são movidos nessa lista e usando lápides e listas de alterações não ordenadas que são classificadas e mescladas de acordo com a necessidade.

A lista de itens visíveis é classificada primeiro pela ID do sombreador e dentro de cada tipo pela distância da câmera. Os IDs do sombreador são atribuídos de modo que o terreno classifique primeiro e depois os edifícios e, em seguida, as unidades e, em seguida, projéteis e, em seguida, partículas e assim por diante - sendo um RTS. Alguns modelos têm mais de um sombreador, mas eles apenas anunciam seu sombreador principal. Quando são solicitados a desenhar, aqueles que precisam de bits desenhados com outro sombreador também se adicionam a uma lista vinculada da próxima passagem.

Assim, o desenho passa pela matriz visível em uma passagem e, nessa passagem, é criada uma lista vinculada dos itens a serem revisitados e eles são desenhados uma segunda passagem e assim por diante.

Desenhar frente e verso e opaco e depois transparente ajuda a manter tudo em ordem.

Talvez isso não esteja minimizando o número de alterações no shader, etc., mas é bastante viável e simples de implementar.

Não tenho idéia do XNA, e como isso é aplicável e quanto de coisas de baixo nível que você cria, eu tenho medo. Seria mais interessante saber o que os veteranos pensam dessa abordagem para os CTS RTSes.

Vai
fonte
Hey Will, eu realmente gosto desta resposta, especialmente porque é totalmente diferente do que eu pensei até agora. Seu método parece muito sensato, especialmente quando se pensa em objetos semitransparentes (que eu quase sempre evitei até agora). Construir uma lista (vinculada) a partir do gráfico da cena para objetos a visitar parece uma ótima idéia. E sim no XNA, temos que fazer todas essas coisas de baixo nível também :).
Roy T.
3

Minha sugestão seria uma abordagem em duas etapas, adaptada aos seus requisitos específicos, semelhante ao que você se descreveu. Você precisa de um gráfico de cena e uma "coleção de renderização" para cada uma das etapas de renderização, no seu caso sombra, geometria, luzes (talvez uma quarta seja objetos transparentes?)

O gráfico da cena pode ser baseado em qualquer tipo de relacionamento, mas minha preferência pessoal seria baseada em relacionamentos espaciais, em que cada nó pode conter os outros nós para facilitar a seleção rápida.

As coleções de renderização podem ser qualquer tipo de estrutura de dados adaptada à etapa específica. Por exemplo, a coleção de sombras pode ser uma lista ou árvore classificada por profundidade para maximizar a rejeição inicial de z. A coleção de geometria pode ser classificada pelo uso do sombreador para minimizar as alterações do estado do sombreador. A coleção de luzes pode ser uma lista ou árvore classificada pela distância da luz, tamanho ou uma combinação dessas, para que você possa limitar a renderização da luz apenas às luzes mais eficazes se o desempenho for um problema.

Quaisquer que sejam as estruturas de dados que você escolher, verifique se a operação de inserção é rápida e use técnicas de pool e outras para eliminar qualquer alocação / destruição de dados, porque você estará limpando e preenchendo essas listas a cada quadro.

Agora, juntar tudo é fácil. Basta percorrer o gráfico da cena e adicionar cada item às coleções de renderizações relevantes. Ajuda se sua estrutura de dados classifica / estrutura automaticamente novas entradas com base nos requisitos. Quando terminar, percorra as coleções de renderizações na ordem necessária e as renderize.

Como suas estruturas de dados têm inserção rápida e não geram lixo, não há penalidade por repovoar listas como você mencionou.

Mart
fonte