суббота, 5 февраля 2022 г.

Volume render, часть 4. Облака

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

Нужно было сделать объемные облака для симулятора, то есть будет возможность подлетать к ним вплотную, смотреть на них с земли и из космоса, что сильно усложняет задачу.


Изучаем существующие решения

Minecraft



  • Используется тот же подход, что в Horizon: Zero Dawn, но шейдер намного сложнее.
  • Есть объемные тени в атмосфере и тени на ландшафте.
  • Недостаточная детализация - вблизи совсем не похожи на облака.
  • Дальность рисования ограничена.
  • При быстром движении камеры видно размытие и "битые пиксели", где неправильно восстанавливается цвет при использовании темпоральных техник.
  • Показан только один слой облаков, неизвестно будет ли корректно работать несколько слоев и насколько это все замедлит.
  • Неизвестно что с производительностью.

Microsoft Flight simulator
  • Больше похоже на 3D частицы (например SPVR), чем на версию из Horizon.
  • Облака слишком прозрачные и с низкой детализацией, похоже это сделано для оптимизации (проще интегрировать).
  • Освещение размытое и слишком серое.
  • Есть тени на ланшафте, но объемных теней похоже что нету.
  • В видео говорится о 32х слоях облаков (и тумана?), если на каждый слой используется маршинг, то понятно зачем им так сильно оптимизировать.
  • Погодные эффекты: дождь, радуга и тд.
  • Неизвестно что с производительностью.

UHawkVR (блог)
  • Используется реймаршинг + дистанс филд.
  • Освещение размытое и слишком серое.
  • Нет анимации облаков из-за долгого обновления SDF 3D текстуры.
  • Заметны патерны тайлинга.
  • Поддержка VR.

Первая попытка

Какие были варианты:
  • Маршинг объема, как во многих современных играх (но в основном шутерах).
  • Билборды как в старых играх.
Версию на билбордах делать сложнее и они хуже смотрятся в VR и при рендере в кубемапу. Поэтому первая версия была на маршинге.

Для карты облаков используется cubemap размером 4096х4096, для Земли точность получается около 1.5км на пиксель, что достаточно мало. Текстуры шумов сделаны как в Horizon: 128x128x128 perlin-worley noise 32x32x32 worley noise, 128x128 curl noise.

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

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



Недостатки:
  • Маленькие 3D текстуры дают заметный тайлящийся патерн при виде из космоса.
  • Сложно конструировать разные формы облаков в одном шейдере.
  • Постоянно нехватает шагов маршинга, особенно если луч проходит через разряженые облака, где размер шага уменьшается в 3 раза.
  • Плохо работает изменение детализации - при добавлении детальных шумов получается больше разряженых пространств, что делает переход между разными уровнями детализации слишком заметным. Увеличение частоты детальных шумов решает эту проблему, но тогда облака больше похожи на пену. На схеме: слева - вид с поверхности на облака, по центру и справа - вид из космоса, получается чем дальше от облаков, тем больше шаг при выборке из 3D текстур и тем больше кэш промахов, что сильно влияет на производительность. 
  • Непонятно как поддерживать слабые GPU типа встроенных Intel и старых дискретных карт.


Почему метод из Horizon плохо работает для симуляторов


Необходимое количество сэмплов. В Horizon это 64 сэмпла на 2.5км, все что выше рисуется не маршингом, а 2D текстурой.


Для симулятора объемные облака нужны во всей атмосфере, то есть на высоте до 13км, а в некоторых случаях и до 30км, что в 5-12 раз больше чем в Horizon. Но кроме взгляда с поверхности есть еще вид внутри слоя облаков вдоль слоя облаков, что для Земли составляет около 780км, это в 300 раз больше чем в Horizon. Небо не всегда заполнено облаками, а маршинг запускается для каждого видимого участка неба, это очень неоптимально, хоть и шагов для пустого пространства намного меньше.

Нехватка сэмплов для освещения. В Horizon использовали 6 сэмплов и этого хватало для апроксимации в таком тонком слое облаков.


В симуляторе слой облаков в 5 раз толще и одного сэмпла для дальних облаков совсем недостаточно. К тому же солнц может быть 2 или 3, а от спутников и колец падают тени, которые нужно учитывать. На закате лучи света проходят намного большее расстояние, для корректного освещения тогда требуется 100 - 1000 сэмплов.

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

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


Ускоряем маршинг облаков

Кроме изучения альтернативных способов, я попробовал ускорить текущий подход насколько это возможно.
  • Сделал 2 типа шейдеров. Первый с высокой детализацией для вида с поверхности планеты, внутри облаков и из космоса вблизи облаков, здесь количество шагов маршинга увеличил до 1024. Второй с низкой детализацией для вида из космоса, где уже не различимы мелкие детали, в нем используется только карта облаков и текстура шума 128х128х128, количество сэмплов для освещения уменьшил в 2 раза, количество шагов маршинга оставил 128.
  • Сделал переменный шаг маршинга в зависимости от расстояния. Это позволило значительно увеличить дальность обзора, а так же уменьшить количетсво шагов маршинга при раннем нахождении пересечений, что немного ускорило рисование.
  • Для 3D текстур сгенерировал мип уровни и включил трилинейную фильтрацию. При автоматическом выборе мипуровней появлялись артефакты, поэтому написал рассчет мипуровня в зависимости от расстояния до камеры. Это в несколько раз увеличило производительность, особенно при виде из космоса.
  • Для сэмплов освещения принудительно снизил мипуровни 3D текстуры, что заметно увеличило производительность.
Теперь в худшем случае у меня было 30мс при взгляде вдаль внутри слоя облаков. В лучшем случае было 2-6мс при виде из космоса. Так как основная нагрузка все еще идет на память из-за чтения 3D текстур, то можно менять производительность за счет выбора мип уровней.


Получаем 2 направления по дальнейшей оптимизации:
  1. Освещение. В идеале хотелось бы кэшировать освещение, чтобы избавиться от лишних сэмплов при маршинге, это ускоряет маршинг в 2 раза (и более, если несколько источников освещения).
  2. Рисование формы облаков. Сейчас много времени тратится на проход по пустым областям в поисках пересечения с облаком, много шагов происходит внутри низкодетализированной области, когда луч не пересекает высокодетализированную область. Маршинг плохо масштабируется и не подходит для создания формы облаков, зато подходит для увеличения детализации вблизи.

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

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