Математика в Gamedev по-простому
описание
Как на самом деле работают стрельба, толпа NPC, графика, физика тканей и свет в играх. Разборы на пальцах, рабочий код, интерактивы. dev-math.ru Сотрудничество: @it_bizdev
Лучшие посты
за три месяцаГде на экране этот треугольник https://dev-math.ru/articles/spaces/ Всю неделю я рассказывал о том где именно находится вершина. Что камеру в 3D на самом деле не двигают — двигается весь мир вокруг неё. Что далёкие поверхности мерцают не из-за материалов, а из-за near, прижатого к нулю. Обещанная статья готова: проходим дорогу одной вершины целиком — от строчки в вашем коде до конкретного пикселя на экране. Плюс разбор, почему отметка Static и статик-батчинг в Unity вообще не спорят с «мир едет навстречу камере». Да, если серия нравится, и статья интересна. Делимся ей с друзями и ставим 🔥. А то я что, не блогер, это не сказать. #devmath #графика #математика #3d #mvp #проекция
Дизеринг и гамма-коррекция: почему градиенты «бандятся» и откуда грязь в тёмных сценах https://dev-math.ru/articles/dithering/ Люблю писать такие статьи. Когда я начинал заниматься что графикой, что трекингом, меня очень часто больше всего увлекало на сколько это мир физических ограничений. Нюансы вывода изображения на экран. Нюансы человеческого зрения и тому подобное. Параллельно изучая такие технические моменты ещё и узнаешь, а как что в этом мире работает. И это то, чем меня увлекла когда-то клиентская разработка в отличии от бекенда. Помимо мнгновенного результата действий, то что ты не живешь в чистой абстракции, а сталкиваешься с нюансами практического мира. Итак. Мы разбирали по кускам тему всю неделю. Теперь полная статья с разбором, интерактивами и так далее. Бандинг, дизеринг, как работает гамма-коррекция, что такое линейное цветовое пространство и зачем оно надо (да и попутно объясняется зачем была нужна гамма). На сайте произошел большой редизайн. Светлая тема мне нравится наверное чуть больше. Но в основном так как я решил делать игру во вселенной своих комиксов и рилсов. Позже анонс будет размещён на сайте по игре (думаю я управлюсь за 4 месяца ну или хотя бы постараюсь). А так репосты и 🔥 как всегда приветствуются. Это мотивирует писать статьи и дальше. Ведь кому-то это интересно. #devmath #графика #квантование #дизеринг #sRGB #linearworkflow
Треугольник становится пикселями https://dev-math.ru/articles/raster/ Вершина добралась до экрана — три точки в пиксельных координатах. Но сам треугольник ещё не закрашен, а на этом коротком отрезке конвейера живёт своя пачка знакомых багов. Разбираем: — почему тонкий провод вдали мерцает и рвётся; — и почему добавить ему полигонов бесполезно; — отчего далёкие поверхности дерутся полосами друг сквозь друга — и при чём тут near, а не far; — как один и тот же кадр выходит то в пять слоёв, то в один — не тронув ни единого полигона; — почему на PlayStation 1 текстуры «плыли» — и что за одно деление это лечит. #devmath #графика #математика #рендер #растеризация
Толпа без AI: как три правила, хеш-сетка и ORCA делают массовку живой https://dev-math.ru/articles/crowd/ Вы просили про толпу. Ну держитесь 🙂 Семь разделов, шесть интерактивов и тысяча юнитов в одном экране браузера. Я заморочился — получилось так объёмно, что статьи скоро можно сшивать в книжку (Поэтому немного задержался. Хотел в пятницу, а получилось в субботу). Жду огоньков и репостов друзьям 🔥 Симуляция массовки упирается в две проблемы: общий behavior tree «толпа делает X» не масштабируется, а наивный поиск соседей даёт O(N²) и кладёт сцену уже на пятистах юнитах. В статье разбираю архитектуру по слоям: три правила Рейнольдса для группового движения, uniform spatial hash для поиска соседей за O(N), упрощённый ORCA для встречных потоков в коридоре, steering behaviors для целей и обхода препятствий, плюс отдельная часть про GPU instancing для рендера тысячи юнитов одним draw call'ом. В финале — разбор под капотом AC Unity, World War Z, They Are Billions, Vermintide 2 и RTS-обобщённо. #мат_геймдев #МатРазбор #algorithms #AI
Толпа на максималках: flow fields, GPU и десятки тысяч юнитов в кадре https://dev-math.ru/articles/crowd-gpu/ Помните прошлую статью про толпу? Я остановился на тысяче юнитов и оставил четыре вещи «на потом» — flow fields, симуляцию на GPU, indirect draw и LOD AI. Обещал продолжение, да и вы за него проголосовали — и вот оно 🙂 Четыре интерактива (один — честная 3D-сцена на three.js, с реальным счётчиком draw call'ов), и снова получилось так объёмно, что впору сшивать в книжку. Жду огоньков и репостов друзьям 🔥 Тысяча юнитов на CPU — это разминка. Десятки тысяч в кадре (Париж в AC Unity, битвы Total War, орды нежити) — уже другая архитектура из четырёх слоёв. Глобальный путь перестаёт быть тысячей независимых A* и становится одним flow field — сеткой направлений на всю толпу за O(1). Симуляция агентов уезжает с ядер CPU на тысячи дорожек GPU (compute shaders + StructuredBuffer). Рендер перестаёт быть draw call'ом на агента и становится indirect draw, где команды отрисовки генерит сам GPU. А то, что не видно вблизи, не считается честно — LOD AI и recycling. В финале — разбор под капотом Planetary Annihilation, Supreme Commander 2, AC Unity, Total War, They Are Billions и Helldivers 2. Первая часть, если пропустили: https://dev-math.ru/articles/crowd/ Думаю на этом тема толп в играх раскрыта окончательно :) #мат_геймдев #МатРазбор #algorithms #GPU
Путь одного draw call Всю неделю мы считали, чем платим за кадр: в понедельник — командами, во вторник — байтами на шине, в среду — когерентностью варпов, в четверг — сменами состояния. Обещанная статья готова: «Путь одного draw call» — проходим дорогу команды рисования целиком, от строчки в вашем коде до пикселя на экране, со всеми четырьмя валютами на местах. В общем я довольно подробно описал разные части графического конвейера, и не как стандартную схему и так далее, а более практично в контексте движка. Читать: https://dev-math.ru/articles/drawcall/ #devmath #графика #математика #gpu #drawcall #оптимизация
Почему далёкая текстура мерцает https://dev-math.ru/articles/textures/ Мне очень нравится конечно составлять эти статьи, так как помимо описаний для понимания компьютерной графики, для меня они являются погружением в ностальгическое прошлое. Как всё было придумано и зачем. В статье разберем: - почему тексель — не пиксель и что на самом деле делают nearest и билинейная фильтрация; - откуда берётся мерцание вдали — алиасинг при уменьшении — и как его лечат мипмапы; - почему при взгляде вдоль пола картинка мылится и что с этим делает анизотропная фильтрация; - сколько всё это весит в памяти и как устроено блочное сжатие BCn и ASTC; - и как эти решения складываются в один запрос к сэмплеру. Ставьте 🔥 и делитесь с друзьями, если статья была интересна. В будущем возможно я сошью это в какой-то учебник по компьютерной графике, который уже будет за символическую цену, чтобы желающие могли поддержать автора так сказать. А пока поделиться постом лучшая поддержка. #devmath #графика #математика #рендер #текстуры
В Fallout 3 нет ни одного поезда https://youtube.com/shorts/0Dw4ciULxYQ?si=2GqaYJOx-ryyU72f Поездка на метро есть — в дополнении Broken Steel. А поезда нет: движок не умеет катать по миру объект, внутри которого сидит игрок. Он умеет ровно две вещи — водить персонажа и надевать на него предметы. Поэтому вагон сделали одеждой. В файлах он так и лежит: недоступная броня на слот правой руки. Игрок садится — дальше всё делает скрипт. Надевает броню, включает свой пакет камеры и гонит игрока по путям. Снаружи — метро. Внутри — человек, который надел поезд и побежал. Нравится мне тут не костыль, а причина, по которой он не палится. Подмену нельзя заметить в принципе: пока вагон приклеен к игроку, в его системе отсчёта вагон стоит, а движется мир. Ровно корабль Галилея, только с метро. Про этот вагон, кстати, ходит красивая неправда: будто это шляпа, надетая на невидимого NPC, который бежит под миром. Версия пошла с вброса на 4chan. Слот не головной, и надевает вагон сам игрок — это видно в GECK, официальном редакторе Bethesda, куда фанаты и залезли в 2015-м. #геймдев #fallout #devmath #fallout3
Про свет по-простому https://dev-math.ru/articles/lighting/ Поговорим про свет. Про Ламберта, про Блинна и про Фонга. Если вы не знали или хотите освежить как устроено освещение в игровых движках — это чтиво для вас! Я постарался собрать полную картину с историей, как всё это работает и как всё это придумывалось. Это пока не PBR с BRDF, эти вещи у нас будут темой следующей недели, но это первый шаг к физически корректному освещению. Вообще чтобы понимать как устроена 3д графика, в первую очередь я считаю, что нужно знать базу того, как всё работает и придумывалось. Это и дает понимание как использовать то, что уже давно сделано и дает пищу для создания новых креативных идей. Ведь чтобы сделать свой хитрый, стилизованный свет полезно знать как работает обычное освещение играх. Да и это база потребуется нам в будущем, когда мы перейдем к более комплесным эффектам и шейдерам. В общем как и обещал: "Я сделаль". 🔥 и репосты приветствуются. #devmath #свет #Ламберт #Фонг #Блинн
Квиз про графику https://dev-math.ru/dave-quiz/ Актуализировал квиз. Раз мы уже прошли с вами большую часть пути и вышло столько статей про графику, то давайте проверим знания небольшим квизом. 15 вопросов по темам что вышли и что выйдут. От самых простых про то, что такое UV до вопросов посложнее. В общем можно за 5 минут понять, а всё ли вы с ходу знаете из того, что я рассказывал 8 недель. #devmath #квиз
Шанс 50/50 выбить нож в CS стоит 660 $ Шанс ножа в кейсе — 0,26%. Эту цифру Valve не публиковала: сообщество годами восстанавливало её по статистике анбоксингов. В 2017-м Министерство культуры Китая обязало раскрывать вероятности лутбоксов, и таблицу выложил Perfect World — издатель, через которого Valve работает в Китае. Чтож, посчитаем. Памяти у кейсов нет, попытки независимы: шанс хотя бы одного ножа за N кейсов — 1−(1−0,0026)^N. Сотня кейсов — должно же хватить? Конечно же нет: 23%. Монетка 50/50 набегает только к 267-му кейсу — те самые 660 $ ключами. Уверенные 99% — 1769 кейсов, около 4 400 $. Ну и моё любимое: остаться без ножа после двух тысяч кейсов вдвое вероятнее, чем выбить его из первого же. Не верите — посчитайте. Пустой кейс — это 99,74%. Возведите в степень 2000: остаётся 0,55%. А нож с первой попытки — те самые 0,26%. Шанс «всё ещё пусто» тает вдвое каждые 266 кейсов и нуля не достигает никогда: из 100 000 человек, открывших по 2000 кейсов, около 550 останутся ни с чем — хотя «в среднем» нож выпадает на 385-м. И вот что я в этой истории так же люблю: та же Valve в Dota подкручивает криты в вашу пользу, лишь бы серия промахов не испортила вам вечер. В кейсах серия неудач продаёт ключи, поэтому кейс номер 2000 ничем не отличается от первого. Даже Genshin даёт гарантию на 90-й крутке. Тут — ни на какой. Шансы при этом честные, жульничать тут и не нужно. #мат_геймдев #МатРазбор #геймдизайн
Flow fields: один расчёт вместо тысячи A* Тысяча юнитов идёт к одной точке. Если для каждого считать A* — тысяча независимых поисков за кадр. Дороговато. Как нам сделать меньше расчётов? По своей сути, идея проста. Можно сделать один расчёт вместо тысячи. Посчитали поле — все юниты просто читают из него «куда идти из своей клетки». Разбиваем карту на сетку. От цели обратной волной (Dijkstra) в каждой клетке считаем дистанцию до цели и записываем вектор на соседа — это и есть flow field. Юниту достаточно прочитать вектор из своей клетки. O(1) на запрос, без зависимости от длины пути и количества юнитов. «А если цель движется?» В RTS — почти никогда. Клик в точку, поход к зданию — цель статична, поле живёт минутами. При движущейся цели перерсчитать получается в любом случае не так дорого. Одну дейкстру пустить по карте не так долго, как для каждого юнита считать А*. Тем более с шумом от boids там не обязательно моментальная реакция на пользовательский ввод или триггеры. Проблема возникает если много юнитов и у каждого своя цель — A* снова в выигрыше. Flow fields — это про движение толпы к общей цели. Канонический разбор — Elijah Emerson, AI Game Programming Wisdom 5 (2008). #мат_геймдев #МатРазбор #algorithms #AI
Почему далекие поверхности мерцают? Проблема: две далёкие поверхности — стена и налепленный на неё декаль, земля и дорога — начинают дрожать и «драться за пиксель», стоит чуть двинуть камеру. Первое желание — лезть в материалы, сортировку, освещение. А чинится это обычно в настройках камеры. Виновник — ближняя плоскость near, выставленная слишком близко к нулю. Классика: near = 0.01, чтобы близкое не обрезалось, и far = 1000, чтобы видно было далеко. Выглядит безобидно. Но точность буфера глубины распределена не поровну. При near = 0.01 и far = 1000 у дальней плоскости соседние значения глубины (в типичном 24-битном буфере) ошибаются почти на 6 единиц — всё, что ближе ~6 единиц друг к другу, буфер там уже не различает. Отсюда мерцание. И вот что неочевидно: далёкую точность рушит именно ближняя плоскость. Сдвиньте near с 0.01 до 1 при том же far — и различимость глубины вдали улучшится примерно в сто раз. Даже 0.01 → 0.1 даёт ×10. Решает не разность far − near, а их отношение far/near: чем оно больше, тем хуже вдали, а главный рычаг — не тянуть near к нулю. Практический вывод, который снимает целый класс мерцания: держите near настолько далеко, насколько терпит сцена, а far — настолько близко, насколько можно. Чем у́же диапазон, тем чище глубина. Прежде чем крутить материалы — проверьте эти два числа. А почему точность вообще нелинейна — это прямое следствие проекции и деления на w. Разберём в пятницу: в статье будет интерактив, где видно кривую глубины и что с ней делает ползунок near. #геймдев #графика #математика #zfighting #рендер #камера
Тысяча юнитов в кадре — это, конечно, эффектно. Но в AAA это только начало. Давайте пройдемся до конца по толпе тогда (по результатам опроса). А потом уже пойдем либо к лутбоксам, либо к ELO и MMR. В прошлой статье мы разобрали, как оживляют тысячу юнитов через boids + spatial hash на CPU. При этом в Assassin's Creed Unity на улицах Парижа — до 10 000 NPC одновременно. В массовых битвах Total War: Warhammer 2 — тоже десять тысяч, у каждого свой коллайдер и анимация. В Helldivers 2 — плотные волны термидов на одного игрока. They Are Billions — название говорит за себя. По сути, любая CPU-архитектура решения из прошлой статьи на этом масштабе отвалится. У проблемы два слоя, которые мы не разобрали — глобальная навигация через flow fields (много готовых реализаций, но для такой задачи уже лучше написать свою) и перенос симуляции на GPU (compute shaders + indirect rendering). Разберем на этой неделе. Всё как обычно со статьей в конце недели. Данная тема прикольна ещё тем, что если углублятся в детали реализации (особенно рендера), то станет понятнее как работает та же Nvidia Flex и подобные технологии. Ну и делимся постами, ставим реакции, пишем чего хотелось бы ещё в комменты. Короче статьи, больше каких-то примеров. Хочется понимать, что интересно, а что нет. А то по SDF статью посмотрело меньше народу, чем даже по толпе, а вышла она уже неделю как. #мат_геймдев #МатРазбор #algorithms #performance
Матчмейкинг по-простому: Сигнал и шум https://dev-math.ru/articles/matchmaking/ В этот раз пост наоборот пораньше, так как много дел на выходных. Одна из самых "математичных" статей получилась. Так как я в целом люблю тервер и статистические процессы, то даже интересно было писать и редактировать. Постарался максимально простым языком объяснить сложные математические понятия. Хотя на самом деле математика всего лишь "язык", который многих пугает, хотя он просто описывает различные процессы. Главная мысль — на все полвека одна. Истинный скилл это скрытый сигнал, который нельзя увидеть напрямую. Один матч — шумная однобитная выборка из него. А рейтинг — это фильтр, который оценивает и сам сигнал, и собственную неуверенность в нём. Вся эволюция ELO → Glicko → TrueSkill ровно про это: как сделать фильтр умнее. ELO — фиксированное доверие к одному матчу (тот самый K) и логистическая сигмоида, откуда берётся «400 очков = ×10 шансов». Glicko добавляет второе число RD — адаптивный K, который сам понимает, про кого мы знаем мало. TrueSkill описывает скилл целым гауссовым колоколом N(μ, σ) и раздаёт его по команде через factor graph. В финале — кто это крутит в проде: Chess.com и Lichess на Glicko, Rocket League, Halo на TrueSkill. Не забываем делиться статьей с друзьями, если она понравится — это помогает развитию канала. Больше подписчиков богам подписчиков. Ну и ставим огоньки естественно. Автор работает за классы :) Я стараюсь в одиночку на пару с клодом делать качественные материалы и хочется чтобы их увидело как можно больше людей. Небольшая ремарка. На самом деле такая математика больше про геймдизайн, чем про разработку. Обычно геймдизайнеры подобные системы отдают на интеграцию. Но это геймдизайнеры математического баланса, которые есть не в каждой студии, да и самому быть осведомленным в таких вещах довольно полезно. #мат_геймдев #МатРазбор #algorithms #matchmaking
Математика невезения: как игры подкручивают случайность, чтобы она ощущалась честной https://dev-math.ru/articles/lootboxes/ Всю неделю мы разбирали рандом по кусочкам — сегодня забираем всю кухню разом. Внутри вывод констант, пять интерактивов прямо в браузере и цифры, после которых надпись «шанс 1%» читается иначе. Жду 🔥 и репостов друзьям 😆 Игроки читают «1% дропа» как «1 из 100», а random в игре считают честным броском — оба утверждения неверны, и на этом зазоре держатся и фрустрация, и часть монетизации. В статье случайность разобрана как три слоя. Первый — генератор: LCG в одну строку, детерминизм seed и история pack.png с перебором 2⁴⁸, спектральный тест Кнута и провал RANDU. Второй — искажение распределения под восприятие: PRD в Dota с численным выводом константы C, pity-системы Genshin и Hearthstone, true hit Fire Emblem, aim assist XCOM и shuffle bag Тетриса. Третий — экономика дропрейта: геометрическое распределение, 385 против 267 кейсов до ножа CS, кривая 1−(1−p)^N и регулирование лутбоксов от Китая 2017-го до отменённого штрафа EA в Нидерландах. Разработчик получает карту выбора инструмента — голый PRNG, PRD, pity или shuffle bag — и честный список цен, которыми оплачивается каждое сглаживание дисперсии. #мат_геймдев #МатРазбор #алгоритмы #геймдизайн
Про отражения в Duke Nukem https://youtube.com/shorts/2yb0Pn-n94k?si=I6mKOw7dFLzbh3xX В зеркале Duke Nukem 3D — не отражение, а построенная за стеной вторая комната. Движок 96-го не умел в отражения: за зеркалом просто копировали комнату целиком, и твой двойник вставал по ту сторону вживую, кадр за кадром. #devmath #gamedev #dukenukem #рендеринг #математикавиграх
Гонитесь за числом дроуколлов, а тормозит другое Допустим в оптимизации вы гонитесь за числом draw calls: объединяете меши, чистите объекты — и счётчик Batches ползёт вниз. Дело конечно хорошее. А кадр работает всё так же медленно, особенно на мобилке. Смотрите профайлер внимательнее: draw calls упали, а вторая цифра рядом, SetPass calls, — нет. Что это за цифра? Дело в том, что это две разные вещи. Batch (draw call) — это просто команда «нарисуй» на текущем состоянии. А SetPass случается, только когда состояние надо СМЕНИТЬ: другой шейдер, другая текстура, другой блендинг, другой Z-тест. Сто вызовов на одном материале — это один SetPass и куча дешёвых команд следом. А смена материала между вызовами — это новый SetPass: перенастройка конвейера, и в тяжёлом случае видеокарта сливает всё, что уже запустила, прежде чем переключиться. Это и есть флаш конвейера (pipeline flush). Собственно, вот тема дня: цену кадру набивает не сколько вы рисуете, а сколько раз между вызовами меняете стейт. Поэтому один материал со статик-батчингом летит — сотни мешей идут одним SetPass'ом; а десяток материалов вперемешку кладёт кадр, хотя вы не добавили ни полигона — вы добавили переключений контекста. Жёстче всего флаш на смене render target: у мобильных тайловых GPU это выгрузка целого тайла в память,. Техника дальше весьма логичная. Меньше разных материалов и шейдеров, свести похожее в один материал и атлас, сортировать по стейту, чтобы объекты с одним состоянием шли подряд. Батчинг, инстансинг и SRP Batcher по-разному делают одно и то же — держат стейт на месте, чтобы конвейер переставлять приходилось как можно реже. Подробнее разберу завтра. #devmath #графика #математика #gpu #батчинг #оптимизация
«Ну сейчас-то повезёт» — это ошибка игрока. А в Dota — фича. Чтож. Начнём неделю лутбоксов и дропрейта. Предмет с «25% крита» на первом ударе критует примерно в 8,5% случаев. Цифра в тултипе не врёт — врёт интуиция о том, как она считается. В Dota крит — не честная монетка, а система с памятью (pseudo-random distribution). То самое «ну сейчас-то повезёт» здесь буквально зашито в формулу: каждый удар без крита поднимает шанс следующего. Старт ~8,5%, дальше выше, к двенадцатому удару крит гарантирован. В среднем по дистанции выходят те самые 25%. Зачем так? Честные 25% дают жирный хвост невезения: не критануть восемь раз подряд — это 10% случаев, и встречается оно сплошь и рядом. Каждый такой стрик игрок читает как «игра жульничает». PRD режет именно хвост: дольше без крита — ближе крит. Но за это вы слабее в начале серии — короткие неудачные полосы как раз учащаются. По сути, вы не стали критовать чаще, вы перестали попадать в катастрофические серии. Это обмен дисперсии на предсказуемость, который продаётся как «честность». В статье — вся кухня: как «случайность» умещается в одну строку кода, почему «1% дропа» это совсем не «1 из 100», и где эта математика правит уже не восприятие, а ваш кошелёк 🙂 #мат_геймдев #МатРазбор #геймдизайн
без подписи