Ray marching é um método de renderização que encontra superfícies percorrendo um raio em passos repetidos.
Ele aparece com frequência em renderização procedural porque uma cena pode ser descrita por funções em vez de uma malha armazenada ou um conjunto de equações fechadas de interseção de raios.
A versão mais comum usa um campo de distância sinalizada (SDF, do inglês signed distance field) para escolher o tamanho de cada passo.
Um SDF informa a distância do ponto atual até a superfície mais próxima, com um sinal que indica se o ponto está fora ou dentro da forma.
Se a distância é d, a superfície mais próxima está exatamente a d unidades de distância, então o raio pode avançar nessa quantidade sem ultrapassá-la.
As seções interativas abaixo permanecem em 2D de propósito para que cada ideia geométrica permaneça visível, e a mesma lógica se estende diretamente para cenas 3D. A próxima seção introduz o algoritmo e explica como o sphere tracing usa o campo de distância para escolher cada passo de forma adaptativa; em seguida, a visualização mostra um único raio marchando em direção a um círculo guiado passo a passo por esse campo.
Algoritmo de Ray Marching
O termo ray marching é amplo. Ele se refere a avançar ao longo de um raio em incrementos e verificar a cena repetidamente. A versão mais simples usa um tamanho de passo fixo: avance um pouco, amostre a cena e repita. Isso é fácil de entender, mas pode ser muito ineficiente. Passos pequenos são mais seguros perto de detalhes finos, mas desperdiçam trabalho em espaço vazio; passos grandes são mais rápidos, mas podem pular superfícies.
Em pseudocódigo, o laço central repete quatro passos:
- defina a distância percorrida
t = 0 - amostre a cena em
rayOrigin + rayDir * t - se a amostra estiver próxima o suficiente de uma superfície, registre uma colisão
- caso contrário, adicione a distância de passo escolhida a
t - pare após uma distância máxima ou um número máximo de passos
A versão mais comum em tutoriais de computação gráfica evita a escolha entre passo fixo grande ou pequeno usando sphere tracing sobre um campo de distância sinalizada , conforme descrito por John C. Hart em Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces. Um SDF retorna a menor distância de um ponto até a superfície mais próxima, com um sinal que indica se o ponto está fora (positivo), sobre a superfície (zero) ou dentro da forma (negativo).
Se o campo é preciso, um valor de significa que não há nenhuma superfície mais próxima do que aquela distância a partir do ponto de amostragem . Isso permite que o raio avance exatamente sem ultrapassar a superfície mais próxima. Em vez de escolher um tamanho de passo fixo para todo o raio, o próprio campo decide quão longe o raio pode se mover com segurança a seguir. A eficiência vem de dar passos largos e seguros através do espaço vazio enquanto os passos encolhem automaticamente perto das superfícies: a próxima seção demonstra isso passo a passo.
Percorrendo um Campo de Distância
Um círculo simples torna a marcha visível em detalhes. Para um círculo com centro e raio , o campo de distância sinalizada é:
A norma é a distância do ponto de amostragem até o centro do círculo. Subtrair o raio desloca essa distância de modo que a fronteira tenha valor zero, pontos externos tenham valores positivos e pontos internos tenham valores negativos.
Distance-Guided Stepping
Drag the circle or the ray arrow to see how the marcher advances by safe distances.
Na visualização, cada anel roxo é a distância retornada no ponto de amostragem atual. Como o anel toca a superfície mais próxima mas não a cruza, o raio pode se mover até a borda desse anel com segurança. Quando o raio aponta diretamente para o círculo, a distância retornada diminui rapidamente e os passos convergem para a fronteira. Quando o raio aponta para longe, as distâncias podem crescer e o algoritmo termina sem colisão.
Isso é o sphere tracing: o raio avança pela distância que o campo retorna, reavalia e repete até alcançar uma superfície ou desistir. A regra de atualização é simplesmente:
onde é a direção do raio. O tamanho do passo não é arbitrário; ele vem da geometria do próprio campo. É isso que diferencia o ray marching com SDF do marching ingênuo com passo fixo.
Em um shader, você normalmente para quando uma de três condições ocorre:
- a distância cai abaixo de um pequeno limiar de colisão, como
0.001 - a distância total percorrida excede um alcance máximo
- o laço atinge um número máximo de passos
Todos os três limites são importantes. O limiar de colisão controla a precisão, o alcance máximo delimita o trabalho para raios que erram o alvo, e o limite de passos protege contra casos patológicos ou estimadores de distância mal comportados. O limite de passos é especialmente importante para raios que roçam superfícies em ângulos rasantes , onde a distância perpendicular muda lentamente conforme o raio avança e o sphere tracing pode consumir centenas de passos para um único raio antes de convergir.
Construindo uma Cena com SDF
Um único círculo é útil para a intuição, mas o ray marching se torna poderoso quando uma cena inteira pode ser descrita como uma única função de distância. Você faz isso combinando SDFs primitivos em um único campo combinado, seguindo a abordagem de Iñigo Quilez em Distance Functions. Em 2D, um círculo é a distância até um centro menos o raio. Uma linha ou plano pode representar um chão. Para combiná-los, você normalmente usa a distância mínima entre todos os objetos, pois a superfície mais próxima controla o próximo passo seguro.
2D Ray Marching Scene
Cast a small fan of rays through circles and a ground line to see how the minimum SDF controls every step.
No explorador de cena, cada raio consulta repetidamente o mínimo entre as distâncias dos círculos e a distância do chão. Esse mínimo é importante por uma razão simples: se um objeto está próximo e outro está distante, o próximo define o maior passo seguro. Usar a distância maior errada poderia saltar sobre a superfície mais próxima.
Essa regra do “mínimo das primitivas” é a base da modelagem SDF construtiva . Um shader não precisa de malhas de triângulos para descrever a cena. Ele precisa apenas de uma função que responda: “a que distância estou da superfície mais próxima agora?”
Por Que o Método Converge
Uma dúvida comum de iniciantes é por que o sphere tracing não salta sobre geometrias finas. A resposta é que ele depende de uma estimativa conservadora de distância. Se o SDF é exato, o valor retornado é um limite inferior garantido para a distância real até a superfície mais próxima, portanto o próximo passo termina sobre ou antes da superfície possível mais próxima, nunca além dela.
Essa garantia se enfraquece quando a função é apenas um estimador de distância em vez de um campo de distância sinalizada perfeito. A renderização de fractais é um exemplo clássico: o estimador pode funcionar, mas a segurança do passo depende do quão conservador é esse estimador. Para mais informações sobre qualidade do campo e quando a garantia de distância exata se mantém, veja a discussão sobre qualidade do campo no artigo sobre campos de distância sinalizada.
Normais SDF e Sombreado
Malhas rasterizadas normalmente armazenam normais de vértices ou as derivam dos triângulos. Uma superfície SDF percorrida por ray marching não tem malha explícita, então a normal precisa vir do próprio campo. A abordagem é estimar o gradiente do SDF amostrando o campo em pequenos deslocamentos: se a amostra da direita está mais distante fora do objeto do que a amostra da esquerda, a superfície se inclina para a direita, e o mesmo para cima e para baixo. Normalizar esse vetor gradiente fornece uma normal de superfície utilizável.
A visualização sobrepõe setas de gradiente no mapa de calor do SDF. Cada seta aponta na direção de em sua localização, irradiando para fora a partir da superfície mais próxima, independentemente da forma. Passe o cursor sobre o campo e uma sonda aparece mostrando a distância com sinal, a direção do gradiente e a magnitude do gradiente naquele ponto exato. A leitura rotula a seta como normal de superfície sempre que o cursor estiver próximo ao contorno zero, tornando explícita a relação entre gradiente e normal. Clique para fixar a sonda no lugar e alterne entre círculo, caixa, caixa arredondada, segmento de linha e uma união composta de dois círculos para confirmar que as normais emergem da estrutura do campo da mesma forma em todas as formas.
O gradiente é estimado numericamente usando diferenças finitas: o estêncil mostra os pontos de amostragem ao longo de cada eixo, cada um rotulado com o valor de distância amostrado ali. Arraste o controle de para ver o equilíbrio entre gradientes ruidosos com espaçamento muito pequeno e direções suavizadas em excesso com espaçamento grande. Esta é uma das ideias mais úteis na renderização com SDF: o mesmo campo que guia a interseção também fornece uma maneira de sombrear a superfície resultante.
Laço Típico de Shader
Uma versão de shader de fragmento normalmente se parece conceitualmente com isto:
- construa um raio de câmera para o pixel atual
- defina
t = 0 - avalie
sceneSdf(rayOrigin + rayDir * t) - se a distância estiver abaixo de
epsilon, registre uma colisão - caso contrário, aumente
tpor essa distância e continue - se o laço terminar sem colisão, desenhe o fundo
- se ocorrer uma colisão, estime uma normal e calcule a iluminação
O laço é simples, mas os detalhes ao redor determinam a qualidade da imagem. A configuração da câmera afeta distorção e composição. O limiar epsilon afeta bandeamento e artefatos de auto-sombreamento. O número máximo de passos determina se raios rasantes terminam de forma limpa. A qualidade da iluminação depende da estimativa de normais, sombras, termos ambientes, reflexos e do modelo de material que você construir em seguida.
Vantagens e Compensações
Ray marching é atraente porque torna a geometria procedural excepcionalmente direta.
Uma primitiva é apenas uma fórmula.
A combinação de cena é frequentemente algumas operações de min e max.
Blendagens suaves, repetições, torções e deformações baseadas em ruído podem muitas vezes ser expressas analiticamente sem reconstruir a topologia da malha.
É por isso que a técnica se tornou popular na arte de shaders, na produção demoscene e em experimentos de renderização procedural.
As compensações são igualmente reais:
- cada pixel pode exigir muitas avaliações de cena
- características finas ou altamente detalhadas podem precisar de muitos passos ou limiares cuidadosos
- sombras suaves, oclusão de ambiente e reflexos adicionam ainda mais marchas
- estimadores de distância que não são conservadores podem causar erros ou artefatos
- cenas grandes precisam de aceleração cuidadosa ou design de domínio para se manterem rápidas
Portanto, ray marching não é um substituto universal para rasterização ou tracing de triângulos por hardware. Ele é melhor compreendido como uma ferramenta poderosa de renderização procedural com um ponto forte específico: quando a geometria é mais fácil de definir como um campo do que como uma malha, em contraste com o pipeline de rasterização padrão descrito em shaders de vértice vs shaders de fragmento no pipeline gráfico . Para uma comparação detalhada lado a lado de desempenho, qualidade, representação de cena e casos de uso, veja ray marching vs ray tracing .
Extensões Comuns
Uma vez que a colisão do raio primário funciona, muitos efeitos clássicos são construídos sobre o mesmo mecanismo. Raios de sombra marcham da superfície em direção à luz. Oclusão de ambiente amostra a rapidez com que a geometria próxima aparece ao longo da direção normal. Reflexos geram outro raio a partir do ponto de colisão. Quando famílias de raios refletidos ou refratados se aglomeram em vez de se espalharem uniformemente, a mesma intuição de roteamento de raios leva a caustics pela concentração de luz . Efeitos de névoa e volumétricos acumulam contribuições à medida que o raio viaja. Cada um reutiliza o mesmo padrão central de avaliação repetida da cena, e muitos se tornam visualmente mais úteis quando você modula formas ou materiais com ruído de valor, ruído de Perlin e ruído fractal .
Essa reutilização é uma das razões pelas quais o ray marching é tão ensinável. O renderizador permanece conceitualmente consistente mesmo quando você adiciona mais funcionalidades. Você continua perguntando à cena por informações de distância e usando essas informações para decidir o quão longe se mover em seguida. A complexidade cresce, mas o modelo mental subjacente não muda.
Resumo
Ray marching com campos de distância sinalizada funciona porque a cena diz a cada raio o quão longe ele pode se mover com segurança. Isso transforma a interseção em um processo iterativo guiado pela geometria, em vez de incrementos fixos. Se você mantiver quatro ideias em mente, a técnica se torna muito mais fácil de compreender:
- um SDF retorna a distância até a superfície mais próxima com um sinal
- a distância mínima na cena determina o próximo passo seguro
- passos seguros repetidos convergem para a superfície quando o campo é conservador
- o gradiente do campo fornece uma normal utilizável para iluminação
Essas quatro peças são o núcleo da maioria dos renderizadores introdutórios com shaders SDF. Depois disso, o trabalho é principalmente engenharia: escolher limiares, otimizar a avaliação da cena e adicionar camadas de iluminação ou efeitos secundários por cima.