Как правильно лить воду: секреты создания воды в видеоиграх

В этом материале много воды. А вот в играх её, наоборот, возмутительно мало.

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

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

Embedded Image

Subnautica

Вода на локации — это в первую очередь объём, то есть часть пространства. С точки зрения движка, это не жидкость, а блок, для которого программисты задают параметры: границы этого блока, высота, физические особенности. Например, так можно установить скорость плавания и глубину, на которой персонажи переходят в «плавучее» состояние. Причём по умолчанию этот блок совсем не похож на воду — в нём нет ни цвета, ни текстур, ни анимаций.

Разработчики стараются обмануть игрока. В том же Unreal Engine вода — это прямоугольный параллелепипед, который меняет физические правила для персонажа, когда тот оказывается внутри заданных границ. С визуальной точки зрения накладывается постпроцессинг — размытие, глубина резкости, искажение и цветовой оттенок. Даже симуляция течений — это обычно поля скоростей, то есть опредёленные объёмы, которые применяют к персонажу ускорение в конкретном направлении.

Embedded Image

Геймплей-программист

Источник

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

Остальные параметры водного блока остаются на усмотрение разработчиков и могут сильно отличаться в разных играх. Так, на локациях из Resident Evil: Revelations иногда поднимается уровень воды, но физическая симуляция тут ни при чём: у блока воды просто меняются параметры высоты и ширины, отчего объём «растягивается».

Resident Evil: Revelations

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

Subnautica

Поверхность водного пространства зачастую работает по схожему принципу — с помощью фильтров, эффектов и текстур. Разработчики ранних 3D-игр старались избежать любой дополнительной нагрузки на процессор, поэтому делали воду совершенно плоской, как в Quake, а то и вовсе статичной — как в Tomb Raider.

Постепенно разработчики учились экспериментировать с поверхностью воды. Так, в Shadow Warrior она стала полупрозрачной, а рельсовый шутер Panzer Dragoon открывался огромным морским уровнем, где на водную гладь накладывались простейшие отражения.

В The Legend of Zelda: Ocarina of Time на воде появились базовые эффекты мерцания и световых бликов. Причём на производительность они почти не влияли — движок просто дважды накладывал одну и ту же текстуру с небольшим отступом, а дальше всё зависело от мастерства художников.

The Legend of Zelda: Ocarina of Time

В Super Mario Sunshine встречаются два типа водной поверхности: заранее размещённая на уровне вода, то есть океан, озёра, реки, — и отдельные лужи, которые мог создавать сам игрок. Для вторых разработчики создали иллюзию высыхания. Стреляя из водяного пистолета, игрок размещал на локации небольшие блоки воды, которые вскоре начинали сжиматься: уменьшаться в радиусе и высоте. А похожий подход потом появился в серии Splatoon.

Super Mario Sunshine

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

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

Dark Messiah of Might & Magic

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

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

Embedded Image

Геймплей-программист

Шейдер NVJOV для Unity (Источник)

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

На консолях шейдеры закрепились с выходом Halo: Combat Evolved, на ПК — после The Elder Scrolls III: Morrowind. Технологии Bungie и Bethesda оказались более гибким и менее ресурсозатратным решением для создания отражений и бликов. Также в них появились и новые эффекты — например, анимированная пена, рябь и следы от дождевых капель на воде.

Вскоре Half-Life 2 добавила к уже привычным эффектам рефракцию — преломление света. Она позволила искажать геометрию находящихся под водой объектов и имитировать светопропускные особенности жидкости, а эффект был лучше всего заметен на не полностью погруженных предметах — например, сваях или плавающих бочках. Для преломления движок Source создавал карту рефракции (refraction map) — эффект, схожий с картой отражений, но направленный вглубь воды.

Half-Life 2

BioShock показал, насколько важно художественное исполнение шейдеров. Большая часть игры разворачивается в городе на глубине океана, поэтому поверхность воды игрок почти не видит, а вот «изнутри» смотрит на неё регулярно через окна-иллюминаторы. Чтобы водное пространство нельзя было перепутать с обычным воздушным, разработчики использовали прозрачные частицы — для пузырей воздуха, например, — и лёгкий эффект ряби. А внутри помещений эта же рябь проецировалась на стены, создавая игру света и тени.

BioShock

Шейдеры надолго останутся в игровой индустрии. Их использует даже трассировка лучей, да и сами по себе они постоянно развиваются. Например, в Far Cry 5 шейдеры целиком работают с PBR — физически корректными материалами, которые гораздо убедительнее показывают свет и тени на воде. Но как бы красиво ни выглядела плоская вода, для реалистичного результата движок должен обрабатывать и её геометрию — то есть, создавать волны.

Шейдерные волны на Unreal Engine 4 (Источник)

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

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

Embedded Image

Геймплей-программист

Волны с тесселяцией появились ещё в 90-х годах. В гоночной аркаде Wave Race 64 поверхность воды, на которой разворачивался игровой процесс, уже состояла из грубой полигональной сетки. Вблизи от игрока движок собирал отдельные треугольники в полноценные волны, которые учитывали столкновения и подбрасывали аквабайки участников. Но на расстоянии нескольких метров вода оставалась плоской, чтобы не нагружать систему, — впрочем, из-за небольшого разрешения экрана в глаза это не бросалось.

PlayStation 2 позволила рисовать реалистичные волны с помощью двух отдельных векторных процессоров, которые были встроены в ЦПУ консоли — Emotion Engine. Они создавались специально под быструю отрисовку объёмной графики: процессоры обрабатывали геометрию объектов, создавали волны, искажения, собирали все изменения в один пакет и отправляли его в графический процессор PS2. При этом нагрузка на ЦПУ оставалась минимальной.

Dark Cloud

Один из наиболее красивых примеров этой технологии — Baldur’s Gate: Dark Alliance. В игре было множество водных поверхностей, от полноценных локаций вроде затопленной канализации до простого фонтана на площади. Любые объекты и персонажи, которые оказывались в воде, создавали волны — а те ещё несколько раз отражались от препятствий и других персонажей.

Baldur’s Gate: Dark Alliance

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

Волны на основе формул Герстнера в Unreal Engine 4 (Источник)

В открытом мире Grand Theft Auto IV физика волн влияет сразу на все находящиеся в воде или около неё объекты. На водной глади остаются круги от низко летящего вертолёта, а если он упадёт в воду — поднимется небольшая волна. Если эта волна дойдёт до причала, то сможет поднять пришвартованную там лодку или даже отнести её ближе к берегу.

Grand Theft Auto IV

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

Чтобы объект необычной формы правильно двигался в воде, для него нужно рассчитать объём части тела, которая погружена в воду, скорость движения, высоту волн и другие факторы. Но если нужно экономить ресурсы, можно прикрепить к объекту невидимые «буйки» — сферы с заданными плотностью и объёмом, к которым и применяется выталкивающая сила. Так, например, плавучесть реализована в Unreal Engine 4.26.

Лодка с невидимыми плавучими «буйками» в Unity (Источник)

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

Uncharted 3: Drake’s Deception

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

Симуляция жидкостей в Houdini (Источник)

Например, разработчики платформера Blinx: The Time Sweeper постарались реалистично воссоздать движение водных масс. Главный герой, кот Блинкс, умел останавливать время, при этом вода на локациях тоже застывала — игрок буквально протаптывал сквозь неё свой путь. Когда время снова включалось, застывшая вода приходила в движение и заполняла образовавшиеся из-за игрока пустоты. За этот эффект отвечал сложный вершинный шейдер — Vertex Rippling, который умел просчитывать коллизию водяной поверхности с другими объектами.

Blinx: The Time Sweeper

А в Half-Life 2 движок Source убедительно реализовал плавучесть и плотность объектов в воде. Игра учитывала тип материала, из которого сделан предмет: кирпичные блоки сразу шли ко дну, а куски дерева оставались плавать. Разработчики могли точно настраивать этот параметр, что помогло создать основанные на физике загадки — например, пропасть, которую можно пересечь только по плавучим строительным катушкам.

Half-Life 2

Хоррор «Анабиоз: Сон разума» впервые использовал для симуляции воды движок Nvidia PhysX. В этом случае акцент делался на переходе воды из жидкого состояния в твёрдое и обратно: из-за действий игрока локации оттаивали, а лёд превращался в отдельные лужицы, которые могли разбиваться или собираться в единую массу. За этот процесс отвечала система частиц PhysX Particles & Fluid, от которой компания потом отказалась в пользу воксельных жидкостей NVIDIA Flow.

Анабиоз: Сон разума

Разработчики другого хоррора — Hydrophobia: Prophecy — тоже стремились к реалистичной физике жидкостей, но уже в масштабе целых помещений. Созданный специально для игры движок HydroEngine умел топорно обрабатывать объёмы воды и их перемещение в реальном времени — так, игрок мог открыть дверь в затопленную каюту и создать большую волну, которая бы пронеслась через весь коридор. Правда, выглядела эта жидкость как угловатое желе, а его поверхность иногда сбоила и выстраивалась в неправильные формы.

Hydrophobia: Prophecy

В симуляторе бога From Dust вода тоже состояла из частиц, которыми игрок мог управлять — собирать жидкость в одном месте, выливать в другом, осушать реки и создавать озёра. От «эффекта желе» игру спасали динамические текстуры на поверхности, которые сглаживали углы и добавляли воде динамики.

Также движок Lyn учитывал взаимодействие воды с другими типами поверхности — песчаными и каменистыми берегами, густыми лесами и лавой. Сами частицы воды в From Dust — довольно крупные и не всегда правильно работают с небольшими объёмами, но в масштабах целых морей и островов это трудно заметить.

From Dust

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

Симуляция течения жидкости отчасти похожа на симуляцию тканей — так называемую Position Based Dynamics. Эта система представляет объект в виде набора элементарных физических элементов — например, точек или небольших сфер.

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

Embedded Image

Геймплей-программист

Источник цитаты:

Как устроена система Position Based Fluids (Источник)

Физика воды активно развивается последние 30 лет и не только в трёхмерной графике. В статье мы обошли стороной жидкости в 2D, хотя там интересных физических законов и честных симуляций тоже достаточно. Особенно после недавнего релиза Noita — игры, в которой не просто вода правильно растекается, тушит огонь и так далее, но и другие материалы разных типов взаимодействуют друг с другом и влияют на игровой процесс. Впрочем, это уже тема для отдельного материала.

Александр Балакшин также ведёт курс в XYZ School под названием Gamecode — для тех, кто увлекается программированием и хочет создавать экшен-игры в Unreal Engine 4. До 30 апреля на курс действует скидка 20% — а новый поток стартует 1 мая.