Como o Anti Aliasing é implementado no Ray Tracing?


12

Depois de ler alguns artigos on-line, posso dizer com confiança que não tenho noção de como o Anti-Aliasing funciona quando o Ray Tracing .

Tudo o que entendo é que um único pixel / raio é dividido em 4 sub-pixels e 4 raios em vez de 1 .

Alguém poderia explicar como isso é feito (de preferência com código)?


2
Posso apenas sugerir que você veja "supersampling" en.wikipedia.org/wiki/Supersampling e talvez também en.wikipedia.org/wiki/Distributed_ray_tracing ?
— Simon F

2
Também posso recomendar a leitura deste capítulo do PBRT pbrt.org/chapters/pbrt_chapter7.pdf e a leitura deste artigo lgdv.cs.fau.de/get/785 (que explica uma técnica diferente daquela implementada no pbrt).
— Tom van Bussel

1
foreach pixel : p{acc = 0; foreach subsample : s { acc+=sample_scene(s);} store(p, acc);}
— catraca aberração

Respostas:


11

Eu acho que é seguro dizer que existem duas maneiras diferentes de fazer AA no raytracing:

1: se você tiver a imagem final e a imagem em profundidade, é possível aplicar quase todas as técnicas existentes usadas em jogos (FXAA, etc.). Essas trabalham diretamente na imagem final e não estão relacionadas ao raytracing.

2: o segundo método é levar em consideração vários raios para cada pixel e calcular a média do resultado. Para uma versão muito simples, pense assim:

  • você renderiza primeiro uma imagem de tamanho 1024x1024, um raio para cada pixel (por exemplo)
  • após a renderização, você redimensiona a imagem para 512x512 (cada 4 pixels são redimensionados em um) e pode observar que as bordas são mais suaves. Dessa forma, você usou efetivamente 4 raios para cada pixel na imagem final do tamanho de 512x512.

Existem outras variações nesse método. Por exemplo, você pode adaptar o número de amostras de pixels que estão exatamente na borda da geometria, o que significa que, para alguns pixels, você terá apenas 4 amostras e para outras 16.

Verifique os links nos comentários acima.


Então, basicamente, eu renderizo uma imagem para um tamanho grande e, ao salvá-la em uma imagem, reduzi-la para um tamanho menor? Isso parece bastante simples :)! Esse é o método de super amostragem?
— Arjan Singh

1
@ Arjan Singh sim é en.wikipedia.org/wiki/Supersampling , mas este é o mais lento de todos eles, raytracing permite que você facilmente fazer supersampling adaptativa, que pode realizar muito melhor
— Raxvan

12

Raxvan está completamente certo de que as técnicas "tradicionais" de anti-aliasing funcionarão no raytracing, incluindo aquelas que usam informações como profundidade para executar o antialiasing. Você pode até fazer anti-aliasing temporal no traçado de raios, por exemplo.

Julien expandiu o segundo item de Raxvan, que era uma explicação da super amostragem, e mostrou como você realmente faria isso, mencionando também que você pode aleatoriamente a localização das amostras dentro do pixel, mas então você está inserindo o país de processamento de sinal, que é muito mais profundo, e definitivamente é!

NN

Se você fizer isso, ainda poderá obter o aliasing. É melhor do que NÃO fazê-lo, porque você está aumentando sua taxa de amostragem; portanto, será capaz de lidar com dados de frequência mais alta (também conhecidos como detalhes menores), mas ainda pode causar aliases.

N

Quando você usa apenas números aleatórios "regulares" como os obtidos com rand () ou std :: uniform_int_distribution, isso é chamado de "ruído branco" porque contém todas as frequências, como a luz branca é composta por todas as outras cores (frequências ) de luz.

O uso de ruído branco para aleatorizar as amostras em um pixel tem o problema de que algumas vezes suas amostras se agrupam. Por exemplo, se você calcula a média de 100 amostras em um pixel, mas TODAS elas acabam no canto superior esquerdo do pixel, você não obtém QUALQUER informação sobre as outras partes do pixel, portanto, a cor final do pixel resultante faltam informações sobre qual cor deve ser.

Uma abordagem melhor é usar algo chamado ruído azul, que contém apenas componentes de alta frequência (como a luz azul é a luz de alta frequência).

O benefício do ruído azul é que você obtém uma cobertura uniforme sobre o pixel, como em uma grade de amostragem uniforme, mas ainda obtém alguma aleatoriedade, que transforma o aliasing em ruído e oferece uma imagem com melhor aparência.

Infelizmente, o ruído azul pode ser muito caro para calcular, e os melhores métodos parecem todos patenteados (que diabos ?!), mas uma maneira de fazer isso, inventada pela pixar (e patenteada também, eu acho, mas não 100% certa) é criar uma grade uniforme de pontos de amostra e, em seguida, deslocar aleatoriamente cada ponto de amostra em uma pequena quantidade - como uma quantidade aleatória entre mais ou menos metade da largura e altura da grade de amostragem. Dessa forma, você obtém uma espécie de amostragem de ruído azul por muito barato.

Observe que esta é uma forma de amostragem estratificada e a amostragem de disco de poisson também é uma forma de gerar ruído azul: https://www.jasondavies.com/poisson-disc/

Se você estiver interessado em ir mais fundo, provavelmente também desejará conferir esta pergunta e responder!

Qual é o raciocínio fundamental para o anti-aliasing usando várias amostras aleatórias em um pixel?

Por fim, esse material está começando a se desviar para o domínio do rastreamento de caminhos de monte carlo, que é o método comum para fazer o rastreamento de raios fotorrealista. se você estiver interessado em aprender mais sobre isso, leia isso!

http://blog.demofox.org/2016/09/21/path-tracing-getting-started-with-diffuse-and-emissive/


7

Vamos supor um loop principal do raytracing bastante típico:

struct Ray
{
    vec3 origin;
    vec3 direction;
};

RGBColor* image = CreateImageBuffer(width, height);

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        float x = 2.0 * (float)i / (float)max(width, height) - 1.0;
        float y = 2.0 * (float)j / (float)max(width, height) - 1.0;

        vec3 dir = normalize(vec3(x, y, -tanHalfFov));
        Ray r = { cameraPosition, dir };

        image[width * j + i] = ComputeColor(r);
    }
}

Uma possível modificação para fazer 4 amostras do MSAA seria:

float jitterMatrix[4 * 2] = {
    -1.0/4.0,  3.0/4.0,
     3.0/4.0,  1.0/3.0,
    -3.0/4.0, -1.0/4.0,
     1.0/4.0, -3.0/4.0,
};

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        // Init the pixel to 100% black (no light).
        image[width * j + i] = RGBColor(0.0);

        // Accumulate light for N samples.
        for (int sample = 0; sample < 4; ++sample)
        {
            float x = 2.0 * (i + jitterMatrix[2*sample]) / (float)max(width, height) - 1.0;
            float y = 2.0 * (i + jitterMatrix[2*sample+1]) / (float)max(width, height) - 1.0;

            vec3 dir = normalize(vec3(x, y, -tanHalfFov) + jitter);
            Ray r = { cameraPosition, dir };

            image[width * j + i] += ComputeColor(r);
        }

        // Get the average.
        image[width * j + i] /= 4.0;
    }
}

Outra possibilidade é fazer um jitter aleatório (em vez da matriz baseada acima), mas logo você entra no campo do processamento de sinais e é preciso muita leitura para saber como escolher uma boa função de ruído.

A idéia permanece a mesma: considere o pixel como uma pequena área quadrada e, em vez de disparar apenas um raio que passa pelo centro do pixel, atire em muitos raios cobrindo toda a área do pixel. Quanto mais densa a distribuição de raios, melhor o sinal que você recebe.

PS: Eu escrevi o código acima em tempo real, então esperaria alguns erros nele. Destina-se apenas a mostrar a ideia básica.


Ótima resposta! Quais seriam os benefícios de usar esse método em oposição ao método @Raxvan usado? Obterei os mesmos resultados renderizando em um tamanho grande e diminuindo para um tamanho menor?
— Arjan Singh

Fundamentalmente, com o traçado de raios, você não precisa renderizar uma imagem maior e reduzi-la. Isso significa que você tem muito mais flexibilidade: pode ter muitas amostras, pode variar o número de amostras dependendo da região e, simplesmente, não precisa adicionar a etapa de nova escala.
— Julien Guertault

2
No tópico de tremulação, esse acaba sendo um tópico bastante complexo. Aqui está um grande papel analisar a state-of-the-art de alguns anos atrás graphics.pixar.com/library/MultiJitteredSampling/paper.pdf
— Mikkel Gjoel

O exemplo de código acima usa um MSAA de 4 exemplos. Se eu quisesse fazer o MSAA 8x, como seria a matriz? O que eu precisaria mudar na matriz de jitter mostrada acima?
— Arjan Singh
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.