Войти
Вячеслав ЕгоровСтатьи

Атмосферные эффекты в играх (Crytek, перевод) (2 стр)

Автор:

3. Расчёт солнечного света


  Возможно, самая фундаментальная часть отрисовки открытых пространств заключается в правдоподобном небе, которое меняется с течением времени. Несколько методов с различным уровнем качества и сложности были разработаны на протяжении лет. С целью точной отрисовки солнечного света в CryEngine2, была использована модель Нишиты (см. список литературы), так как она позволяет создать отличные виды закатов, и предоставляет некоторые средства контроля вывода для художников. К сожалению, это одна из наиболее сложных для вычисления техник. O’Neil представляет реализацию для частного случая (симулятор полёта), который работает целиком на GPU, что потребовало некоторых упрощений для реализации. Используя эти подходы, стало возможным реализовать модель Нишиты в рамках текущих аппаратных решений, за цену некоторых артефактов отрисовки (цветовые переходы часто имели “слоистые” разрывы).
  Цель CryEngine2 заключалась в получении как можно более высокого качества изображения с приемлемой скоростью работы. Отказавшись учитывать некоторые факторы, которые зависят от положения камеры над землёй (нам не требуется передвигаться в верхних слоях атмосферы), мы можем обновлять небо только в зависимости от времени, тем самым делая это достаточно редко. Реализация использует структуры для ускорения, предложенные в оригинальном документе. К примеру, мы считаем, что солнечные лучи приходят параллельно, и поэтому можем создать двухмерную таблицу данных, которая хранит угол между входящими солнечными лучами и зенитом, а также оптическую глубину, в зависимости от высоты слоя атмосферы (слои распределены экспоненционально, в соответствии с характеристиками атмосферы). Для отрисовки был выбран смешанный GPU\CPU подход, так как нахождение интеграла функции рассеивания света для получения промежуточных результатов для пересечений view вектора с n слоями атмосферы для каждой точки семплирования на полусфере неба требует выполнения цикла. На процессоре мы считаем интеграл функции рассеивания для 128х64 точек полусферы неба, с использованием  текущего времени, направления солнца, коэффициентов рассеивания М'и (Mie) и Рэлея (Rayleigh), и сохраняем результат в floating point текстуре. Полное обновление текстуры распределёно по нескольким кадрам для уменьшения влияния на скорость движка. Одно распределённое обновление типично занимает порядка 15-20 секунд. На процессорных архитектурах, предоставляющих векторные операции (например, на консолях вроде Xbox360 и PS3) стоимость расчёта может быть существенно уменьшена. Полученная текстура используется в каждом кадре для отрисовки неба на графическом ускорителе. Однако прямое использование текстуры из-за малого размера привёло бы к явным блочным артефактам, поэтому, для повышения качества часть работы производиться во фрагментном шейдере. Найдя результат фазовой функции в каждом фрагменте (то есть, мы не “запекаем” его в текстуру низкого разрешения), умножим его на результат рассеивания для данной точки на поверхности полусферы (выборка из текстуры с фильтрацией). В результате, мы полностью избавимся от блочных артефактов даже около солнца, где яркость соседних пикселей очень быстро меняется.
  На графических ускорителях с относительно быстрой работой динамических ветвлений может быть возможным перенести текущий подход расчёта интеграла функции рассеивания полностью на GPU. Благодаря двухмерной таблице данных, код уже довольно компактен. Первые тесты переноса C++ версии расчёта на HLSL показали, что используя ветвления это займет около двухсот шейдерных инструкций. На данный момент цикл производит 32 итерации. Это число экспоненционально распределённых слоёв атмосферы было принято достаточным для производства точного результата интеграла функции, и создаёт хорошо выглядящее небо даже на таких “стресс тестах” вроде отрисовки закатов. Зная, что примерно 32*200=6400 инструкций придется выполнить для нахождения интеграла функции рассеивания для каждого сэмпла на полусфере, было просто необходимо распределить расчёты на несколько кадров (то есть, отрисовывать последовательно отдельные части квада, обновляя разные части текстуры). Но в любом случае, с данным подходом скорость полного обновления текстуры стала бы гораздо меньше.

4. Глобальный объёмный туман


  Даже не смотря на то, что модель Нишиты производит, несомненно, отличные результаты, она всё ещё слишком дорога для того, чтобы применять её повсюду в сцене (то есть, считать интеграл функции рассеивания вдоль видового луча из камеры к фрагменту, получая цвет фрагмента в соответствии с атмосферной моделью).
  Поэтому было решено предоставить атмосферную модель, которая может применить свои эффекты на стандартных объектах сцены. В этом разделе мы расскажем о решении, реализованном в движке CryEngine2. Как создать взаимодействие с тем, как рассчитывается солнечный свет будет описано в следующей главе. Данное решение происходит от недорогой функции расчёта тумана, результат которой зависит от высоты и расстояния и имеет экспоненциональный спад.
Изображение
fфункция распределния плотности тумана
bглобальная плотность тумана
cспад по высоте
vвидовой вектор от камеры(о) к мировой позиции фрагмента (о+d), t = 1
  Также следует позаботиться над случаем, когда вектор взгляда смотрит точно горизонтально (и dz равен нулю). Это реализуется в следующем куске HLSL кода.
float ComputeVolumetricFog(in float3 worldPos, in float3 cameraToWorldPos) 
{  //cVolFogHeightDensityAtViewer = exp(-cHeightFalloff * vfViewPos.z); 
  float fogInt = length( cameraToWorldPos ) * cVolFogHeightDensityAtViewer; 
  const float cSlopeThreshold = 0.01; 
  if(abs(cameraToWorldPos.z) > cSlopeThreshold) 
  { 
    float t = cHeightFalloff * cameraToWorldPos.z; 
    fogInt *= (1.0 - exp(-t)) / t; 
  } 
  return exp(-cGlobalDensity * fogInt); 
} 

Листинг 1. Расчёт коэффициента объёмного тумана в HLSL коде

  Условие “if”, при компиляции транслируется в cmp инструкцию и предотвращает проблемы с возникновением значений бесконечности, которые могут пойти дальше по коду и испортить расчёты на дальнейших стадиях (tone mapping, пост процессинг, и т.п.) Весь этот код транслируется в 18 инструкций, при использовании компилятора HLSL и шейдерной модели 2.0.
  Эта функция возвращает значение от нуля до единицы, которое может быть использовано для смешивания тумана. Для непрозрачной геометрии сцены эта модель может быть применена с помощью простой отрисовки одного полноэкранного квада (как описано во второй главе), с установленным шейдером, который вызовет эту функцию для каждого фрагмента. Остается только узнать, как следует рассчитывать цвет тумана, который будет хорошо переходить в цвет неба и смешиваться с ним.

5. Объеденение цвета неба и глобального объёмного тумана


  Создавая отдельные модели для расчёта цвета неба и глобального объёмного тумана, у нас возникает  небольшая проблема. Теперь у нас есть две модели частично решающих одну проблему: как нарисовать атмосферную дымку или туман. Вопрос в том, возможно ли объединить эти две модели для совместной работы. Мы хотим реализовать модель освещения, которая позволит:
- получить гало вокруг солнца при установке дымных атмосферных кондиций
- реализовать приятные цветовые переходы для получения чувства глубины сцены
- позволит увидеть воздушную перспективу (оттенок цвета гор в дали, которые частично находятся в тумане, должен соответствовать цветам неба для данного времени и настроек атмосферы).
  Модель Нишиты позволяет добиться требуемых эффектов, но слишком дорога для использования в общем случае. Модель глобального объёмного тумана, представленная в предыдущей главе, подходит для отрисовки реального времени, но имеет слишком много ограничений.
Для того чтобы две модели подходили друг к другу, нам нужен способ определить цвет тумана, который может быть использован с результатом функции ComputeVolumetricFog для приятного слияния геометрии сцены с небом. Для этой цели модель Нишиты была немного расширена для того, чтобы производить недорогие по-пиксельные расчёты цвета тумана, соответствующие цвету неба на горизонте в требуемом направлении. Для реализации этого все сэмплы, найденные в процессе обновления текстуры неба для направлений представляющих горизонт, усредняются и сохраняются для дальнейшего использования во фрагментном шейдере. Использование всех сэмплов у горизонта для производства более подходящего цвета тумана выглядит привлекательно, но было обнаружено, что разница едва заметна и не стоит дополнительных затрат на шейдерные расчёты. При отрисовке тумана можно использовать тот же самый код, который находил финальный цвет неба. Фазовая функция рассчитывается, как и раньше, только вместо выборки из текстуры низкого разрешения, хранящей результаты рассеивания света, мы используем усреднённые семплы у горизонта, рассчитанные на процессоре. Далее, используя значение функции ComputeVolumetricFog, цвет в буфере кадра может быть смешан с цветом тумана. Возможно это не совсем корректно с точки зрения физики света, но даёт хорошие результаты за очень малую цену расчёта.
Страницы: 1 2 3 4 Следующая »

#atmospheric crysis

22 октября 2007

Комментарии [7]