суббота, 30 апреля 2011 г.

Робастные множественные зеркальные отражения и преломления–Часть 1

 

Ссылка на оригинал статьи:

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch17.html

В этой главе, мы представляем робастный алгоритм для вычисления одиночных и множественных отражений и преломлений на GPU. Для того, чтобы позволить фрагментарному шейдеру иметь доступ к геометрическому описанию всей сцены при поиске целевых точек вторичных лучей, мы в первую очередь представляем сцену как расслоенную карту расстояний. Каждый слой сохраняется как кубическая карта в памяти текстур. Тексели этих кубических карт содержат не только информацию о цвете, но также и о расстоянии от точки отсчета и нормальной поверхности, так что тексели могут быть интерпретированы как упрощенные отображения сцены. Алгоритм производит поиск этого отображения для трассировки вторичных лучей. Процесс поиска начинается с определения лучей, которое позволяет убедиться в том, что ни одно пересечение поверхностей лучей не потеряно, и продолжается секущим поиском, который предоставляет точность.

После того, как мы представили основной механизм трассировки вторичных лучей, мы представляем приложения, включающие одиночные и множественные отражения и преломления на неровных поверхностях. Для вычисления множественных отражений и преломлений, собственный вектор, сохраненный в картах расстояний, прочитывается и используется для генерации отражающихся/преломляющихся лучей. Эти лучи старшего порядка трассируются так же, как и при первом отражении, фрагментарным шейдером. Интенсивность отраженного луча вычисляется в соответствии с упрощенной формулой Френеля, которая также подходит для металлов. Результирующий алгоритм прост в применении, запускается в режиме реального времени и достаточно точен для определения самоотражения. Применение нашего предложенного метода требует поддержки динамического ветвления.

 

17.1 Введение

Синтез изображений вычисляет яркость точек, которые видимы через пиксели виртуальной камеры. Локальные модели освещения вычисляют яркость из локальных свойств – таких как позиция, нормальный вектор и данные о материале – в дополнение к глобальным параметрам источника света. Каждая точка затеняется независимо, что открывает большое количество возможностей для параллельных вычислений. Эта независимая и параллельная концепция затенения широко применяется в современных GPU. Как бы то ни было, для идеальных отражателей и преломителей, яркость точки зависит также от освещения других точек; таким образом, точки не могут быть затенены независимо. Это условие означает, что вычисление яркости точки рекурсивно генерирует новую видимость и задания вычисления цвета для определения интенсивности непрямого освещения.

Основная операция для решения проблемы видимости точки на направлении – трассировка луча. Для получения полного пути нам следует продолжить трассировку луча в целевой точке, чтобы получить вторую точку и точки дальнего рассеивания. GPU производят трассировку лучей с одинаковым источником очень эффективно, делая "фотографию" из совместного источника луча и используя фрагментарный шейдер для вычисления яркости видимых точек. Процесс фотографирования привлекает растеризацию геометрии сцены и использование z-буфера для нахождения первых целей лучей, проходящих через пиксели.

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

Объекты сцены могут быть encoded как набор параметров уравнения поверхности, схожим с классической трассировкой луча (Havran 2001, Purcell et al. 2002, и Purcell et al. 2003). Если геометрия сцены слишком сложная, может быть использовано замещение простыми геометриями, что позволяет быстро аппроксимировать пересечения (Bjorke 2004 и Popescu et al. 2006).

С одной стороны, геометрия сцены может быть сохранена в упрощенной форме. Старейшее применение этой идеи – это карта глубин, используемая теневым алгоритмом, (Williams 1978), которая сохраняет свето-пространственные координаты z для части геометрии, которая видна из позиции света через окно.

Для того чтобы охватить все направления, нам следует использовать кубическую карту вместо одиночного изображения глубин. Если мы сохраняем мировое евклидово расстояние в текселях, кубическая матрица становится похожей на сферическую карту (Patow 1995 и Szirmay-Kalos et al. 2005). Таким образом, пара направлений и значения расстояния определяет точку, видимую на направлении, без знания ориентации сторон карты-куба. Это свойство очень важно, когда мы выполняем интерполяцию между двумя направлениями, так как это избавляет нас от беспокойства о границах сторон карты-куба. Эти кубические карты, сохраняющие значения расстояния, называются картами расстояния.

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

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

Робастный механизм для трассировки вторичных лучей может быть использован для вычисления в режиме реального времени множественных отражений и преломлений.

17.2 Трассировка вторичных лучей

Предложенный алгоритм трассировки луча работает на геометрии, сохраненной в расслоенных картах расстояний. Один из этих слоев – кубическая карта, где тексель содержит свойства о материале, расстояние и нормальный вектор точки, которая находится в направлении текселя. Свойство материала – это отраженная яркость для диффузных поверхностей и множитель Френеля при перпендикулярном освещении для зеркальных отражателей. Для преломителей индекс преломления также сохраняется как свойство материала. Расстояние измеряется из центра кубической карты (то есть от опорной точки).

17.2.1 Generation of Layered Distance Maps

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

Набор слоев, представляющий собой сцену, в общем случае может быть получен очисткой глубины (Everitt 2001 и Liu et al. 2006). Для управления количеством слоев, мы можем ограничить количество очищающих проходов, таким образом, мы располагаем дальние объекты в одном слое в не зависимости от того, пересекают ли они друг друга, как показано на Рисунке 17-1. Если расстояние до дальних объектов значительно больше, чем размер отражающего объекта, эта аппроксимация допустима.

clip_image001

Рисунок 17-1 Расслоенная карта расстояний с 3 + 1 слоями

Для более простых отражающих объектов, которые не слишком близко к окружению, генерация слоя может быть также упрощена. Опорная точка устанавливается в центре отражающего объекта, а лицевая и задняя части отражающего объекта обрабатываются отдельно в двух слоях. Заметьте, что этот метод может заполнить не все тексели слоя, таким образом, некоторые тексели могут не представлять ни одной видимой точки. Если мы очищаем цель обработки с отрицательным значением расстояния до обработки, тексели, не содержащие ни одной видимой точки, могут быть распознаны позже проверкой подписи расстояния.

Когда объекты сцены двигаются, карта расстояний должна быть обновлена.

17.2.2 Трассировка луча в расслоенных картах расстояний

Основная идея рассмотрена с использованием подписей Рисунка 17-2. Вектора мест точек представлены строчными буквами, и вектора направлений обозначены прописными буквами. Пусть центр нашей координатной системы o является опорной точкой, и мы заинтересованы в освещении точки x в направлении R.

clip_image002

Рисунок 17-2 Направленная трассировка

Точка освещения расположена на луче уравнения x + R · d, где d – параметр луча, необходимый для определения. Мы можем проверить точность случайной аппроксимации d, прочитав расстояние окружающей поверхности, сохраненное с направлением l = x + R · d в кубической матрице (|l'|), и сравнив его с расстоянием аппроксимированной точки l на луче |l|. Если |l| ≈ |l'|, тогда мы нашли пересечение. Если эта точка на луче на поверхности, что равно |l| < |l'|, текущая аппроксимация отклонена вниз. С другой стороны, когда точка |l| за поверхностью (|l| > |l'|), аппроксимация отклонена вверх.

Параметр луча d может быть найден при помощи использования итерационного процесса. Процесс начинается с прохода по лучу (то есть линейного поиска) и продолжается секущим поиском. Робастный линейный поиск вычисляет грубое отклоненное вниз приближение и отклоненную вниз аппроксимацию, которая включает в себя первое пересечение луча. Начинаясь с этих аппроксимаций, секущий поиск быстро получает точное пересечение.

Линейный поиск

Точки возможного пересечения находятся на луче. Таким образом, пересечение может быть найдено проходом луча (то есть проверкой точек r(d) = x + R · d, сгенерированных с возрастающей последовательностью положительного параметра d, и определением первой пары последующих точек, где одна точка отклонена вверх, в то время как остальные отклонены вниз). Это реальное пересечение, then, лежит между этими двумя предположениями и найдено с использованием секущего поиска (это будет рассмотрено в следующем подразделе).

Определение пересечений параметра луча d нуждается в более тщательном рассмотрении, потому что теперь геометрия упрощена, и проверка того же образца несколько раз при игнорировании других образцов не имеет ценности. К сожалению, выполнение равномерных шагов на луче не гарантирует, что пространство текстуры равномерно упрощено. При удалении от опорной точки, шаги единичной длины на луче соответствуют меньшим шагам в пространстве текстур. Эта задача может быть решена проходом на линейном сегменте, который выглядит идентично лучу от опорной точки, за исключением того, что его две крайние точки на одном и том же расстоянии. Конечные точки такого линейного сегмента могут быть получены проекцией начала луча, r(0) и конца луча, r() на единичную сферу, результатом которой станут новое начало s = x/|x| и конечная точка e = R/|R|, соответственно. Пересечение должно быть найдено в текселях, которые видимы в направлении между s и e, как показано на Рисунке 17-3.

clip_image003

Рисунок 17-3 Проход на луче, выполняющего равномерные шаги в пространстве текстур

Алгоритм пересечения ищет те тексели, которые делают равномерные шаги на линейном сегменте s и e:

clip_image005

clip_image007

Соответствие между параметрами луча d и t может быть найдено проекцией r' на луч, которая управляется следующей формулой:

clip_image009

Применение фрагментарного шейдера должно брать входные параметры источника луча x и направления Rтакже кубическая карта – карта типа samplerCUBE проходит как uniform-параметр – и последовательно генерирует параметры луча d и точки на луче r, и возвращает параметр отклонения вниз dl и параметр отклонения вверх dp. Отношения |l|/|l'| и |p| / |p'| представлены переменными llp и ppp соответственно. Значения расстояния сохранены в альфа-канале кубической карты. Листинг 17-1 показывает алгоритм для выполнения линейного поиска фрагментарным шейдером.

Алгоритм находит пару последующих точек отклонения вниз и вверх в одиночном слое, подготавливаясь к созданию равномерных шагов Dt на луче в пространстве текстур. Размер шага Dt установлен пропорционально длине линии сегмента s и e и разрешению кубической карты. Установив шаг текселя Dt больше, чем расстояние между двумя соседними текселями, мы ускоряем алгоритм, но увеличиваем возможность потери отражения тонких объектов. В текселе значение расстояния получается из альфа-канала кубической карты. Заметьте, что мы используем функцию texCUBElod() – установку множественного отображения уровня точно в 0 – вместо texCUBE(), потому что texCUBE(), как tex2D(), ускорит компилятор DirectX 9 HLSL для развертывания динамического цикла (Sander 2005).

Линейный поиск должен запускаться для каждого слоя. Слой, где параметр луча (dp) минимальный, содержит первую цель луча.

Ускорение со значениями расстояния Min-Max

Для ускорения поиска пересечения на слое мы вычислим минимальное и максимальное значения расстояния для каждой карты расстояний. Когда трассировка луча произведена, луч пересекается сферами с центрами в опорной точке и радиусом, равным минимальному и максимальному значениям. Две точки пересечения значительно влияют на пограничное пространство луча. Процесс передвигает начальную точку s и конечную точку e ближе, так что меньшее количество шагов перехода даст ту же точность. См. Рисунок 17-4.

clip_image010

Рисунок 17-4 Min-Max ускорение

Example 17-1. Выполнение линейного поиска фрагментарным шейдером в HLSL

1. float a = length(x) / length(R);

2. bool undershoot = false, overshoot = false;

3. float dl, llp; // Параметр луча и |l|/|l'| последнего отклонения вниз

4. float dp, ppp; // Параметр луча и |p|/|p'| последнего отклонения вверх

5. float t = 0.0001f;

6. while( t < 1 && !(overshoot && undershoot) ) {  // Итерация

7. float d = a * t / (1-t);  // Параметр луча, соответствующий t

8.   float3 r = x + R * d;  // r(d): точка на луче

9. float ra = texCUBElod(map, float4(r,0)).a; // |r'|

10. if (ra > 0) {  // Подходящий тексель, то есть ничего не видимо

11. float rrp = length(r)/ra;  //|r|/|r'|

12. if (rrp < 1) {  // Отклонение вниз

13.       dl = d;  // Сохранение последнего отклонения вниз в dl

14.       llp = rrp;

15.       undershoot = true;

16.     } else {  // Отклонение вверх

17.       dp = d;   // Сохранение последнего отклонения вверх как dp

18.       ppp = rrp;

19.       overshoot = true;

20.     }

21.   } else {  // Ничего не видимо: перезапуск поиска

22.     undershoot = false;

23.     overshoot = false;

24.   }

25.  t += Dt;  // Следующий тексель

26. }

 
   float a = length(x) / length(R);
bool undershoot = false, overshoot = false;
float dl, llp;  // Ray parameter and |l|/|l'| of last undershooting
   float dp, ppp;  // Ray parameter and |p|/|p'| of last overshooting
   float t = 0.0001f;
while( t < 1 && !(overshoot && undershoot) ) {  // Iteration
   float d = a * t / (1-t);  // Ray parameter corresponding to t
   float3 r = x + R * d;  // r(d): point on the ray
   float ra = texCUBElod(map, float4(r,0)).a; // |r'|
   if (ra > 0) {  // Valid texel, i.e. anything is visible
   float rrp = length(r)/ra; //|r|/|r'|
   if (rrp < 1) {  // Undershooting
      dl = d;  // Store last undershooting in dl
      llp = rrp;
      undershoot = true;
    } else {  // Overshooting
      dp = d;   // Store last overshooting as dp
      ppp = rrp;
      overshoot = true;
    }
  } else {  // Nothing is visible: restart search
    undershoot = false;
    overshoot = false;
 }
 t += Dt;  // Next texel
}

Очистка секущим поиском

Линейный поиск предоставляет первое простую пару последующих примеров отклонений вниз и вверх, так что реальное пересечение должно лежать между этими точками. Пусть параметры отклонения луча вниз и вверх – dp и dl , соответственно. Соответствующие две точки на луче – p и l и две точки на поверхности – p' и l', соответственно, как показано на Рисунке 17-5.

clip_image011

Рисунок 17-5 Очистка секущим шагом

Приняв то, что поверхность между точками p' and l' гладкая, мы наблюдаем ее пересечение лучом в точке r = x + R · dnew , где

clip_image013

Если одиночный секущий шаг не дает результатов достаточной точности, можно заменить одну из предыдущих аппроксимаций dl или dp (всегда сохраняя одно отклонение и одну отклоняющуюся аппроксимацию), используя dnew, и мы сможем продолжить с этого итерационного шага. Заметьте, что секущий поиск получает точные результаты для плоских поверхностей за один итерационный шаг и требует только конечного числа шагов для плоских сеток. Листинг 17-2 показывает применение фрагментарного шейдера при секущем поиске.

Пример 17-2. Применение фрагментарного шейдера при секущем поиске в HLSL

1. for(int i = 0; i < NITER; i++) {

2. // Параметр луча нового пересечения

3. dnew = dl + (dp-dl) * (1-llp)/(ppp-llp);

4.  float3 r = x + R * dnew;  // Новая точка на луче

5. float rrp = length(r)/ texCUBElod(map, float4(r,0)).a; // |r|/|r'|

6. if (rrp < 0.9999) {  // Отклонение вниз

7. llp = rrp; // Сохранить как последнее отклонение вниз

8. dl = dnew;

9. } else if (rrp > 1.0001) {  // Отклонение вверх

10. ppp = rrp; // Сохранить как последнее отклонение вверх

11. dp = dnew;

12. } else i = NITER;

13. }

   for(int i = 0; i < NITER; i++) {
  // Ray parameter of the new intersection
  dnew = dl + (dp-dl) * (1-llp)/(ppp-llp);
  float3 r = x + R * dnew;  // New point on the ray
   float rrp = length(r)/ texCUBElod(map, float4(r,0)).a; // |r|/|r'|
   if (rrp < 0.9999) {  // Undershooting
    llp = rrp;  // Store as last undershooting
    dl = dnew;
  } else if (rrp > 1.0001) {  // Overshooting
    ppp = rrp;  // Store as last overshooting
    dp = dnew;
  } else i = NITER;
}

Мы помещаем линейный поиск, выполненный для каждого слоя плюс секущий поиск, который обрабатывает одиночный слой, вместе в функцию Hit(). Теперь мы имеем основное средство для трассировки произвольного луча в сцене. Эта функция находит первую цель l. Прочитав кубическую карту в данном направлении, мы можем получить материальные свойства и собственный вектор, ассоциированный с точкой.

Комментариев нет:

Отправить комментарий