glTF: скелетная анимация

В следующей версии Dagon наконец-то дебютирует поддержка анимации в сценах glTF. Поддерживается GPU-скиннинг, причем универсальный — для любого объекта можно передать в рендер-пайплайн набор матриц костей (за это отвечает объект Pose) и необходимые вершинные атрибуты (индексы матриц костей и веса).

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

auto characterNode = characterModel.node("character");
characterPose = New!GLTFPose(characterNode.skin, assetManager);
characterPose.animation = characterModel.animation("walk");

Entity character = characterNode.entity;
character.pose = characterPose;
characterPose.play();

Можно прикреплять объекты к костям при помощи родительской связи:

Entity weapon = addEntity(characterModel.node("arm_right").entity);
weapon.drawable = someWeaponMesh;

Dagon 0.21.0

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

  • Переход на SDL 2.32. Под Linux движок теперь предоставляет готовую библиотеку libSDL2-2.0.so, которая копируется в папку с приложением — чтобы ее использовать вместо системной, нужно собирать с флагом линкера "lflags-linux": ["-rpath=$$ORIGIN"] (либо перед запуском задавать рабочую папку в LD_LIBRARY_PATH, что, на мой взгляд, намного менее удобно)
  • Текстуры теперь загружаются через библиотеку SDL2_Image, если она присутствует. Благодаря этому появилась поддержка прогрессивных JPEG, WebP, AVIF, SVG и множества других форматов. Необходимые библиотеки также копируются в проект при сборке (для 64-битных Windows и Linux). Также можно реализовать и подключить к AssetManager кастомный загрузчик изображений
  • Поддержка текстур формата KTX. Полноценная поддержка KTX1 и KTX2. Текстуры, сжатые в Basis Universal, транскодируются в S3TC/RGTC/BPTC или распаковываются в RGBA8, в зависимости от заданной пользователем настройки. Поскольку для этого требуется дополнительная библиотека, за загрузку KTX отвечает расширение dagon:ktx
  • Расширение dagon:physfs, которое позволяет примонтировать в AssetManager виртуальную файловую систему PhysFS и загружать ассеты из архивов
  • Упрощенные тени в SimpleRenderer: дефолтный шейдер затемняет пиксели в зависимости от удаленности от указанной точки в плоскости XZ, создавая кружочек тени под объектом. Радиус затемнения можно контролировать, чтобы сделать либо мягкий кружок, либо резкий. Центр тени можно привязать, например, к позиции персонажа
  • 4-байтное выравнивание в текстурах, которые загружаются из файла вместе с mip-уровнями
  • Функция isExtensionSupported для проверки поддержки расширений OpenGL. Также maxTextureUnits и maxTextureSize — для опрашивания максимального количества текстурных блоков и максимального размера текстуры.

Полный список изменений читайте на странице релиза.

SDL_Image и загрузчики текстур

Вслед за KTX я решил улучшить в движке ситуацию с поддержкой стандартных форматов изображений. Отныне Dagon загружает текстуры с помощью SDL_Image, если библиотека присутствует, системно или локально. В противном случае используется старый загрузчик на основе dlib.image. Преимуществом такого подхода является гарантированная под Windows поддержка огромного числа форматов, включая современные WebP и AVIF; также автоматически решается застарелая проблема с декодированием прогрессивных JPEG.

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

(далее…)

Chillwave Drive

Значительно обновлена демка физики автомобиля на Dagon, которая отныне называется Chillwave Drive. Трение колес теперь моделируется на чистых силах вместо встроенных джоинтов Newton, что сделало симуляцию более точной и стабильной. При движении используется динамическое трение (продольное и поперечное) на основе формул Pacejka ’98, при остановке — статическое, препятствующее боковому скольжению машины на склоне. Улучшено управление с контроллера, также добавлена новая модель машины и шейдер неба с облаками и сменой дня и ночи.

Скачать готовую сборку демки под Windows можно тут.

Dagon 0.20.0

Вышло небольшое, но важное обновление Dagon. Добавлена поддержка кастомных шейдеров для текстурирующих слоев материала ландшафта — это делает систему невероятно гибкой, так как вы можете рисовать на ландшафте все, что захотите. В качестве примера в движок добавлен шейдер луж (dagon.extra.puddle) с эффектом кругов от дождевых капель. Также появилась поддержка Matcap для фейковых отражений (особенно полезная фича в в SimpleRenderer, где нет честных отражений), поддержка glTF-расширения KHR_materials_emissive_strength, доступ к материалам glTF по именам. Обновлена библиотека Newton под Linux.

В репозитории проекта открыты обсуждения: https://github.com/gecko0307/dagon/discussions

KTX в Dagon

Наконец-то реализовал давнюю идею поддержки текстур в формате KTX (Khronos Texture). Это контейнер, специально созданный для OpenGL и Vulkan и поддерживающий большое количество форматов текстур, включая сжатые. Особенно интересен KTX2, который позволяет хранить текстуры в формате Basis Universal — он хорош тем, что позволяет при создании игровых ресурсов не волноваться, что сжатие не будет поддерживаться на системах каких-то пользователей. Формат сжатия выбирается движком игры на основе информации от видеодрайвера, а затем текстура на лету транскодируется в этот формат. Эта фича нужна главным образом на мобильных платформах, но и в десктопном движке не помешает — Basis Universal сжимает очень эффективно и транскодируется в S3TC или BPTC за считанные мгновения.

Текстура KTX1/KTX2 загружается в объект KTXAsset, при его создании необходимо указать приоритет транскодирования. Если это TranscodePriority.Size, то загрузчик отдает предпочтение S3TC, если TranscodePriority.Quality — BPTC (при наличии поддержки). Также можно использовать TranscodePriority.Uncompressed, чтобы получить наилучшее качество — текстура будет распакована в RGBA8.

Пример:

TextureAsset aTextureBox;
TextureAsset aTextureEnvmap;

// В конструкторе сцены:

registerKTXLoader(assetManager);

// На стадии запроса ассетов:

aTextureBox = addTextureAsset("data/box.ktx2");
aTextureBox.conversion.hint = TranscodeHint.Size;

aTextureEnvmap = addTextureAsset("data/cubemap.ktx2");
aTextureEnvmap.conversion.hint = TranscodeHint.Quality;

// При создании материалов:

material.baseColorTexture = aTextureBox.texture;
environment.ambientMap = aTextureEnvmap.texture;

Dagon 0.19.0

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

  • Добавлен модуль dagon.core.persistent — простая БД типа «ключ-значение», которую можно использовать для управления пользовательскими данными игры, такими как настройки и сохранения;
  • InputManager теперь поддерживает разделенные пробелами имена кодов клавиш в привязках. Вместо пробела используется символ плюса, например, kb_left+ctrl для левого Ctrl;
  • Dagon-приложение теперь устанавливает кодировку консоли на UTF-8 в Windows, чтобы нормально выводился нелатинский текст;
  • Добавлен SimpleRenderer, о котором я уже писал ранее — облегченный рендерер для казуальной и стилизованной графики;
  • Добавлена поддержка бокс-проекции для световых зондов. Ее можно включить с помощью свойства Entity.probeUseBoxProjection. Зонды теперь используют альфа-спад для плавного смешивания с данными в G-буфере — благодаря этой фиче сглаживается граница между интерьерным и уличным освещением. Для управления этим эффектом введено свойство Entity.probeFalloffMargin;
  • Добавлена поддержка ортогональных проекций: свойство RenderView.projection теперь принимает константы Perspective, Ortho и OrthoScreen. RenderView.orthoScale управляет масштабом проекции в режиме Ortho;
  • Добавлен новый примитив — цилиндр ShapeCylinder, а также Billboard (прямоугольник, который всегда направлен в сторону камеры);
  • Материалы теперь поддерживают произвольные преобразования текстур (аффинные матрицы 3×3) благодаря свойству Material.textureTransformation. Метод Material.setSprite(Vector2f uvSize, Vector2f uvPosition) можно использовать для наложения на квады фрагментов текстуры — полезно для рендеринга спрайтов и покадровой анимации;
  • Добавлен новый пакет dagon.collision — базовая система обнаружения столкновений;
  • В контроллере персонажей NewtonCharacterComponent появилась поддержка приседания (метод crouch) и улучшенная проверка земли.

Обновления

Улучшения в Dagon

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

dmech, мой старый физический движок, включает продвинутые алгоритмы проверки столкновений, которые до недавнего времени пропадали зря (в частности, Minkowski Portal Refinement и солвер Джонсона) — я решил исправить этот недочет и добавить их в Dagon в качестве пакета dagon.collision. В данный момент он поддерживает обнаружение пересечений между любыми выпуклыми телами и проверку пересечения выпуклого тела с лучом.

Продолжаю работу над упрощенным рендером, о котором уже писал ранее. Появились билборды и универсальная ортографическая проекция: теперь можно, к примеру, легко сделать изометрическое 3D со спрайтовой графикой, как на скриншоте. Среди прочих улучшений — рефакторинг компонента FreeviewComponent и улучшенный контроллер персонажа Newton (появилась поддержка приседания). Оптимизирован deferred-рендер, сокращено количество переключений кадровых буферов. Добавлен новый встроенный примитив — цилиндр.

BindBC-GLSLang

Написал биндинг к glslang, референсному компилятору GLSL от Khronos — можно генерировать модули SPIR-V для WebGPU-приложений прямо в D, без использования внешнего ПО.

https://github.com/gecko0307/bindbc-glslang

Раздел со статьями

Добавил раздел «Статьи» для быстрого доступа к ним. Там, в основном, написанное за последние 10 лет и доступное онлайн, так как более ранние мои материалы публиковались еще в PDF-версии журнала «FPS» и бумажных изданиях — ссылки на них поставить затруднительно.

Упрощенный рендеринг

По мере усложнения стандартного рендер-движка Dagon, повышаются и системные требования — в данный момент он требует довольно мощную видеокарту геймерского класса (желательно NVIDIA, желательно не ниже Turing). Но, поскольку далеко не все игры обязаны иметь топовую графику, неплохо предусмотреть в движке некий облегченный режим, оптимальный для казуальных жанров и стилизации под ретро, где не нужен сложный пайплайн с реалистичным освещением и PBR. В Dagon рендер уже давно структурно вынесен в отдельную систему, которую можно модифицировать и даже полностью заменять, не трогая остальной код движка — модель данных сцены и менеджер ресурсов в Dagon полностью независимы от рендера. Это позволило без особых сложностей добавить упрощенный рендер-движок SimpleRenderer, который вы можете создать в вашем классе игры (на базе Game или Application) и заменить им стандартный DeferredRenderer.

SimpleRenderer полностью переопределяет рендеринг объектов. Здесь по умолчанию нет физически обоснованных источников света, карт окружения и т.д. — за освещение отвечает простейшая модель Блинна-Фонга, которая в данный момент работает с одним глобальным направленным источником света (environment.sun текущей сцены). Нет normal mapping’а и прочих эффектов материала — учитывается только baseColorFactor/baseColorTexture. Но зато вы можете назначить вашим материалам любой шейдер с любыми эффектами — в DeferredRenderer такой возможности нет (все объекты с пользовательскими шейдерами трактуются как forward и рендерятся отдельно, после всех deferred-проходов). Также в этой системе поддерживаются слои, что позволяет явным образом задавать порядок рендеринга группам объектов — например, можно занести все прозрачные объекты в отдельный слой, который рисуется поверх дефолтного.

SimpleRenderer отлично подойдет для создания игр для low-end железа, он будет работать даже на самых слабых системах.

Бокс-проекция

Добавил в Dagon поддержку бокс-проекции для световых зондов окружения (EnvironmentProbe). Техника старая, но никем не отмененная — а главное, хорошо сочетается с deferred-рендером!

Стандартный environment mapping предполагает, что стенки виртуальной среды, с которой считывается освещение, бесконечно удалены от объектов сцены. Это допущение работает для открытого пространства, но не годится для интерьера. Бокс-проекция корректирует сэмплинг из карты окружения так, что результат выровнен по сторонам бокса заданного размера, благодаря чему минимумом ресурсов достигается сносного качества непрямое освещение в интерьере (если, конечно, карта окружения 1 в 1 совпадает с моделью комнаты). Это эффективный способ аппроксимировать локальный GI в ограниченном пространстве: окружение интерьера, с которого рендерилась карта, статичное, но любые другие объекты могут быть динамическими. При трансформации камеры или объекта внутри комнаты, отражения соответствующим образом меняются, причем как зеркальные, так и диффузные.

Получается даже имитировать объемные источники света! На скриншотах ниже нет ничего, кроме параллельного источника света для солнца и двух статичных карт окружения — для улицы и для интерьера. Отражения окон и светящегося блока на полу получаются автоматически:

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