Хотелось сделать игру предельно физичной, чтобы не скрипты, а физические законы управляли игровым миром, чтоб реализм вместо грубоватых скриптов, чтоб можно было всё разрушать и предсказывать последствия не исходя из капризов разработчика, а из поведения среды.
В этой статье рассказывается об опыте создания такой игры.
В качестве модели мира выбрана симуляция двумерной материи на основе множества взаимодействующих частиц.
Опорный игровой жанр - артиллерия, вроде Scorched Earth. В этой игре изначально была заложена разрушаемость земли, но она была статичной: из холма вычитался выжигаемый взрывом кружок. Это было круто и свежо для эпохи доса, но пришло время желать большего.
Моя идея состояла в том, чтобы скрестить игру из жанра песочницы (вроде "Powder Toy" или "OE CAKE") со старой доброй артиллерийской стрелялочкой. То есть, реализовать аркадный геймплей в физической симуляции.
Первая проблема состояла в том, что для сложного и просторного игрового мира требовались десятки тысяч частиц, а процессоры тянули в лучшем случае тысячи, даже если очень постараться по части оптимизации, а такой опыт у меня был, я с физикой и раньше поигрывал.
Решение меня потрясло, требовалось просто перейти с процессора на видеокарту. Производительность видеокарт оказалась в 50-100 раз выше, чем у процессоров, и для параллельной обработки десятков тысяч частиц они годились идеально. Я не ожидал такого гигантского бонуса, но получив его, понял, что игра будет сделана ровно такой, какой я её задумал, без компромиссов.
Без компромиссов, впрочем, не обошлось, но о них ниже.
Непосредственный кодинг шейдера для обсчёта физики оказался простым и приятным. Язык HLSL хорошо развит, и изначально относится к семейству СИ-подобных, так что начать программировать получилось сразу. Проблемы были только с тем, чтобы разобраться, как индексируются потоки, но хелп в msdn очень подробный, так что дело пошло.
Компилятор языка HLSL нашёлся в Юнити, там есть классы ComputeShader и ComputeBuffer, которые предоставили исчерпывающий интерфейс для вычислений на видеокарте.
Решив технические вопросы, я вплотную занялся непосредственно физикой.
Модель была простая: есть множество частиц, взаимодействующих по формуле Леннарда-Джонса, которая соединяет притяжение и отталкивание, так что частицы тяготеют к образованию "материи", располагаясь в узлах гексагональной решётки.
Каждая частица описывалась координатами и вектором скорости. Плюс, набором дополнительных параметров, вроде температуры, цвета, типа физического материала и т.д. Данные о частицах располагались в видеопамяти. На каждом шагу для каждой частицы требовалось изменить скорость на основе создаваемых соседями сил и продвинуть частицу вперёд вдоль вектора скорости.
Чтобы перейти от O(N^2) к O(N * log(N)), я использовал стандартный метод, двумерную решётку, каждая ячейка которой запоминала лежащие на её площади частицы, чтобы затем при обсчёте каждая частица обращалась не ко всем частицам, а только к соседям по узлу решётки. В итоге, каждая из десятков тысяч частиц взаимодействовала лишь с десятком соседей.
Рендер сделал так же в шейдерном коде, каждая частица рисовалась на текстуре в виде нескольких пикселей.
После реализации первой версии модели получилось вот так:
Комментарий недоступен
Ага.