Como o Marching Ray de campo à distância assinado é implementado para um mundo dinâmico?

10

Acho que entendo o básico do Marched Ray Fielded Distance Distance. Você modela sua cena com vários campos de distância (como estes: http://iquilezles.org/www/articles/distfunctions/distfunctions.htm ) e, em seguida, para cada pixel que você lança um raio, comece do início do raio , encontre a distância até o objeto mais próximo nesse ponto e aumente o ponto pela distância mais próxima, até atingir alguma coisa. Eu consegui criar um renderizador simples, e é aí que a maioria das descrições da técnica para.

Isso me deixa com algumas perguntas sobre como o SDF Ray Marching pode ser usado em um cenário do mundo real:

Pergunta 1: Em um jogo real, a cena é geralmente complexa e carregada na CPU, com muitos objetos dinâmicos. Entendo o descarte básico de oclusão (como octrees) e, com a renderização poligonal, eu criaria uma lista (na CPU) de itens na exibição de frustrum a ser renderizada.

Então, imagine que eu tenho uma cena muito complexa, com muitos personagens e objetos dinâmicos movendo-se na tela, controlados pela CPU. Como transmitiria os objetos que quero renderizar para a GPU em cada quadro? Todo exemplo tem a cena codificada no GLSL. Alguém pode compartilhar um exemplo do nível que está sendo transmitido para o shader dinamicamente?

Pergunta 2: Como os objetos podem ter várias cores? As funções de distância retornam apenas uma distância, mas como as implementações geralmente devolvem a cor? (por exemplo, você bate em uma esfera vermelha e não em um cubo azul.) Se essa fosse uma implementação de CPU, eu poderia chamar uma função global dentro da função distance quando for um hit para finalizar o ray marcher, e que também pode passar o objeto do hit. textura / cor. Mas como você retornaria a cor ou a textura do item no GLSL?

Obrigado.

Andrew Price
fonte

Respostas:

2

Essa é uma resposta mínima, mas você deseja compartilhar as informações caso não tenha uma resposta melhor.

Em relação à maneira como os jogos reais usam ray marching, eles geralmente não usam. Somente nos últimos dois anos os jogos começaram a usar o raymarching no buffer de profundidade para refletir o espaço da tela, mas nenhum jogo que eu conheça usa o ray marching da maneira que você descreve - ainda?

Para a outra pergunta sobre cores e outras coisas, as pessoas geralmente associam materiais a objetos e usam "coordenadas de textura" do ponto em que o raio atinge o objeto para descobrir as propriedades do material naquele ponto no objeto. Os materiais comuns incluem coisas como cores difusas, intensidade especular, cores emissivas e índice de transparência / refração.

Espero que seja pelo menos alguma ajuda para você! Você também pode obter boas respostas no site de troca da pilha de gráficos.

Alan Wolfe
fonte
2
"nenhum jogo que eu conheço usa ray marching da maneira que você descreve" O próximo jogo da Media Molecule, Dreams, usa campos de distância assinados para esculpir o conteúdo gerado pelo usuário, mas se eu entendi corretamente, os campos são convertidos em uma nuvem de pontos para renderização em vez de sendo marcados diretamente. Este artigo pode ter algumas idéias: dualshockers.com/2015/08/15/…
DMGregory
1
@DMGregory Nice, mas acho que isso não é estritamente Ray Marching. Portanto, o argumento ainda é válido, os jogos geralmente não usam ray marching.
concept3d
1
Atualizando esta discussão - o jogo Claybook , em breve, renderiza suas cenas usando raios disparados diretamente por campos de distância , em vez de convertê-los primeiro em geometria convencional. Então o "ainda?" parece ter sido confirmado dois anos depois. :)
DMGregory
1

Atualmente, estou desenvolvendo um mecanismo de jogo que utiliza campos de distância assinados como uma técnica de renderização para exibir geometria processual suave (gerada com primitivas simples como as do seu link no momento, procurando implementar os fractais Julia e IFS no futuro). Como meu mecanismo está focado na geração de procedimentos e deve definir figuras de maneira a torná-las amigáveis ​​aos marcadores de raios, acho que estou em um bom lugar para responder a essa pergunta: P.

Em relação ao streaming, a solução simples é usar um tipo de buffer de algum tipo e jogá-lo na GPU quando você quiser fazer a marcação de raios. Cada elemento do buffer é um tipo complexo (por exemplo, uma estrutura em C / C ++), e cada tipo contém elementos que definem qual função você deve usar para representá-lo, sua posição, rotação, escala, etc. e uma cor média. O processo simplifica até:

  1. Escolha sua cena em um subconjunto gerenciável (observe que a seleção de frustum e a seleção de oclusão são parcialmente realizadas automaticamente pelo algoritmo de marcação de raios)
  2. Passe o subconjunto para o buffer de entrada de renderização
  3. Passe o buffer para a GPU, se ainda não estiver lá, e depois renderize sua cena com a marcha tradicional tradicional. Você precisará executar algum tipo de pesquisa por etapa para avaliar qual item do buffer de entrada é o mais próximo de cada raio para cada iteração do marcador de raios e aplicar transformações nos raios (nesse caso, você precisará inverter as rotações das figuras antes que elas atinjam a GPU) ou as próprias funções de distância (mover a origem da função para alterações de posição, ajustando, por exemplo, comprimentos laterais cúbicos para alterações de escala, etc.) A abordagem mais simples é modificar os raios antes você os passa para a função de distância do núcleo real.

Em relação às cores das figuras, lembre-se de que os sombreadores permitem definir tipos complexos e primitivos;). Isso permite que você jogue tudo em uma estrutura no estilo C e passe essas estruturas de volta da sua função de distância.

No meu mecanismo, cada estrutura contém uma distância, uma cor e um ID que o vincula à definição de figura correspondente no buffer de entrada. Cada ID é deduzido do contexto circundante da função de distância relevante (como minha função de mapeamento percorre o buffer de entrada para encontrar a figura mais próxima de cada raio para cada etapa, posso tratar com segurança o valor do contador de loop quando cada SDF é chamado como o ID da figura para essa função), enquanto os valores de distância são definidos usando um SDF principal arbitrário (por exemplo,point - figure.pos para uma esfera) e as cores são definidas a partir da cor média do elemento apropriado no buffer de figuras (por isso, é útil manter os IDs das figuras por aí) ou através de uma cor de procedimento ponderada em relação à média armazenada (um exemplo pode estar ocorrendo uma contagem de iteração para algum ponto no Mandelbulb, mapeando sua "cor média" do espaço de cores FP para o espaço de cores inteiro e, em seguida, usando a cor mapeada como uma paleta, usando XOR para a contagem de iterações).

Texturas procedurais são outra abordagem, mas eu nunca as usei. O iq fez muita pesquisa nessa área e publicou algumas demonstrações interessantes em Shadertoy, de modo que essa pode ser uma maneira de reunir algumas informações extras.

Independentemente de sua cor é estático para cada figura, processualmente gerado, ou magicamente amostrados de uma textura processual, a lógica básica é a mesma: Figuras abstratas em algum tipo de tipo complexo intermediário (por exemplo, um struct), armazenar tanto distância locais e locais color em uma instância desse tipo, depois passe o tipo complexo como um valor de retorno da sua função de distância. Dependendo da sua implementação, a cor de saída pode passar diretamente para a tela ou seguir o ponto de colisão no seu código de iluminação.

Não sei se o exposto foi claro o suficiente ou não, então não se preocupe em perguntar se algo não faz sentido. Eu realmente não posso fornecer nenhum exemplo de código GLSL / pixel-shading, pois estou trabalhando com HLSL e computar sombreamento, mas estou feliz em tentar revisar qualquer coisa que não tenha escrito corretamente em primeiro lugar :).

Paul Ferris
fonte