Как добавить реализма в path tracing

Здравствуйте, уважаемые хабровчане. Казалось бы: куда уже реальнее, но все же, есть у меня идея. По порядку.

Введение


Path tracing — это метод создания сцен виртуальной реальности, основан на оптике.

В трехмерном пространстве из источника света испускается очень много лучей (в идеале сколько же, сколько в реальности фотонов) и прослеживаются истории каждого луча. Когда луч встречается с преградой, возможно несколько событий: поглощение, отражение, преломление. Вероятность каждого из них зависит от материала преграды и цвета луча. Те лучи, которые попали в камеру — рисуются на экране. Вообще, подробнее это можно прочитать в википедии.

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

Идея


А что если трассировать не лучи, а фотоны. Это же тоже самое! Я уточню. В одному направлении испускать сразу много монохроматических фотонов. Там где раньше был один луч, теперь 16, 32, 64… сколько не жалко фотонов с длиной волны 720, 700, ..., 450 нм. И у каждого из них может быть своя история. Смысл это будет иметь только тогда, когда материал по разному изменяет направление фотонов с разной частотой.

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

На псевдокоде это как-то так выглядит:
	i = 0..screen_h-1
	j = 0..screen_w-1
		double x = 2*j/screen_w-1;
		double y = 2*i/screen_h-1;
		table[i, j] = norm(center+x*left+y*up);

	n = 0..samples_num-1
	i = 0..screen_h-1
	j = 0..screen_w-1
	freq = 0..color_quality-1
		power = 0;
		Ray r = ray_from_vecs(eye, table[i, j]);
		trace(&r, &power, freq);
		screen[i*w+j] = screen[i*w+j]+power*rgb_from_freq(freq);

	i = 0..screen_h-1
	j = 0..screen_w-1
		screen[i*w+j] /= samples_num;



Здесь, думаю, все понятно. freq — частота волны света, screen_w, screen_h — ширина и высота экрана в пикселях, samples_num — количество выборок. Истинный цвет — среднее арифметическое по всех выборках, когда число выборок стремится к бесконечности. Векторы направлений фотонов лучше сохранять в таблице (table), что-бы не рассчитывать каждый раз. Рассчитываются они по несложной формуле, в которой участвуют еще и вектора указывающие на центр экрана, левую и верхнюю границу экрана. Например если соотношение сторон 4:3, то можно выбрать

center = (0, 0, 0)
left = (4, 0, 0)
up = (3, 0, 0)


Разумеется это все зависит от реализации.

Теперь о функции trace, в ней и происходит «магия». Она принимает положение и направление луча, а также его частоту, мощность (power) должна быть равна нулю. Возвращает она новое положение и направление и мощность. Положение и направление нас не интересует и фигурирует только для того, что-бы функция trace могла вызываться рекуррентно.

Color — массив, размер которого совпадает с количеством градаций частот.

Опять псевдокод
void trace()
{
	Vec n;	// вектор нормали в точке пересечения
	Vec p;	// точка пересечения
	Color dif;	// вероятности диффузного отражения от материала
	Color rfl;	// вероятности зеркального отражения от материала
	Color ems;	// интенсивность излучения материала
	Color koef;	// коэффициент преломления материала при конкретной частоте
	find_intersekt();

	double f = random();	// (fade) судьба луча
	double a = dif[freq];
	double b = a+rfl[freq];

	r->pos = p;
	double k = n*r->dir;	// косинус угла с нормалью при падении

	if (f < a)			// диффузное отражение
	{
		r->dir = случайное_направление_в_полупространстве_нормали;
	}
	if ((f >= a) && f < b)	// зеркальное отражение
	{				// эти формулы получил я сам
		Vec a_ = cross(n, r->d);
		Vec b_ = cross(a_, koef*n);
		double d = 1-b_*b_;
		if (d < 0)		// если возможно отражение (в полупространстве нормали), то отражаем
			r->dir = r->dir+2*k*n;
		else			// иначе преломляем
		{
			double l = sqrt(d);
			r->dir = b_-l*n;
		}
	}
	if (f < b)			// диффузное или зеркальное отражение, то идем в рекурсию
		trace(r, power, freq);
	power = power+ems[freq]*k;	// на выходе с рекурсии подсчитываем поверхности, которые излучают
}


Конечно этот псевдокод не претендует ни на что. Можно например сохранять разные вероятности для преломления и зеркального отражения. Или еще как то усложнить модель. Главное здесь — вероятности и коэффициент преломления зависят от частоты и у каждого фотона она своя.

Я полистал картинки по запросу path tracing в гугле и не увидел дисперсию света. Поиск по запросу monochromatic path tracing не показал ничего интересного. Пересмотрел всю первую страницу, везде эти слова разделены другими и в самой статье нету моей идеи.

Конечно скорее всего это уже реализовано и описано в книгах, до которых я еще не дотянулся.

Следствия


Не нужно быть гением, что-бы понять: трассировка монохроматических фотонов обойдется в 16, 32,… дороже чем стандартный алгоритм (зависит от качества цвета). Сейчас трассировка пути в реальном времени на железе обычного пользователя невозможна и непонятно когда это можно будет осуществить. А «монохроматическая» трассировка — еще дороже.
Поделиться публикацией

Комментарии 17

    0
    >>трассировка монохроматических фотонов обойдется в 16, 32,… дороже чем стандартный алгоритм

    Можно трейсить два пограничных «фотона» и если их пути совпадают, то забить на все, что между. Также путь можно колоть на отрезки.
      +13
      Не хватает картинок «до» и «после» (с лучами и с фотонами).
        +3
        Пока ничего убедительного не получил. Это тема моей курсовой, еще будут.
      • НЛО прилетело и опубликовало эту надпись здесь
          0
          Path tracing is a physically based rendering technique, based on ray tracing. Where regular recursive ray tracing [2] (Whitted-style) is able to render reflections, refractions, and shadows, path tracing also handles diffuse reflections, indirect light, and even caustics. It does this by replacing the integrals involved in these effects by the expected value of a stochastic process: Soft shadows are calculated by sending several random rays to an area light source; anti-aliasing is calculated as the average of several random rays over the area of a pixel, and so on. Randomness means noise, and thus the resulting image quality depends on the number of samples. A path traced image converges over time, as more samples are added to previous frames.

          Towards Real-Time Path Tracing in Games
            0
            Интерференции и дифракции не получится. Да, я употреблял слова фотон и луч имея ввиду одно и тоже.
              0
              В ray tracing'е нету никакой истории луча, там луч идет от глаза к первому пересечению и в том месте рассчитывается цвет. В path tracing'е же луч отражается пока не поглотится или не попадет на лампу. Path tracing дороже и реалистичнее.
                +1
                В ray tracing'е луч точно так же переотражается, пока его вклад в расчёты не упадет ниже cutoff threshold либо пока он не упрётся в фон, либо пока не превысит заданное максимальное кол-во переотражений.

                Разница между PT и RT в другом.

                Что же касается фотонов — они уж лет 15-20 существуют в том же mental ray.
                en.wikipedia.org/wiki/Photon_mapping

                «Новшество» в виде длины волн уж лет 5 как реализовано в Maxwell renderб да и не только в нём, насколько я помню.
                  0
                  Это же замечательно! Как я раньше не видел. Рендеринг без допущений! Уже качаю, спасибо.
              +4
              Это называется photon mapping и используется как вспомогательный приём при ray tracing-е. На эту тему давным давно написаны диссертации.

              Вот например статья одна: Global Illumination using Photon Maps (Henrik Wann Jensen).
                +4
                И давно реализовано, например, в PovRay. Там запускается один фотон, который в местах потенциального преломления порождает настраиваемое количество фотонов с другими характеристиками.
                0
                Разработчики ментала в 2011м обещали добавить возможность дисперсии в iray, в 2012 сделали (по второй ссылке в файлике на фтпшнике pdf с примерами, там есть и пример дисперсии).
                  0
                  Еще больше реализма получиться если учесть спектральные характеристики источника света.
                  Т.е. назначить не линейное распределение мощностей в зависимости от длинны волны (под мощностью тут правильно понимать количество фотонов в единицу времени)
                    0
                    Здесь так и есть, Color — массив и берется он из файла. Распределение может быть любым
                      0
                      И какой же спектр вы сопоставите rgb(255,0,0)? rgb(255,255,0)? rgb(235, 55, 143)? rgb(255,255,255)?

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

                      То же самое касается поверхностей: у них есть спектры поглощения и излучения, а не просто «цвет». Ну вы поняли, про прозрачные тела даже говорить страшно.
                        0
                        Это задача не программы рендеринга, а художника или физика в команде. Спектры будут известны изначально.
                  • НЛО прилетело и опубликовало эту надпись здесь

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое