<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rgabdullin</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rgabdullin"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Rgabdullin"/>
	<updated>2026-10-23T01:24:17Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20252</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20252"/>
		<updated>2016-12-07T14:06:48Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
Использовалось следующее программное обеспечение:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
| Microsoft Windows 10 Education Edition&lt;br /&gt;
|-&lt;br /&gt;
| Ubuntu 16.10 Yakkety Yak&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Компиляторы C++&lt;br /&gt;
|-&lt;br /&gt;
| nvcc из пакета NVIDIA CUDA SDK 8.0.44 + Microsoft Visual C++ 2015(Windows)&lt;br /&gt;
|-&lt;br /&gt;
| nvcc из пакета NVIDIA CUDA SDK 8.0.44 + gcc-4.9(Linux)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Результаты тестирования получены на следующих машинах:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! CPU&lt;br /&gt;
! RAM&lt;br /&gt;
! GPU&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-3210m 3.1GHz&lt;br /&gt;
| 6Gb DDR3 1333MHz&lt;br /&gt;
| NVIDIA GT 640m 2.0Gb DDR3&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-6600 3.9GHz&lt;br /&gt;
| 16Gb DDR4 2133MHz&lt;br /&gt;
| NVIDIA GTX 1070 8.0Gb GDDR5&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20251</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20251"/>
		<updated>2016-12-07T14:06:21Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
Использовалось следующее программное обеспечение:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
| Microsoft Windows 10 Education Edition&lt;br /&gt;
|-&lt;br /&gt;
| Ubuntu 16.10 Yakkety Yak&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Компиляторы C++&lt;br /&gt;
|-&lt;br /&gt;
| nvcc из пакета NVIDIA CUDA SDK 8.0.44 + Microsoft Visual C++ 2015(Windows)&lt;br /&gt;
| nvcc из пакета NVIDIA CUDA SDK 8.0.44 + gcc-4.9(Linux)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Результаты тестирования получены на следующих машинах:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! CPU&lt;br /&gt;
! RAM&lt;br /&gt;
! GPU&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-3210m 3.1GHz&lt;br /&gt;
| 6Gb DDR3 1333MHz&lt;br /&gt;
| NVIDIA GT 640m 2.0Gb DDR3&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-6600 3.9GHz&lt;br /&gt;
| 16Gb DDR4 2133MHz&lt;br /&gt;
| NVIDIA GTX 1070 8.0Gb GDDR5&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20249</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20249"/>
		<updated>2016-12-07T13:58:46Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
Использовалось следующее программное обеспечение:&lt;br /&gt;
&lt;br /&gt;
OS: Microsoft Windows 10 Education Edition / Ubuntu 16.10 Yakkety Yak.&lt;br /&gt;
&lt;br /&gt;
Компиляторы: nvcc из пакета NVIDIA CUDA SDK 8.0.44, Microsoft Visual C++ 2015(Windows) / gcc-4.9(Linux).&lt;br /&gt;
&lt;br /&gt;
Результаты тестирования получены на следующих машинах:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! CPU&lt;br /&gt;
! RAM&lt;br /&gt;
! GPU&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-3210m 3.1GHz&lt;br /&gt;
| 6Gb DDR3 1333MHz&lt;br /&gt;
| NVIDIA GT 640m 2.0Gb DDR3&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|-&lt;br /&gt;
| Core i5-6600 3.9GHz&lt;br /&gt;
| 16Gb DDR4 2133MHz&lt;br /&gt;
| NVIDIA GTX 1070 8.0Gb GDDR5&lt;br /&gt;
| Ubuntu 16.10&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20248</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20248"/>
		<updated>2016-12-07T13:58:03Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
Использовалось следующее программное обеспечение:&lt;br /&gt;
&lt;br /&gt;
OS: Microsoft Windows 10 Education Edition / Ubuntu 16.10 Yakkety Yak.&lt;br /&gt;
&lt;br /&gt;
Компиляторы: nvcc из пакета NVIDIA CUDA SDK 8.0.44, Microsoft Visual C++ 2015(Windows) / gcc-4.9(Linux).&lt;br /&gt;
&lt;br /&gt;
Результаты тестирования получены на следующих машинах:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! CPU&lt;br /&gt;
! RAM&lt;br /&gt;
! GPU&lt;br /&gt;
! OS&lt;br /&gt;
|-&lt;br /&gt;
! Core i5-3210m 3.1GHz&lt;br /&gt;
! 6Gb DDR3 1333MHz&lt;br /&gt;
! NVIDIA GT 640m 2.0Gb DDR3&lt;br /&gt;
! Ubuntu 16.10&lt;br /&gt;
|-&lt;br /&gt;
! Core i5-6600 3.9GHz&lt;br /&gt;
! 16Gb DDR4 2133MHz&lt;br /&gt;
! NVIDIA GTX 1070 8.0Gb GDDR5&lt;br /&gt;
! Ubuntu 16.10&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20247</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=20247"/>
		<updated>2016-12-07T13:51:46Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
Использовалось следующее программное обеспечение:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19585</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19585"/>
		<updated>2016-11-30T04:09:07Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 500px]] [[File:CudaRaytracerPerformance.png| 500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19584</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19584"/>
		<updated>2016-11-30T04:08:48Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]] [[File:CudaRaytracerPerformance.png]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|} &lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19583</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19583"/>
		<updated>2016-11-30T04:07:33Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Видно, что с ростом размера окна &amp;quot;исчезает&amp;quot; рост производительности. Это связано с накладными расходами на хранение данных в памяти GPU.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19582</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19582"/>
		<updated>2016-11-30T04:05:52Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
В программной реализации на CUDA изображение делится на окна меньшего размера. &lt;br /&gt;
Затем происходит отрисовка каждого окна, при этом цвета пикселей в каждом окне вычисляются параллельно.&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Лучей в окне&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8 c&lt;br /&gt;
|58.0 c&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|15.2 c&lt;br /&gt;
|35.5 c&lt;br /&gt;
|-&lt;br /&gt;
|2048&lt;br /&gt;
|8.2 c&lt;br /&gt;
|25.2 c&lt;br /&gt;
|-&lt;br /&gt;
|4096&lt;br /&gt;
|4.6 c&lt;br /&gt;
|24.5 c&lt;br /&gt;
|-&lt;br /&gt;
|8192&lt;br /&gt;
|3.0 c&lt;br /&gt;
|23.5 c&lt;br /&gt;
|-&lt;br /&gt;
|16384&lt;br /&gt;
|3.1 c&lt;br /&gt;
|23.4 c&lt;br /&gt;
|-&lt;br /&gt;
|32768&lt;br /&gt;
|2.8 c&lt;br /&gt;
|23.2 c&lt;br /&gt;
|-&lt;br /&gt;
|65536&lt;br /&gt;
|2.5 c&lt;br /&gt;
|23.1 c&lt;br /&gt;
|-&lt;br /&gt;
|131072&lt;br /&gt;
|2.4 c&lt;br /&gt;
|23.0 c&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19581</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19581"/>
		<updated>2016-11-30T03:58:07Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Размер фрейма&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|29.8&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19580</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19580"/>
		<updated>2016-11-30T03:56:46Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Размер фрейма&lt;br /&gt;
! GTX 1070&lt;br /&gt;
! GT 640m&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|2&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19579</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19579"/>
		<updated>2016-11-30T03:54:37Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|} [[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19578</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19578"/>
		<updated>2016-11-30T03:54:27Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19577</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19577"/>
		<updated>2016-11-30T03:53:50Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
1) [[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19576</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19576"/>
		<updated>2016-11-30T03:53:39Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 400px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19575</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19575"/>
		<updated>2016-11-30T03:53:29Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png | 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19574</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19574"/>
		<updated>2016-11-30T03:53:18Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью MPI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19573</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19573"/>
		<updated>2016-11-30T03:53:08Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью MPI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|300px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19572</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19572"/>
		<updated>2016-11-30T03:52:57Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью MPI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19571</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19571"/>
		<updated>2016-11-30T03:52:16Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью MPI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|400px]] {| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19570</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19570"/>
		<updated>2016-11-30T03:51:48Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png 300px]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19569</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19569"/>
		<updated>2016-11-30T03:51:16Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Реализация с помощью NVIDIA CUDA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
[[File:CudaRaytracer_scene1.png]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19568</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19568"/>
		<updated>2016-11-30T03:48:40Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью NVIDIA CUDA ===&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19567</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19567"/>
		<updated>2016-11-30T03:46:31Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Полученные изображения */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
File:CudaRaytracer_scene1.png&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19331</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19331"/>
		<updated>2016-11-28T03:26:00Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] — очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] — система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay — это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] — технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] — профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] — это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19330</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19330"/>
		<updated>2016-11-28T03:25:08Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] ---- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] ---- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay ---- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] ---- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] ---- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] ---- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19329</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19329"/>
		<updated>2016-11-28T03:24:46Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] --- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] --- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay --- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] --- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] --- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] --- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19328</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19328"/>
		<updated>2016-11-28T03:24:15Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19327</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19327"/>
		<updated>2016-11-28T03:23:40Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компанией NVIDIA) в 1986 году.&lt;br /&gt;
Использован в фильмах [https://en.wikipedia.org/wiki/Terminator_3:_Rise_of_the_Machines Терминатор 3: Восстание машин](2003), [https://en.wikipedia.org/wiki/Tron:_Legacy Трон: Наследие](2010).&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19326</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19326"/>
		<updated>2016-11-28T03:19:58Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компаней NVIDIA) в 1986 году.&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3. Параллельные вычисления на GPU. Архитектура и программная модель CUDA: Учеб. пособие / А.В. Боресков и др. - М.: Издательство Московского университета, 2012. - 336 с.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19325</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19325"/>
		<updated>2016-11-28T03:17:21Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компаней NVIDIA) в 1986 году.&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/ Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19324</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19324"/>
		<updated>2016-11-28T03:17:05Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компаней NVIDIA) в 1986 году.&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. [http://www.raytracegroundup.com/&lt;br /&gt;
Suffern, Kevin G. &amp;quot;Ray Tracing from the Ground Up / Kevin G. Suffern&amp;quot;, 2007]&lt;br /&gt;
&lt;br /&gt;
2. [http://www.scratchapixel.com/ Scratchapixel 2.0. Learn Computer Graphics From Scratch!]&lt;br /&gt;
&lt;br /&gt;
3.&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19323</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19323"/>
		<updated>2016-11-28T03:14:18Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com/object/nvidia-iray.html NVIDIA IRay] -- технология создания фотореалистичных изображений с использованием графических ускорителей, созданная компанией NVIDIA.&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/Mental_ray mental ray] -- профессиональная система рендеринга и визуализации изображений, разработанная компанией mental images(является дочерней компаней NVIDIA) в 1986 году.&lt;br /&gt;
&lt;br /&gt;
[http://www.raytracing.ru/ Hydra Renderer] -- это плагин для рендера реалистичных изображений в 3D Studio Max. Разработан при поддержке Лаборатории компьютерной графики и мультимедиа факультета ВМК МГУ.&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19322</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19322"/>
		<updated>2016-11-28T02:58:38Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] -- очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/V-Ray V-Ray] -- система рендеринга, разработанная компанией Chaos Group в 2000 году.&lt;br /&gt;
VRay -- это рейтрейсный рендерер, в котором присутствует несколько алгоритмов просчета глобального освещения.&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19321</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19321"/>
		<updated>2016-11-28T02:55:37Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] - очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 году.&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19320</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19320"/>
		<updated>2016-11-28T02:55:12Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan RenderMan] - очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 годую&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [https://en.wikipedia.org/wiki/Avatar_(2009_film) Аватар](2009), [https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) Гарри Поттер и Орден Феникса](2007), [https://en.wikipedia.org/wiki/Finding_Nemo | В поисках Немо](2003).&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19319</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19319"/>
		<updated>2016-11-28T02:54:17Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[http://www.example.com заголовок ссылки]&lt;br /&gt;
&lt;br /&gt;
[https://ru.wikipedia.org/wiki/RenderMan | RenderMan] - очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 годую&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [[https://en.wikipedia.org/wiki/Avatar_(2009_film) | Аватар]](2009), [[https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) | Гарри Поттер и Орден Феникса]](2007), [[https://en.wikipedia.org/wiki/Finding_Nemo | В поисках Немо]](2003).&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19318</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19318"/>
		<updated>2016-11-28T02:53:16Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[[https://ru.wikipedia.org/wiki/RenderMan | RenderMan]] - очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 годую&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [[https://en.wikipedia.org/wiki/Avatar_(2009_film) | Аватар]](2009), [[https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film) | Гарри Поттер и Орден Феникса]](2007), [[https://en.wikipedia.org/wiki/Finding_Nemo | В поисках Немо]](2003).&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19317</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19317"/>
		<updated>2016-11-28T02:51:22Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[[https://ru.wikipedia.org/wiki/RenderMan|RenderMan]] - очень известный пакет программ для рендеринга 3D-анимации, который был создан компанией Pixar в 1986 годую&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов и мультфильмов, например: [[https://en.wikipedia.org/wiki/Avatar_(2009_film)|Аватар]](2009), [[https://en.wikipedia.org/wiki/Harry_Potter_and_the_Order_of_the_Phoenix_(film)|Гарри Поттер и Орден Феникса]](2007), [[https://en.wikipedia.org/wiki/Finding_Nemo|В поисках Немо]]&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19316</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=19316"/>
		<updated>2016-11-28T02:46:09Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
Вычислим последовательную сложность алгоритма в терминах пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
[[file: Raytracer_graph.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Зеленые вершины - генерация лучей для данного пикселя.&amp;lt;br&amp;gt;&lt;br /&gt;
Желтые вершины - трассировка лучей данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Из информационного графа видно, что обработка каждого пикселя происходит независимо от других, а затем происходит соединение всех пикселей в итоговое изображение. Пусть &amp;lt;math&amp;gt;N_p \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N_p - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O\Big(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p}\Big)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Реализация с помощью MPI ===&lt;br /&gt;
1)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene5.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|479.915&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|492.614&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|313.172&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|170.866&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|82.375&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|43.812&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|22.318&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|12.195&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|8.793&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|6.954&lt;br /&gt;
|-&lt;br /&gt;
|1024&lt;br /&gt;
|6.741&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
2)&amp;lt;br&amp;gt;&lt;br /&gt;
Размер изображения 1340 на 1340 пикселей, 1024 лучей на пиксел, глубина рекурсии 5.&amp;lt;br&amp;gt;&lt;br /&gt;
Сцена:&amp;lt;br&amp;gt;&lt;br /&gt;
[[file: Raytracer_scene8.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|600.270&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|610.583&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|243.261&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|136.025&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|67.517&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|33.467&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|17.234&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|9.361&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan - очень известный пакет программ для рендерина 3D-анимации, который был создан компанией Pixar в 1986 годую&lt;br /&gt;
Данный пакет использовался во множестве известных фильмов, например: &lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
1. Kevin Suffern &amp;quot;Ray Tracing from the Ground Up&amp;quot;, 2007 http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
2. &amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Rgabdullin&amp;diff=18858</id>
		<title>Участник:Rgabdullin</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Rgabdullin&amp;diff=18858"/>
		<updated>2016-11-21T17:58:37Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Габдуллин Руслан Айдарович, ВМК МГУ, 416 группа 2016/2017.&lt;br /&gt;
&lt;br /&gt;
Статьи:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Участник:vlamakarenko/Трассировка лучей|Трассировка лучей]].&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18857</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18857"/>
		<updated>2016-11-21T17:56:52Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
Scratchapixel 2.0 - http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
HydraRenderer - http://www.raytracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18856</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18856"/>
		<updated>2016-11-21T17:56:37Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
ScratchaPixel 2.0 - http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
HydraRenderer - http://www.raytracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18855</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18855"/>
		<updated>2016-11-21T17:53:19Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - готовое изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18854</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18854"/>
		<updated>2016-11-21T17:51:26Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0}; //прямое излучение&lt;br /&gt;
indirect_illumintaion = {0,0,0}; //непрямое излучение&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18853</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18853"/>
		<updated>2016-11-21T17:50:51Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
Для упрощения модели разобьем входящее излучение на &#039;&#039;прямое&#039;&#039; и &#039;&#039;непрямое&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
Прямое излучение - излучение, приходящее в точку непосредственно от источников света.&amp;lt;br&amp;gt;&lt;br /&gt;
Непрямое излучение состоит из отраженного от других объектов сцены света.&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0};&lt;br /&gt;
indirect_illumintaion = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18851</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18851"/>
		<updated>2016-11-21T17:48:27Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0};&lt;br /&gt;
indirect_illumintaion = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18850</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18850"/>
		<updated>2016-11-21T17:46:15Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. &amp;lt;br&amp;gt;&lt;br /&gt;
Для каждого луча находится точка первого пересечения с объектами сцены, расчитывается входящие излучения и на основе этого - итоговое выходящее. &amp;lt;br&amp;gt;&lt;br /&gt;
После этого цвет усредняется по всем лучам, проходящим через данный пиксел.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0};&lt;br /&gt;
indirect_illumintaion = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18849</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18849"/>
		<updated>2016-11-21T17:43:50Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Улучшение визуальных качеств изображения */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Заметим, что чем больше лучей выпускается через каждый пиксел изображения, тем лучше получается картинка.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. Для каждого луча находится первое пересечение с объектами сцены, расчитывается прямое и непрямое входящие излучения и итоговое выходящее. После этого цвет усредняется по всем лучам данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0};&lt;br /&gt;
indirect_illumintaion = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18848</id>
		<title>Участник:Vlamakarenko/Трассировка лучей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Vlamakarenko/%D0%A2%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BB%D1%83%D1%87%D0%B5%D0%B9&amp;diff=18848"/>
		<updated>2016-11-21T17:42:22Z</updated>

		<summary type="html">&lt;p&gt;Rgabdullin: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;авторы: [[Участник:vlamakarenko|В.А.Макаренко]], [[Участник:Rgabdullin|Р.А.Габдуллин]]&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Трассировка лучей&#039;&#039;&#039; - это технология визуализации трехмерных сцен путем отслеживания обратной траектории лучей света (от наблюдателя к источнику).&lt;br /&gt;
Достоинствами данного метода являются реалистичность итоговых изображений, возможность визуализации гладких объектов без аппроксимации полигональными поверхностями, простота реализации отражений, преломлений, взятия в фокус, реалистичного освещения; возможность параллельной обработки лучей.&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Некоторые понятия из радиометрии ===&lt;br /&gt;
&lt;br /&gt;
[[file: Radiance_raytracer.png|thumb|right|300px|Энергетическая яркость]]&lt;br /&gt;
[[file: BRDF Diagram.svg|thumb|right|300px|BRDF]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергия излучения&#039;&#039;&#039; - энергия, переносимая оптическим излучением. Обозначается через&amp;amp;nbsp; &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Поток излучения&#039;&#039;&#039; - мощность, переносимая оптическим излучением через какую-либо поверхность.&amp;amp;nbsp; &amp;lt;math&amp;gt;\Phi = \frac{dQ}{dt}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Плотность потока излучения&#039;&#039;&#039; - отношение потока излучения, проходящего через малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Облученность&#039;&#039;&#039; - отношение потока излучения, падающего на малый участок поверхности, к площади этой поверхности. &amp;amp;nbsp; &amp;lt;math&amp;gt;E=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая светимость&#039;&#039;&#039; - отношение потока излучения, испускаемого малым участком поверхности, к площади этой поверхности.&amp;amp;nbsp; &amp;lt;math&amp;gt;M=\frac{d\Phi}{dA}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; где &amp;amp;nbsp; &amp;lt;math&amp;gt;dA&amp;lt;/math&amp;gt; - дифференциал поверхности.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сила излучения&#039;&#039;&#039; - мощность излучения источника света в некотором направлении. Равна отношению потока излучения, исходящего от источника, к малому телесному углу. &amp;amp;nbsp; &amp;lt;math&amp;gt;I=\frac{d\Phi}{d\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Энергетическая яркость&#039;&#039;&#039; - отношение потока излучения через малую площадку поверхности и распространяющегося в малом телесном угле, к площади проекции этой площадки на плоскость, перпендикулярную направлению распространения, и величине телесного угла.&amp;amp;nbsp; &amp;lt;math&amp;gt;L=\frac{d^2\Phi}{dA\cdot d\omega \cdot \cos \theta}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Энергетическую яркость, падающую на элемент поверхности, будем назвать &#039;&#039;&#039;падающей яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_i&amp;lt;/math&amp;gt;. Энергетическую яркость, отраженную элементом поверхности, будем называть &#039;&#039;&#039;отраженной яркостью&#039;&#039;&#039; и обозначать &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Из определений следует, что:&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt;dE_i(\overline{p}, \overline{\omega}_i) = L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2) &amp;lt;math&amp;gt;E(\overline{p}) = \int_{\Omega_i} L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i \, d\omega_i&amp;lt;/math&amp;gt;,&amp;amp;nbsp; где интегрирование проводится по направлениям &amp;lt;math&amp;gt;\overline{\omega}_i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i)&amp;lt;/math&amp;gt; &amp;gt; 0,&amp;amp;nbsp; то есть по полусфере.&amp;lt;br&amp;gt; (&amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль к поверхности в точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt;, &amp;amp;nbsp; &amp;lt;math&amp;gt;\Omega_i = 2\pi^{+}&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; - точка поверхности, &amp;lt;math&amp;gt;\overline{n}&amp;lt;/math&amp;gt; - нормаль в этой точке, &amp;lt;math&amp;gt;\overline{\omega}_i, \overline{\omega}_o&amp;lt;/math&amp;gt; - единичные вектора такие, что &amp;lt;math&amp;gt;(\overline{n}, \overline{\omega}_i) &amp;gt; 0, \,\, (\overline{n}, \overline{\omega}_o) &amp;gt; 0 &amp;lt;/math&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Будем считать, что &amp;amp;nbsp; &amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt; пропорционален &amp;amp;nbsp; &amp;lt;math&amp;gt;dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;dL_o(\overline{p}, \overline{\omega}_o) \sim dE_i(\overline{p},\overline{\omega}_i)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Функция &amp;amp;nbsp; &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{dE_i(\overline{p},\overline{\omega}_i)} = \frac{dL_o(\overline{p}, \overline{\omega}_o)}{L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i}&amp;lt;/math&amp;gt; &amp;amp;nbsp; называется &#039;&#039;&#039;двулучевой функцией отражательной способности (BRDF)&#039;&#039;&#039;.&amp;lt;br&amp;gt;&lt;br /&gt;
В точке &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; может быть задано несколько BRDF - множество &amp;lt;math&amp;gt;\{f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)\}&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Тогда итоговая BRDF просто равна сумме BRDF из этого множества: &amp;lt;math&amp;gt;f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) = \sum_k f_{r_k}(\overline{p}, \overline{\omega}_i, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;. &amp;amp;nbsp; - уравнение отражений.&amp;lt;br&amp;gt;&lt;br /&gt;
Важная часть алгоритма трассировки лучей - определить отраженную яркость по падающим яркостям, то есть посчитать этот интеграл. Обычно для вычисления интеграла применяют метод Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
==== Уравнение рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга - это интегральное уравнение, которое определяет количество излученного в определенном направлении света как сумму отраженного и собственного излучения. Физической основой для уравнения рендеринга является закон сохранения энергии.&lt;br /&gt;
&lt;br /&gt;
Уравнение отражений является частью уравнения рендеринга, поэтому остается только добавить собственное излучение объектов &amp;lt;math&amp;gt;L_e(\overline{p}, \overline{\omega}_o)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Уравнение рендеринга имеет вид &amp;lt;math&amp;gt;L_o(\overline{p}, \overline{\omega}_o) = L_e(\overline{p}, \overline{\omega}_o) + \int_{\Omega_i} f_r(\overline{p}, \overline{\omega}_i, \overline{\omega}_o) L_i(\overline{p}, \overline{\omega}_i)\cos \theta_i d\omega_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
По сути, алгоритмы рендеринга, в том числе и трассировка лучей, занимаются поиском приближенного решения уравнения рендеринга.&lt;br /&gt;
&lt;br /&gt;
==== Поиск приближенного решения уравнения рендеринга ====&lt;br /&gt;
&lt;br /&gt;
Введем оператор поиска первого пересечения.&lt;br /&gt;
&amp;lt;math&amp;gt;r_c(\overline{p}, \overline{\omega})&amp;lt;/math&amp;gt; - оператор, который находит точку первого пересечения с объектами луча, выпускаемого из точки &amp;lt;math&amp;gt;\overline{p}&amp;lt;/math&amp;gt; по направлению &amp;lt;math&amp;gt;\overline{\omega}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Воспользуемся предположением, что количество излучения, распространяющегося вдоль одной прямой одинаково в любой точке прямой. Тогда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_i(\overline{p},\overline{\omega}_i) = L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
и уравнение рендеринга превратится в &#039;&#039;уравнение Фредгольма второго рода&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
L_o(\overline{p},\overline{\omega}_o) = L_e(\overline{p},\overline{\omega}_o) + \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i&lt;br /&gt;
&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим интеграл в правой части как &amp;lt;math&amp;gt; K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда уравнение рендеринга перепишется, как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; L_o = L_e + K \circ L_o &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Искать решение будем итерационным методом: выберем какое-либо начальное приближение &amp;lt;math&amp;gt; L_{o}^{(0)} &amp;lt;/math&amp;gt;. Найдем значение правой части &amp;lt;math&amp;gt;L_o^{(1)} = L_e + K \circ L_o^{(0)}&amp;lt;/math&amp;gt;, воспользуемся им для поиска следующего приближенного решения &amp;lt;math&amp;gt;L_o^{(2)} = L_e + K \circ L_o^{(1)} = L_e + K \circ ( L_e + L_o^{(0)} ) = L_e + K \circ L_e + K^2 \circ L_o^{(0)} &amp;lt;/math&amp;gt; и т.д. &lt;br /&gt;
&lt;br /&gt;
В конечном итоге получим, что &amp;lt;math&amp;gt;L_o = \sum \limits_{n=0}^\infty K^n \circ L_o^{(0)}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот метод называется &#039;&#039;методом последовательных приближений&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Определения ===&lt;br /&gt;
&lt;br /&gt;
[[file: Ray trace diagram.svg|thumb|right|300px|Камера и видовая плоскость]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объект&#039;&#039;&#039; - поверхность в трехмерном пространстве.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Материал объекта&#039;&#039;&#039; - множество BRDF.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Сцена&#039;&#039;&#039; - четверка &#039;&#039;&#039;{камера, объекты, источники света, видовая плоскость}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Камера ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Камера&#039;&#039;&#039; - &amp;quot;виртуальный глаз&amp;quot;, через который мы видим объекты сцены. &lt;br /&gt;
&lt;br /&gt;
Камера задается положением в пространстве и ортонормированным базисом &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; (локальная система координат). &amp;lt;math&amp;gt;\overline{u}_c&amp;lt;/math&amp;gt; направлен вправо относительно наблюдателя, &amp;lt;math&amp;gt;\overline{v}_c&amp;lt;/math&amp;gt; - вверх, &amp;lt;math&amp;gt;\overline{w}_c&amp;lt;/math&amp;gt; - на наблюдателя. Таким образом, &amp;lt;math&amp;gt;(\overline{u}_c, \overline{v}_c, \overline{w}_c)&amp;lt;/math&amp;gt; - правая тройка векторов. Вектор направления камеры в своей системе координат: &amp;lt;math&amp;gt;(0, 0, -1)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
==== Видовая плоскость ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в ее центр. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева.&lt;br /&gt;
&lt;br /&gt;
Заметим, что с увеличением &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; уменьшается угол обзора, а &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; влияет на масштаб.&lt;br /&gt;
&lt;br /&gt;
==== Источники света ====&lt;br /&gt;
&lt;br /&gt;
Типы источников света:&amp;lt;br&amp;gt;&lt;br /&gt;
1) &#039;&#039;&#039;Point light&#039;&#039;&#039; - точка, излучающая свет одиноково во всех направлениях.&amp;lt;br&amp;gt;&lt;br /&gt;
2) &#039;&#039;&#039;Directional light&#039;&#039;&#039; - бесконечно удаленный источник света, задается единичным направлением на себя.&amp;lt;br&amp;gt;&lt;br /&gt;
3) &#039;&#039;&#039;Area light&#039;&#039;&#039; - объект, излучающий свет одинаково во всех направлениях.&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм трассировки лучей ===&lt;br /&gt;
&lt;br /&gt;
==== Генерация луча ====&lt;br /&gt;
&lt;br /&gt;
Перед камерой на расстоянии &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; поставим пиксельную сетку &amp;lt;math&amp;gt;w \times h&amp;lt;/math&amp;gt; с размером пикселя &amp;lt;math&amp;gt;s \times s&amp;lt;/math&amp;gt; так, чтобы камера была направлена в центр сетки. Итоговое изображение будет получено из этой сетки покраской пикселей в нужный цвет.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;p(i, j)&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=\overline{0,h-1}, \quad j=\overline{0,w-1}&amp;lt;/math&amp;gt; - пиксел &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-ой строки снизу &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-го столбца слева. Проведем пучок лучей из камеры через пиксел в локальной системе координат камеры. Начало каждого луча в точке &amp;lt;math&amp;gt;\overline{pos}=(0,0,0)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Найдем вектора направления &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.x = s \cdot (j + \delta_n.x -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.y = s \cdot (i + \delta_n.y -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}_n.z = d&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; \delta_n = (\delta_n.x, \delta_n.y) \in [0;1]^2&amp;lt;/math&amp;gt; - смещения начала n-ого луча.&lt;br /&gt;
&lt;br /&gt;
Нормируем вектора &amp;lt;math&amp;gt;\overline{dir}_n&amp;lt;/math&amp;gt; и переведем лучи в глобальную систему координат.&lt;br /&gt;
&lt;br /&gt;
==== Пересечение луча с объектами сцены ====&lt;br /&gt;
&lt;br /&gt;
Все точки луча &amp;lt;math&amp;gt;ray(\overline{p}, \overline{d})&amp;lt;/math&amp;gt; можно представить в виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h(x,y,z)=\overline{p}+t \cdot \overline{d}, \quad t \in [0;\infty) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt; тогда и только тогда, когда &amp;lt;math&amp;gt;t_i = \inf\{t &amp;gt; 0 \, | \quad \overline{p}+t \cdot \overline{d} \in O_i\} \, &amp;lt; \infty&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если луч пересекает объект &amp;lt;math&amp;gt;O_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;h_i(x,y,z) = \overline{p}+t_i \cdot \overline{d}&amp;lt;/math&amp;gt; - их первое пересечение, &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - расстояние от начала луча до точки пересечения.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление энергитической яркости &amp;lt;math&amp;gt;L_o&amp;lt;/math&amp;gt;, выходящей из точки пересечения ====&lt;br /&gt;
&lt;br /&gt;
Найдем &amp;lt;math&amp;gt;T = \{t_i\}&amp;lt;/math&amp;gt; - параметры пересечения с объектами (см. предыдущий пункт).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;t_{min} = \min \{t_i\}, \quad O_{min} = \{O_i | t_i = t_{min}\}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} = \infty&amp;lt;/math&amp;gt;, то луч не пересекает ни один объект и нужно покрасить соответствующий пиксел в черный цвет (цвет фона).&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;t_{min} &amp;lt; \infty&amp;lt;/math&amp;gt;, то нужно найти выходящее излучение (цвет) из точки пересечения в камеру. Выходящее излучение зависит от свойств материала объекта и входящего излучения в точку пересечения.&lt;br /&gt;
&lt;br /&gt;
Чтобы вычислить входящее излучение, находится приближенное значение интеграла &amp;lt;math&amp;gt; \int_{\Omega_i} f_{r}(\overline{p},\overline{\omega}_i,\overline{\omega}_o)L_o(r_c(\overline{p}, \overline{\omega}_i), -\overline{\omega}_i) \cos\theta_i d\omega_i &amp;lt;/math&amp;gt; методом Монте-Карло.&lt;br /&gt;
&lt;br /&gt;
Заметим, что каждый луч необходимо продолжить в некотором направлении(а не создавать новый пучок), так как необходимое количество лучей для численного интегрирования можно заранее сгенерировать в камере.&lt;br /&gt;
&lt;br /&gt;
Таким образом, алгоритм моделирует обратное движение пучка лучей света, который пришел в камеру. Пучок лучей движется из камеры и, сталкиваясь с объектами, распространяется в пространство в случайных направлениях, согласно свойствам материалов объектов.&lt;br /&gt;
&lt;br /&gt;
=== Улучшение визуальных качеств изображения ===&lt;br /&gt;
&lt;br /&gt;
Чтобы сгладить изображение и избавиться от шума, обычно через пиксел проводят не один луч, а достаточно много лучей, для каждого считают цвет, а потом усредняют по всем лучам (берут среднее арифметическое).&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Основные вычисления связаны с поиском пересечения луча с объектами сцены.&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для каждого пикселя изображения генерируется пучок лучей, проходящих через этот пиксел. Для каждого луча находится первое пересечение с объектами сцены, расчитывается прямое и непрямое входящие излучения и итоговое выходящее. После этого цвет усредняется по всем лучам данного пикселя.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Здесь приведен псевдокод ключевых моментов алгоритма.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//Покраска пикселей изображения&lt;br /&gt;
&lt;br /&gt;
    for (uint r = 0; r &amp;lt; h; r++) //строки&lt;br /&gt;
    {&lt;br /&gt;
        for (uint c = 0; c &amp;lt; w; c++) //столбцы&lt;br /&gt;
        {&lt;br /&gt;
            image(r,c) = renderPixel(r, c); //вычисляем цвет в пикселе&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //renderPixel(r, c)&lt;br /&gt;
&lt;br /&gt;
    pixel_color = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
    for (uint j = 0; j &amp;lt; num_rays_per_pixel; j++)&lt;br /&gt;
    {&lt;br /&gt;
        pp = generatePoint(); //генерируем произвольное смещение внутри пикеля&lt;br /&gt;
&lt;br /&gt;
        //вычисляем координаты точки на полотне&lt;br /&gt;
        x = s * (c - 0.5 * w + pp.x);&lt;br /&gt;
        y = s * (r - 0.5 * h + pp.y);&lt;br /&gt;
&lt;br /&gt;
        //cоздаем луч&lt;br /&gt;
        Ray ray({0,0,0}, normalize({x,y,-d}));&lt;br /&gt;
        Ray worldRay = convertToWorldCoords(ray);&lt;br /&gt;
        &lt;br /&gt;
        pixel_color += traceRay(worldRay, 0) * 1.0 / num_rays_per_pixel; //вычисляем цвет для каждого луча и усредняем&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
    //traceRay(ray, depth)&lt;br /&gt;
&lt;br /&gt;
    if (depth &amp;gt; max_depth) //превысили максимальную глубину луча, дальше не идем&lt;br /&gt;
    {&lt;br /&gt;
        return black; //возвращаем черный цвет&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Intersection is = hitObjects(ray); //нашли первое пересечение с объектами сцены и записали информацию о нем в is:&lt;br /&gt;
                                       //материал объекта, расстояние, нормаль и т. п.&lt;br /&gt;
&lt;br /&gt;
    if (is) //если есть пересечение&lt;br /&gt;
    {&lt;br /&gt;
        is.ray = ray; //запомнили луч&lt;br /&gt;
        is.depth = depth; // и глубину&lt;br /&gt;
&lt;br /&gt;
        return shade(is); //расчитали цвет в точке пересечения в зависимости&lt;br /&gt;
                          //от материала объекта, используя информацию о пересечении&lt;br /&gt;
                                        &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getBackgroundColor(ray); //вернули цвет фона&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
//shade(is)&lt;br /&gt;
&lt;br /&gt;
//цвета&lt;br /&gt;
direct_illumination = {0,0,0};&lt;br /&gt;
indirect_illumintaion = {0,0,0};&lt;br /&gt;
&lt;br /&gt;
for (uint i = 0; i &amp;lt; light_count; i++)&lt;br /&gt;
{&lt;br /&gt;
    if (light[i].isVisible(is)) //если источник света виден из точки пересечения&lt;br /&gt;
    {&lt;br /&gt;
         direct_illumination = getIllumination(light[i], is); //рассчитываем прямое излучение от i-го источника света&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if (isReflective(is.object))&lt;br /&gt;
{&lt;br /&gt;
      indirect_illumination = traceRay(reflecedRay(is.ray), is.depth + 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//зная входящее излучение, расчитываем выходящее в зависимости от свойств материала объекта&lt;br /&gt;
//... &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; - ширина полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt; - высота полотна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;depth_{max}&amp;lt;/math&amp;gt; - максимальная глубина луча в рекурсии (помимо первичного луча)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{obj}&amp;lt;/math&amp;gt; - количество объектов сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{lights}&amp;lt;/math&amp;gt; - количество источников света сцены&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;N_{rays}&amp;lt;/math&amp;gt; - число лучей на один пиксел&lt;br /&gt;
&lt;br /&gt;
На каждой итерации ищется пересечение луча со всеми объектами: &amp;lt;math&amp;gt;O(N_{obj})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После нахождения точки пересечения, выясняется, виден ли каждый источник света из этой точки. Для этого нужно найти первое пересечение теневого луча (начало в точке пересечения, направлен к источнику света) и сравнить расстояние до точки пересечения с расстоянием до источника света. Для всего этого требуется &amp;lt;math&amp;gt;O(N_{lights} \cdot N_{obj})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Для каждого луча понадобится &amp;lt;math&amp;gt;O(depth_{max}(N_{obj} + N_{obj} \cdot N_{lights})) = O(depth_{max}\cdot N_{obj} \cdot N_{lights})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
Всего лучей, выходящих из камеры &amp;lt;math&amp;gt;w \cdot h \cdot N_{rays}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге получаем &amp;lt;math&amp;gt;O(depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays})&amp;lt;/math&amp;gt; операций.&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
На вход алгоритму подается описание сцены (описание камеры, видовой плоскости, объектов и их материалов, источников света).&amp;lt;br&amp;gt;&lt;br /&gt;
Выходные данные алгоритма - изображение.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
= Программная реализация алгоритма =&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
== Локальность данных и вычислений ==&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
RenderMan&lt;br /&gt;
&lt;br /&gt;
V-Ray&lt;br /&gt;
&lt;br /&gt;
NVIDIA IRay&lt;br /&gt;
&lt;br /&gt;
NVIDIA mental ray&lt;br /&gt;
&lt;br /&gt;
Hydra Renderer&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
http://www.scratchapixel.com/&lt;br /&gt;
&lt;br /&gt;
http://www.raytracegroundup.com/&lt;br /&gt;
&lt;br /&gt;
http://www.ray-tracing.ru/&lt;br /&gt;
&lt;br /&gt;
= Полученные изображения =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Raytracer_scene1.jpeg&lt;br /&gt;
File:Raytracer_scene2.jpeg&lt;br /&gt;
File:Raytracer_scene3.jpeg&lt;br /&gt;
File:Raytracer_scene4.jpeg&lt;br /&gt;
File:Raytracer_scene5.jpeg&lt;br /&gt;
File:Raytracer_scene6.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rgabdullin</name></author>
	</entry>
</feed>