Как сглаживание реализовано в трассировке лучей?

13

Прочитав несколько статей в Интернете, я могу с уверенностью сказать, что не знаю, как работает сглаживание, когда Рэй Трассинг работает .

Все, что я понимаю, это то, что один пиксель / луч разделен на 4 субпикселя и 4 луча, а не 1 .

Может кто-нибудь объяснить, как это делается (желательно с кодом)?

Арджан Сингх
источник
2
Могу ли я просто предложить вам посмотреть «суперсэмплинг» en.wikipedia.org/wiki/Supersampling и, возможно, также en.wikipedia.org/wiki/Distributed_ray_tracing ?
Саймон Ф
2
Я также могу порекомендовать прочитать эту главу PBRT pbrt.org/chapters/pbrt_chapter7.pdf и прочитать эту статью lgdv.cs.fau.de/get/785 (которая объясняет метод, отличный от того, который реализован в pbrt).
Том ван Бассел
1
foreach pixel : p{acc = 0; foreach subsample : s { acc+=sample_scene(s);} store(p, acc);}
фрик с трещоткой

Ответы:

12

Я думаю, можно с уверенностью сказать, что есть два разных способа выполнения АА в трассировке лучей:

1: если у вас есть окончательное изображение и изображение глубины, можно применить практически все существующие методы, которые используются в играх (FXAA и т. Д.). Они работают непосредственно с конечным изображением и не связаны с трассировкой лучей.

2: второй метод состоит в том, чтобы учитывать несколько лучей для каждого пикселя и затем усреднять результат. Для очень простой версии подумайте об этом так:

  • сначала вы визуализируете изображение размером 1024x1024, по одному лучу на каждый пиксель (например)
  • после рендеринга вы масштабируете изображение до 512x512 (каждые 4 пикселя выровнены в один), и вы можете заметить, что края более гладкие. Таким образом, вы эффективно использовали 4 луча для каждого пикселя в конечном изображении размером 512x512.

Есть и другие варианты этого метода. Например, вы можете адаптировать количество выборок для пикселей, которые находятся прямо на краю геометрии, что означает, что для некоторых пикселей у вас будет только 4 образца, а для других 16.

Проверьте ссылки в комментариях выше.

Raxvan
источник
Таким образом, в основном я отрисовываю изображение большого размера и при сохранении его в изображение уменьшаем его до меньшего размера? Это кажется довольно простым :)! Это метод супер выборки?
Арджан Сингх
1
@ Арджан Сингх, да, это en.wikipedia.org/wiki/Supersampling , но это самый медленный из них, трассировка лучей позволяет вам легко выполнять адаптивную суперсэмплинг, который может работать намного лучше
Raxvan
13

Raxvan совершенно прав, что «традиционные» методы сглаживания будут работать в трассировке лучей, включая те, которые используют информацию, такую ​​как глубина, для сглаживания. Вы можете даже сделать временное сглаживание в трассировке лучей, например.

Жюльен подробно остановился на 2-м пункте Раксвана, который был объяснением суперсэмплинга, и показал, как вы на самом деле это делаете, также упомянув, что вы можете рандомизировать расположение сэмплов в пикселе, но затем вы входите в страну обработки сигналов, которая очень глубже, и это определенно так!

NN

Если вы сделаете это, вы все равно можете получить псевдоним. Это лучше, чем НЕ делать этого, потому что вы увеличиваете частоту дискретизации, поэтому сможете обрабатывать более высокочастотные данные (то есть более мелкие детали), но это все равно может вызывать алиасинг.

N

Когда вы используете только «обычные» случайные числа, как вы получаете из rand () или std ::iform_int_distribution, это называется «белый шум», потому что он содержит все частоты, например, как белый свет состоит из всех других цветов (частот). ) света.

Использование белого шума для рандомизации сэмплов в пикселе имеет проблему, заключающуюся в том, что иногда ваши сэмплы будут объединяться. Например, если вы усредняете 100 выборок в пикселе, но все они в конечном итоге оказываются в верхнем левом углу пикселя, вы не собираетесь получать ЛЮБУЮ информацию о других частях пикселя, поэтому ваш конечный цвет пикселя в результате будет отсутствовать информация о том, какого цвета это должно быть.

Лучшим подходом является использование так называемого синего шума, который содержит только высокочастотные компоненты (например, как синий свет - это высокочастотный свет).

Преимущество синего шума состоит в том, что вы получаете равномерное покрытие по пикселю, как вы получаете с равномерной сеткой выборки, но вы все равно получаете некоторую случайность, которая превращает наложение в шум и дает вам лучше выглядящее изображение.

К сожалению, синий шум может быть очень дорогим для вычисления, и все лучшие методы, кажется, запатентованы (какого черта ?!), но один из способов сделать это, изобретен Pixar (и запатентован тоже, я думаю, но не уверен на 100%) состоит в том, чтобы сделать четную сетку точек выборки, а затем произвольно сместить каждую точку выборки на небольшую величину - например, случайную величину между плюс или минус половиной ширины и высоты сетки выборки. Таким образом, вы получите своего рода выборку синего шума за довольно дешевую цену.

Обратите внимание, что это форма многоуровневой выборки, и выборка из пуассоновых дисков также является одной из форм, которая также является способом генерации синего шума: https://www.jasondavies.com/poisson-disc/

Если вы заинтересованы в том, чтобы углубиться, вы, вероятно, захотите проверить этот вопрос и ответить на него!

Какова основная причина сглаживания с использованием нескольких случайных выборок в пикселе?

Наконец, этот материал начинает уходить в область трассировки Монте-Карло, которая является распространенным методом фотореалистичной трассировки лучей. Если вы хотите узнать больше об этом, прочитайте это!

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

Алан Вульф
источник
7

Давайте предположим довольно типичный основной цикл трассировки лучей:

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);
    }
}

Одна из возможных модификаций для выполнения 4 выборок MSAA:

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;
    }
}

Другая возможность состоит в том, чтобы сделать случайный джиттер (вместо основанного на матрице выше), но затем вы вскоре войдете в область обработки сигналов, и потребуется много чтения, чтобы узнать, как выбрать хорошую функцию шума.

Идея остается неизменной: считайте, что пиксель представляет крошечную квадратную область, и вместо того, чтобы снимать только один луч, проходящий через центр пикселя, снимайте много лучей, покрывающих всю область пикселя. Чем плотнее распределение лучей, тем лучше сигнал.

PS: я написал код выше на лету, поэтому я ожидал несколько ошибок в нем. Это только для того, чтобы показать основную идею.

Жюльен Геро
источник
Отличный ответ! Каковы преимущества использования этого метода по сравнению с методом @Raxvan? Получу ли я те же результаты, выполняя рендеринг в большой размер, а затем уменьшая масштаб до меньшего размера?
Арджан Сингх
По сути, при трассировке лучей вам не нужно визуализировать большее изображение, а затем уменьшать его. Это означает, что у вас намного больше гибкости: у вас может быть много образцов, вы можете варьировать количество образцов в зависимости от региона, и просто вам не нужно добавлять шаг изменения масштаба.
Жюльен Герто
2
Что касается джиттера, то это довольно сложная тема. Вот отличная статья, в которой анализируется состояние дел нескольких лет назад graphics.pixar.com/library/MultiJitteredSampling/paper.pdf
Миккель Гьоэль
В приведенном выше примере кода используется MSAA из 4 примеров. Если бы я хотел выполнить 8x MSAA, как бы выглядела тогда матрица? Что мне нужно изменить в приведенной выше матрице дрожания?
Арджан Сингх