Dagon 0.27.0

Выпустил новую версию движка. В Dagon 0.27 наконец-то появились тени от позиционных источников света (то есть, для всех, кроме Sun) — это реализовано техникой двойного параболоида, которая значительно эффективнее классического подхода с теневой кубической картой. Чтобы включить тень, ничего особенного делать не надо, просто light.shadowEnabled = true;.

Также добавил префильтрацию кубических карт — свертку с использованием GGX BRDF под различные значения шероховатости. Чтобы сконвертировать равнопромежуточную карту в кубическую, а затем отфильтровать, нужно сделать так:

uint resolution = 1024;
Texture cubemap = generateCubemap(resolution, aEnvmap.texture, null);
Texture prefilteredCubemap = prefilterCubemap(resolution, cubemap, assetManager);
Delete(cubemap);

Появилась поддержка анизотропной фильтрации текстур (если поддерживается расширение GL_EXT_texture_filter_anisotropic). Включается следующим образом:

texture.useAnisotropicFiltering = true;
texture.anisotropy = texture.maxAnisotropy;

Добавлена поддержка поля extras для большинства объектов в загрузчике glTF (кроме материалов и текстур).

Еще одна новая фича — поддержка локализации приложений (dagon.core.i18n). Локали — файлы *.lang — загружаются из папки locales. Например, чтобы добавить русскую локаль, нужно добавить файл locales/ru_RU.lang.

Синтаксис файлов точно такой же, как у конфигов. Например, можно сделать так:

hello_world: "Привет, мир!";

В приложении:

string text = application.translate("hello_world");

Приложение сначала пытается загрузить locales/en_US.lang, затем локализацию, выбранную в зависимости от текущего системного языка и региона, перезаписывая дефолтные английские значения. Либо пользователь может явно указать нужную ему локаль в settings.conf:

locale: "ru_RU";

Обновления

BindBC-Vulkan

Зарегистрировал новый DUB-пакет bindbc-vulkan — динамический биндинг к Vulkan. В настоящее время доступны API Vulkan 1.0 и расширения для создания поверхности под Windows и Linux (X11 или Wayland). Тестировал пока только под Windows. К биндингу прилагается минимальный пример рендеринга, создающий окно при помощи SDL (правда, он пока ничего не рисует 😅).

https://github.com/DLangGamedev/bindbc-vulkan

BindBC-WGPU 0.25

Обновил биндинг к wgpu-native до версии 0.25 (или 25 в официальной нумерации). Изменения в API минимальные, в основном в модуле bindbc.wgpu.c.wgpu. Поломок обратной совместимости быть не должно.

https://github.com/DLangGamedev/bindbc-wgpu

Страничка про OpenGL

Добавил в раздел «Технологии» страницу, посвященную OpenGL.

Тени от позиционных источников света

Фича, которую я запланировал на Trello очень давно и сумел реализовал только сейчас. Теперь в Dagon любой позиционный источник света (AreaSphere, AreaTube, Spot) может иметь тени — это реализовано техникой двойного параболоида (dual paraboloid shadow mapping), где геометрия проецируется на две текстуры глубины, с двух сторон относительно источника света.

Dagon 0.26.0

На днях вышла новая версия движка! Как я уже писал ранее, в этой версии все загрузчики ресурсов в Dagon используют единую виртуальную файловую систему — Application.vfs. В связи с этим класс VirtualFileSystem был значительно актуализирован и расширен. В частности, теперь движок из коробки поддерживает загрузку ресурсов из папки с данными (C:\Users\AppData\Roaming\<appDataFolder> под Windows, где <appDataFolder> — кастомное имя папки, которое указывается при создании приложения Dagon). Кроме того, главный конфиг приложения (ранее Game.config) переехал в класс Application. Появился новый метод Application.showConsoleWindow для переключения видимости окна консоли под Windows.

В EventManager наконец-то доведена до ума проверка однократного нажатия и отпускания клавиш/кнопок мыши/кнопок контроллера (EventManager.keyDown, EventManager.keyUp и т.д.). Эта функциональность добавляет небольшой оверхед, поэтому она по умолчанию отключена — нужно ее включать свойством EventManager.trackUpDownState. Как следствие, InputManager.getButtonUp и InputManager.getButtonDown теперь также работают корректно. Добавлено свойство EventManager.application, чтобы можно было получить доступ к объекту приложения из менеджера событий.

Добавлен новый аппаратно-ускоряемый генератор кубических карт — функция dagon.graphics.texproc.generateCubemap, эффективная замена методу Texture.createFromEquirectangularMap. Эта функция конвертирует равнопромежуточные карты окружения в кубические, что позволяет избежать некоторых неприятных артефактов первых. Благодаря переносу на GPU, теперь эта процедура выполняется очень быстро. Данный компонент будет развиваться и дальше — в следующих версиях будет поддержка префильтрации, о которой я писал в предыдущем посте.

Предрассчитанная таблица BRDF LUT теперь поставляется вместе с движком в папке data/__internal/textures/brdf.dds. Эта текстура загружается автоматически и доступна как DeferredRenderer.brdf. В случае использования отложенного рендера, рекомендуется активировать ее следующим образом:

environment.ambientBRDF = game.deferredRenderer.brdf;

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

GLTFPose и GLTFBlendedPose теперь обновляют матрицы трансформации объектов Entity, ассоциированных с костями glTF. Это позволяет, например, использовать Entity.positionAbsolute для получения позиции кости в мировом пространстве.

Добавлен новый модуль dagon.extra.verlet с реализацией position-based динамики для симуляции веревок и цепей.

Префильтрация кубических карт

В дополнение к простому конвертеру из равнопромежуточных карт окружения в кубические карты, в Dagon появилась поддержка предварительной фильтрации (prefiltering) — то есть, свертки кубических карт с использованием GGX BRDF под различные значения шероховатости. Результаты свертки сохраняются в mip-уровнях. Этот процесс является одной из ключевых оптимизаций PBR, поскольку избавляет от необходимости вычислять интеграл облученности в реальном времени. Префильтрация осуществляется очень быстро на GPU, поэтому ее, в принципе, можно делать каждый раз при запуске приложения (но лучше, конечно, однократно с кэшированием в файл — скоро добавлю и такую возможность). Преимуществом является то, что теперь для этого необязательно использовать сторонние утилиты типа IBLBaker — движок все делает сам.

Реализация основана на классическом методе (выборка по последовательности ван дер Корпута-Хаммерсли), описанном в статье «Real Shading in Unreal Engine 4» (Брайан Карис, Epic Games, SIGGRAPH 2013).

Переезд всех сайтов на домене timurgafarov.ru

Некоторые мои ресурсы используют домен timurgafarov.ru, и сегодня я изменил для него DNS-серверы в связи с переездом на новый хостинг. Это касается следующих сайтов:

https://gamedev.timurgafarov.ru теперь редиректит на https://blog.pixperfect.online.

Пропагация DNS в процессе — в ближайшее время сайты могут быть доступны не во всех странах и не для всех провайдеров.

Виртуальная файловая система

В Dagon уже достаточно давно существовала поддержка VFS, но до сих пор все загрузчики ресурсов использовали отдельные объекты VirtualFileSystem, поэтому не было простой возможности монтировать общие для всей логики движка пути. Все изменится в грядущем Dagon 0.26, где будет единая VFS на все случаи жизни — Application.vfs. Пользовательский API при этом останется без изменений.

VFS позволяет хранить ресурсы игры в различных папках (и даже в архивах), предоставляя унифицированный интерфейс для доступа к ним. По умолчанию в Dagon теперь монтируются рабочая папка игры и папка с данными (C:\Users\AppData\Roaming\<appDataFolder> под Windows, где <appDataFolder> — кастомное имя папки). Последний примонтированный источник является наиболее приоритетным — то есть, в данном случае файл будет сначала искаться в appDataFolder, а потом — в рабочей папке. Преимуществом такого подхода является упрощение моддинга, возможность замены любого ресурса без риска сломать оригинальную игру, вплоть до создания тотальных конверсий.

Шоурил 2025

Выпустил на YouTube-канале небольшое обзорное видео самых интересных новых возможностей Dagon:

Dagon 0.25.0

Вышла очередная версия движка! Наиболее интересным нововведением является расширение dagon:video, о котором я писал ранее — теперь в играх можно воспроизводить видео при помощи библиотеки libVLC. Видеопоток декодируется в текстуру, которую можно применить к любому материалу. Для полноэкранного отображения видео предусмотрен виджет FullscreenMediaView.

Наконец-то добавил в упрощенный рендер поддержку точечных и конусных источников света. Поддерживается до 8 источников света на слой, их нужно добавлять методом SimpleRenderPass.addLight. Также в упрощенном рендере появилась поддержка cel-шейдинга — управляется свойствами Material.celShading и Material.rimLight. В deferred-рендере эти свойства ни на что не влияют.

Появилась поддежка uniform-блоков в шейдерах. Вы можете создать массив uniform-структур при помощи объекта UniformBlockParameter. Поля структуры должны соответствовать требованиям std140.

Реализован MaterialAsset — ресурс описания материала, основанный на том же синтаксисе, что и конфигурационные файлы. Кстати, в файлах *.conf теперь поддерживаются матрицы 4×4 и 3×3 (фактически они являются массивами из 16 или 9 числовых значений, которые можно интерпретировать в приложении как матрицы с построчным расположением элементов).

Из мелочей: поддержка Entity.opacity в HUD-проходе, поддержка анимации для свойства Entity.opacity, поддержка Material.emissionEnergy в шейдере Sky, свойство TextureAsset.loaded.

libVLC и видеотекстуры

Я давно искал удобное решение для воспроизведения видео в играх, и вот, наконец, оно найдено — libVLC, библиотека, на которой основан всеми любимый плеер VLC. В отличие от FFMPEG, это высокоуровневый API, который позволяет буквально в несколько строк добавить видеоплеер в любое окно по HWND (или X window ID под Linux). Но самое интересное, конечно, декодировать видео во внеэкранный буфер, чтобы потом передать его в OpenGL-текстуру — libVLC это также позволяет с минимальными телодвижениями. Я уже добавил в репозиторий Dagon экспериментальное расширение dagon:video, которое предоставляет класс Video, обертку над libvlc_media_t* и libvlc_media_player_t*. Использовать его очень просто — сначала создается VideoManager, общий для всего приложения (лучше хранить его в классе, наследующем от Game):

VideoManager videoManager = New!VideoManager(this);

Затем, уже в сцене, создается источник видео:

Video video = New!Video(videoManager, 1920, 1080, assetManager);
video.open("media/video.mp4");

auto videoMaterial = addMaterial();
videoMaterial.baseColorTexture = video.texture;
videoMaterial.alphaTestThreshold = 0.0f;

video.play();

Можно использовать видеотекстуру для любых целей — показать заставку в начале игры, натянув на screen-aligned плоскость, или применить к мешу для создания внутриигрового экрана. Можно даже воспроизводить 360-градусные ролики в равнопромежуточной проекции для отображения на панорамном фоне.