<?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=Vlamakarenko</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=Vlamakarenko"/>
	<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/Vlamakarenko"/>
	<updated>2026-10-23T07:56:44Z</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=20257</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=20257"/>
		<updated>2016-12-07T14:24:49Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Компилятор C++&lt;br /&gt;
|-&lt;br /&gt;
| Intel 13.0.1 + impi 4.1.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&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>Vlamakarenko</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=20256</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=20256"/>
		<updated>2016-12-07T14:24:01Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Компилятор C++&lt;br /&gt;
|-&lt;br /&gt;
| Intel/13.0.1 + impi/4.1.0&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&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>Vlamakarenko</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=20255</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=20255"/>
		<updated>2016-12-07T14:21:28Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;.&lt;br /&gt;
&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>Vlamakarenko</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=19210</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=19210"/>
		<updated>2016-11-26T10:58:09Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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&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>Vlamakarenko</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=19209</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=19209"/>
		<updated>2016-11-26T10:44:04Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|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&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>Vlamakarenko</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=19208</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=19208"/>
		<updated>2016-11-26T10:34:50Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|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;
|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&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>Vlamakarenko</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=19207</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=19207"/>
		<updated>2016-11-26T10:27:15Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&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;
|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&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>Vlamakarenko</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=19206</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=19206"/>
		<updated>2016-11-26T10:22:26Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&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;
|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&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>Vlamakarenko</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=19205</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=19205"/>
		<updated>2016-11-26T10:18:06Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&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;
|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&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>Vlamakarenko</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=19204</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=19204"/>
		<updated>2016-11-26T10:14:58Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&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;
|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&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>Vlamakarenko</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=19203</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=19203"/>
		<updated>2016-11-26T10:12:43Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&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;
|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&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>Vlamakarenko</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=19202</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=19202"/>
		<updated>2016-11-26T10:06:54Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&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;
|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&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>Vlamakarenko</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=19172</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=19172"/>
		<updated>2016-11-25T18:11:48Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Литература */&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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>Vlamakarenko</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=19171</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=19171"/>
		<updated>2016-11-25T18:11:31Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Литература */&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
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>Vlamakarenko</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=19170</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=19170"/>
		<updated>2016-11-25T18:06:12Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Литература */&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
&amp;quot;Scratchapixel 2.0. Learn Computer Graphics From Scratch!&amp;quot;. 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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19169</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=19169"/>
		<updated>2016-11-25T17:55:03Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19168</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=19168"/>
		<updated>2016-11-25T17:54:22Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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 \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N - 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;, где &amp;lt;math&amp;gt;N_p&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19167</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=19167"/>
		<updated>2016-11-25T17:53:58Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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 \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv).&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;math&amp;gt;O(\frac{depth_{max}\cdot N_{obj} \cdot N_{lights} \cdot w \cdot h \cdot N_{rays}}{N_p})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N_p&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19166</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=19166"/>
		<updated>2016-11-25T17:51:23Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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 \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;\Big[\frac{w \cdot h}{N - 1}\Big] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv). Время работы:&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19165</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=19165"/>
		<updated>2016-11-25T17:51:02Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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 \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме первого поручим обработать свою часть изображения (каждый процесс обработает &amp;lt;math&amp;gt;[\frac{w \cdot h}{N - 1}] &amp;lt;/math&amp;gt; пикселей, а оставшуюся часть работы поручим произвольному процессу). Первому процессу поручим принять работу и собрать итоговое изображение (используем MPI_Gatherv). Время работы:&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19164</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=19164"/>
		<updated>2016-11-25T17:45:57Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Ресурс параллелизма алгоритма */&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 \geqslant 2&amp;lt;/math&amp;gt; - количество процессов. Всем процессам, кроме одного поручим визуализировать сцену (каждый процесс обработает &amp;lt;math&amp;gt;[\frac{w \cdot h}{N - 1}] &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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19163</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=19163"/>
		<updated>2016-11-25T17:38:23Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Информационный граф */&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;
== Входные и выходные данные алгоритма ==&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19162</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=19162"/>
		<updated>2016-11-25T17:29:51Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Информационный граф */&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;
== Ресурс параллелизма алгоритма ==&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19155</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=19155"/>
		<updated>2016-11-25T14:31:25Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Raytracer_scene8.jpeg&amp;diff=19154</id>
		<title>Файл:Raytracer scene8.jpeg</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Raytracer_scene8.jpeg&amp;diff=19154"/>
		<updated>2016-11-25T14:25:45Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19153</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=19153"/>
		<updated>2016-11-25T13:39:17Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19150</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=19150"/>
		<updated>2016-11-25T13:00:35Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19149</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=19149"/>
		<updated>2016-11-25T12:59:57Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
Алгоритм перестает масштабироваться, когда время работы параллельной части алгоритма (собственно визуализация) мало по сравнению с накладными расходами MPI и временем, которое расходуется на инициализацию сцены (загрузка сцены из файла, построение оптимизирующих структур данных для ускорения визуализации 3d-моделей).&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19134</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=19134"/>
		<updated>2016-11-25T00:16:23Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19130</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=19130"/>
		<updated>2016-11-24T15:11:43Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Полученные изображения */&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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы каждого процесса становится соразмерным с накладными расходами MPI.&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;
File:Raytracer_scene7.jpeg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vlamakarenko</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=19094</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=19094"/>
		<updated>2016-11-24T12:06:53Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&lt;br /&gt;
&lt;br /&gt;
Алгоритм перестает масштабироваться, когда время работы каждого процесса становится соразмерным с накладными расходами MPI.&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>Vlamakarenko</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=19093</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=19093"/>
		<updated>2016-11-24T12:05:21Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19092</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=19092"/>
		<updated>2016-11-24T12:04:43Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&lt;br /&gt;
&lt;br /&gt;
[[File:Raytracer_stat1.jpg|400px|График ускорения от числа процессов]]&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>Vlamakarenko</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=19091</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=19091"/>
		<updated>2016-11-24T12:04:15Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&lt;br /&gt;
&lt;br /&gt;
[[File:Raytracer_stat1.jpg|200px|График ускорения от числа процессов]]&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>Vlamakarenko</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=19090</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=19090"/>
		<updated>2016-11-24T12:03:47Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&lt;br /&gt;
&lt;br /&gt;
[File:Raytracer_stat1.jpg|200px|График ускорения от числа процессов]&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>Vlamakarenko</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=19089</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=19089"/>
		<updated>2016-11-24T11:25:50Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19088</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=19088"/>
		<updated>2016-11-24T11:24:38Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19087</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=19087"/>
		<updated>2016-11-24T11:24:05Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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|left|300px]]&amp;lt;br&amp;gt;&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19086</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=19086"/>
		<updated>2016-11-24T11:23:31Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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|left|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19085</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=19085"/>
		<updated>2016-11-24T11:23:00Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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|thumb|left|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19084</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=19084"/>
		<updated>2016-11-24T11:21:27Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&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|thumb|left|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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19083</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=19083"/>
		<updated>2016-11-24T11:19:27Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&lt;br /&gt;
Изображение:&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;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19082</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=19082"/>
		<updated>2016-11-24T11:12:21Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|505.963&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|314.106&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|185.988&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|86.771&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|45.171&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|25.555&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|13.962&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;
|}&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>Vlamakarenko</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=19081</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=19081"/>
		<updated>2016-11-24T10:56:47Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|8m:26s&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|5m:14s&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|3m:6s&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|1m:27s&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|0m:45s&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|0m:26s&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|0m:14s&lt;br /&gt;
|-&lt;br /&gt;
|256&lt;br /&gt;
|0m:9s&lt;br /&gt;
|-&lt;br /&gt;
|512&lt;br /&gt;
|0m:6.5s&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>Vlamakarenko</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=19079</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=19079"/>
		<updated>2016-11-24T10:49:52Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Реализация с помощью 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;
== Ресурс параллелизма алгоритма ==&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;
&lt;br /&gt;
Размер изображения 700 на 700 пикселей, 256 лучей на пиксел, глубина рекурсии 3.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Число процессов&lt;br /&gt;
! Время (с)&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|8m:26s&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>Vlamakarenko</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=19078</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=19078"/>
		<updated>2016-11-24T10:44:41Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Масштабируемость алгоритма и его реализации */&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;
== Ресурс параллелизма алгоритма ==&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;
&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>Vlamakarenko</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=19077</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=19077"/>
		<updated>2016-11-24T10:41:39Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Последовательная сложность алгоритма */&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;
== Ресурс параллелизма алгоритма ==&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>Vlamakarenko</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=19076</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=19076"/>
		<updated>2016-11-24T10:41:18Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Последовательная сложность алгоритма */&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;
== Ресурс параллелизма алгоритма ==&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>Vlamakarenko</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=19075</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=19075"/>
		<updated>2016-11-24T10:40:42Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Последовательная сложность алгоритма */&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;
== Ресурс параллелизма алгоритма ==&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>Vlamakarenko</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=18826</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=18826"/>
		<updated>2016-11-21T16:58:24Z</updated>

		<summary type="html">&lt;p&gt;Vlamakarenko: /* Полученные изображения */&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;
Перед камерой на расстоянии &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}&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}.x = s (j -\frac{w}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}.y = s (i -\frac{h}{2} + \frac{1}{2}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{dir}.z = d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нормируем вектор &amp;lt;math&amp;gt;\overline{dir}&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;
&lt;br /&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;
==== Вычисление прямого излучения ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;h_{min}(x,y,z) = \overline{p}+t_{min} \cdot \overline{d}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L_{is} = \sum_i L(S_i, h_{min})&amp;lt;/math&amp;gt; - прямое входящее излучение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L(S_i, h_{min})&amp;lt;/math&amp;gt; - излучение источника света &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;, приходящее в точку &amp;lt;math&amp;gt;h_{min}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суммирование ведется по &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; таким, что &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; &amp;quot;виден&amp;quot; из точки &amp;lt;math&amp;gt;h_{min}&amp;lt;/math&amp;gt;, в противном случае какой-то объект загораживает источник света, и в точку &amp;lt;math&amp;gt;h_{min}&amp;lt;/math&amp;gt; будет падать тень от этого объекта.&lt;br /&gt;
&lt;br /&gt;
==== Вычисление непрямого излучения ====&lt;br /&gt;
&lt;br /&gt;
Рассмотрим упрощенную модель непрямого излучения. Пусть материал объекта &amp;lt;math&amp;gt;O_{min}&amp;lt;/math&amp;gt; обладает способностью отражать свет.&lt;br /&gt;
&lt;br /&gt;
Тогда нужно найти излучение, приходящее со стороны отраженного луча:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;ray(\overline{h}_{min}, \overline{w}_i)&amp;lt;/math&amp;gt; - отраженный луч.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\overline{w}_i = \overline{d} -2\cdot (\overline{n}, \overline{d})\cdot \overline{n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L\{ray(\overline{h}_{min}, \overline{w}_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;
Основные вычисления связаны с:&amp;lt;br&amp;gt;&lt;br /&gt;
1) поиском пересечения луча с объектами сцены.&amp;lt;br&amp;gt;&lt;br /&gt;
2) расчетом излучения от каждого источника света (требуется определить, &amp;quot;виден&amp;quot; ли источник света из точки пересечения с объектом).&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&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>Vlamakarenko</name></author>
	</entry>
</feed>