Объемная задача

В обновлении «Новая сила» в War Thunder у самых результативных игроков в бою появилась возможность использовать атомное оружие. И появилась чертовски интересная задача создания визуального эффекта атомной бомбардировки.

Исходя из существующих в 40-х и 50-х годах калибров советского и американского тактического атомного вооружения, мощность взрыва была выбрана на уровне 30-40 килотонн (бомбы Mark 4 и РДС-2), а высота подрыва — порядка 200 метров (при этом обеспечивается наибольшее воздействие наземной ударной волны). Мощность и высота подрыва очень во многом определяют качественную картину взрыва и его развитие.

Целью был не только сам визуальный эффект грибовидного облака (который можно было бы выполнить в широкой вариации), а максимально правдоподобная картина взрыва со всеми сопутствующими эффектами – превращение огненного шара во вращающийся огненный тор, образование пылающего кольца внутри по мере остывания внешних слоёв облака взрыва, формирование огненной «юбочки», характерной для невысоких контактных атомных взрывов, образование конденсационных облаков во влажном воздухе. Все эти эффекты были изучены по литературе, посвященной физике воздушного атомного взрыва и документальным хроникам атомных испытаний, проведенных в СССР и США. Итоговая форма взрыва не повторяет ни один из проведенных в реальности взрывов – но основными источниками вдохновения были картины испытаний Upshot-Knothole “Grable”, Upshot-Knothole “Annie” и Buster-Jangle “Easy”.

Длительность эффекта атомного взрыва очень высока. На полное развитие облака взрыва в горячей фазе уходит около 30-40 секунд. На рост до стратосферы и развеивание уходят десятки минут. Все эти фазы должны плавно переходить друг в друга, любая склейка или смена одного «поколения» частиц другим будут сразу же заметны. А если фазы пропустить, или схематически развить и развеять эффект за десяток секунд – теряется вся претензия на какой-либо реализм.

Вдобавок, игра допускает и подразумевает свободный полёт камеры вокруг поля боя – поэтому изображение плоского взрыва из нескольких слоев качественно анимированных спрайтов и частиц (как это сделано в Call of Duty, Metro 2033 и др) является неприемлемым. Несмотря на высокое качество, такой эффект будет виден только с одного ракурса, а при малейшем движении камеры в сторону станет понятно, что он является плоской плашкой.

Изображение взрыва обычными партиклами в трёхмерном пространстве тоже является неприемлемым – потребуются многие тысячи, если не десятки тысяч, больших по размеру частиц со сложными траекториями движения и цветовыми кривыми. Наложение этих частиц друг на друга будет стократным, это мгновенно съест все возможные резервы по производительности из-за постоянной перезаписи видеопамяти. А при уменьшении числа частиц они станут различимы в эффекте, во многом из-за щелканья при сортировке.

Итоговый список требований к эффекту выглядел так:

  1. Большая длительность эффекта

  2. Произвольный ракурс и облеты камеры (в том числе возможный пролёт внутри эффекта), произвольное время суток и погода.

  3. Вменяемое влияние на производительность и минимальный расход видеопамяти

Объёмное решение

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

A_{RGBA}(x, y, z, t)

Численное интегрирование этой функции через реймаршинг даёт итоговую картинку на экране.

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

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

Топологическое разделение облака атомного взрыва
Топологическое разделение облака атомного взрыва

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

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

Шляпка гриба является наиболее характерной частью объемного эффекта.

Из общей области, занятой эффектом, выделяется зона, занятая шляпкой. Декартовы координаты в этой зоне приводятся к диапазону -1..1, и далее преобразуются в тороидальные r, ?, ?. Внешний радиус тора R является одним из параметров эффекта, изменяющихся со временем. Полученные семейства торов не совсем верно повторяют требуемую форму поверхности, поэтому на исходную систему координат накладывается искажение

y'=y +( 0.5-d )

где d – радиус-вектор точки в цилиндрической системе координат эффекта. Это искажение воздействует на торы, и на больших радиусах мы получаем форму луковицы, более похожую на картину реального взрыва.

Базовые функции плотности эффекта в тороидальной системе координат r, ?, ? очень просты, например, saturate(1-r). Поэтому для координаты каждого пикселя эффекта вносится возмущение трехмерным перлиновским шумом, в результате чего целостность тороидальных поверхностей нарушается, а эффект теряет симметрию и приобретает детали. Сам шум сэмплируется в тороидальных координатах, в которых и проводится его смещение вдоль поверхности торов. После этого перлиновский шум с другим масштабом читается ещё раз, что позволяет увеличить детализацию и спрятать тайл. Для имеющего места в реальности неравномерного вращения внутренние части тора вращаются в три раза быстрее внешних. На итоговом эффекте можно заметить эту поверхность разрыва.

Базовая светимость в ходе «горячей» фазы эффекта определяется простой функцией

S = max( 0, perlin + k(r, t) - r)

которая обеспечивает остывание внешних слоев тора перед внутренними. Если варьировать функцию k(r, t), можно получить разные профили остывания, и получить быстро гаснущие внешние слои и долгоживущее огненное кольцо внутри.

На скриншотах последовательно показана исходная система координат, искаженная и после наложения шумов (сам эффект показан в разрезе).

Преобразования координат шляпки гриба в разрезе
Преобразования координат шляпки гриба в разрезе

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

После окончания интегрирования, зная конкретные точки входа и выхода из реймаршинга, на эффект накладывается объемный туман.

Другие области грибовидного облака определяются схожим образом, со своими динамиками смещения в своих системах координат и профилями остывания.

Развеивание

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

Эффект без воздействия ветра и с ним
Эффект без воздействия ветра и с ним

Требуется трехмерная карта смещений, изменяющаяся со временем под воздействием турбулентного ветра.

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

При рендере каждого кадра для текстуры офсетов 32х32х64 проводится интегрирование в обратном направлении по времени.

Ofs(x, y, z,t)= - \int_t^0 {wind(x', y', z',t')dt'}

x’, y’, z’ не равны x, y, z, так как по мере движения по времени точка пространства, в которой берется ветер, также смещается. В качестве ветра используется комбинация из нескольких турбулентных шумов.

Обратное направление времени используется потому, что текстура смещений решает не прямую задачу (куда со временем сместится заданная точка облака?), а обратную (откуда в заданную точку облако прилетело?). При реймаршинге через объем требуется решение именно второй задачи.

Интеграл вычисляется численно по дискретным шагам времени. При этом для первого шага (в момент времени t) функция ветра берется в еще не наступивший момент времени t’, соответствующий дискретизации. Величина вклада этого шага в общий интеграл умножается на

(t'-t) / ?t

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

Оптимизация

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

Согласно изначальному топологическому разделению на шляпку, юбочку, ножку и основание, сам эффект был разделен на четыре цилиндрических слоя, отсортированных по высоте перед отрисовкой. В пределах каждого слоя выполняется переход только в одну систему координат, что заметно улучшает контроль потоков в пиксельном шейдере. Ценой за использование этой методики является четырехкратная перезапись пикселя при виде сверху, при этом в каждом из пройденных слоев реймаршинг набирает плотность с нуля. Но для всех прочих ракурсов подобный подход ускорил эффект до 100%, во многом из-за естественного ограничения растеризуемого объема и сокращения реймаршинга по пустым областям, что особенно важно для «рыхлых» краёв эффекта (где полная плотность не набирается никогда), в том числе при виде сверху.

Разбиение одного объёмного эффекта на четыре
Разбиение одного объёмного эффекта на четыре

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

В игре уже имеется ТАА, накладываемый на кадр после отрисовки всех других эффектов, поэтому добавление джиттера позволило визуально увеличить число шагов интегрирования в 4 раза. Сам эффект, как и остальные эффекты прозрачного прохода, рисуется в половинном разрешении, и далее апскейлится на экран.

Тем не менее, чуда не происходит: полученный эффект не является быстрым с точки зрения отрисовки, но на максимальных настройках при рендере в половинном разрешении для FullHD на видеокарте GeForce 1060 GTX выполняется за 3 мс для стандартных ракурсов и около 8 мс в худших случаях, когда эффект целиком занимает весь экран и рисуется с наименее оптимального направления, что с учетом размера эффекта и его роли в игре выглядит оправданным. Тем не менее, остаются возможности для более глубоких оптимизаций эффекта.

Выводы

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

Одна из первых рабочих версий эффекта
Одна из первых рабочих версий эффекта

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

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

Итоговая версия эффекта с конденсационными куполами
Итоговая версия эффекта с конденсационными куполами

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