пятница, 19 января 2024 г.

UMaterial, UMaterialInstanceDynamic, UMaterialInstanceConstant и UpdateStaticPermutation в UE5.2+

    Недавно столкнулся со странностями в архитектуре UE 5.2+. В данном случае – с устройством материалов в движке. Материал, как уже известно, в анриле может быт много чем, но меня интересовала первичное его назначение – когда он работает как эдакий шейдер+ с биндингами переменных. Основной проблемой было то, что материалы странно вели себя при рендеринге из коммандлета, который запускался из консоли – в одну из веток поступали какие-то некорректные данные и, увы, это пока не удалось отладить. Частично из-за того, что нет простой прямой связи между объектами рендеринга и материалами. А ещё RenderDoc упорно не хотел показывать никаких вызовов графического API, хотя рендеринг явно происходил. В итоге принял решение сбросить определённый флажок, который имел вид Static Parameter Switch в наследуемом инстансе материала  и должен был решить проблему за счёт убирания глючащей ветки.

    И вот здесь позволю себе отступления, что вообще во время исполнения EG рекомендуют использовать UMaterialInstanceDynamic, который по идее позволяет избежать лишней компиляции материалов и вообще весь шустрый. В принципе, почему бы и нет? Все нужные методы у него есть, хорошо же? Я говорю, само собой, об условном UpdateStaticPermutation, аж в трёх вариантах, который по идее должен давать возможность переопределять статические параметры.

    А вот нет, ни разу. Перегрузка может не триггерить  повторную компиляцию материала. Беглый поиск по редактору и движку, показал, что там чаще используется вот эта перегрузка. Но самое смешное – это если дёрнуть метод на UMaterialInstanceDynamic, то оно счастливо упадёт с ассертом о том, что лишь UMaterialInstanceConstant можно менять такие флаги. В документации ограничения нет, отсюда и пост.

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

    Справедливости ради создать UMaterialInstanceConstant в рантайме, вполне можно есть вот такой пример. Однако здесь его кидают в ассет, а это не обязательно всё же делать. Зато, кроме переопределения статических параметров, было нужно ещё и копирование настроек из определённого «предыдущего» материала.

    В итоге получилось что-то такое. Это  далеко не оптимальный код, есть ощущение, что если покопаться ещё, то можно ещё отрезать ненужные действия.


UMaterialInstanceConstantFactoryNew* MaterialFactory = 
	NewObject<UMaterialInstanceConstantFactoryNew>();
// Это совсем базовый материал, а вот Material – это инстанс, который хочется копировать. 
// Замечу, что BaseMaterial должен по идее быть UMaterial
UMaterialInterface* BaseMaterial = Material->GetBaseMaterial();
MaterialFactory->InitialParent = BaseMaterial;
const FName MatName = FName(TEXT("REPLACE_WITH_OWN_MAT_NAME"));
// В данном случае нам не интересен пакет, т.к. мы не планируем из этого делать ассет
UMaterialInstanceConstant* Instance = CastChecked<UMaterialInstanceConstant>(
	MaterialFactory->FactoryCreateNew(
    	UMaterialInstanceConstant::StaticClass(), 
        this, 
        MatName, 
        RF_Standalone | RF_Public, 
        nullptr, 
        GWarn
   )
);

// Это обычно делают перед обновлением свойств в редакторе, не стал менять
Instance->PreEditChange(nullptr); 

// Копирование исходных параметров. Замечу, что если родителем Material является 
// другой инстанс, то его тоже стоит скопировать 
Instance->CopyMaterialUniformParametersEditorOnly(Material, true);

// Далее меняем Static Parameter Switch
FStaticParameterSet Set;
// Важно использовать именно эту перегрузку, другая не возвращает базовые свитчи
Instance->GetStaticParameterValues(Set); 
for (auto& Switch : Set.StaticSwitchParameters)
{
     if (Switch.ParameterInfo.Name.ToString() == TEXT("SWITCH_NAME"))
	{
		Switch.Value = <новое значение>;
		Switch.bOverride = true;
	}
}
Instance->UpdateStaticPermutation(Set, Instance->BasePropertyOverrides, true);

// Тут документация недоговаривает, эта принудительная компиляция прекрасно работает 
// и вне FMaterialUpdateContext. 
// Возможно, в будущем всё изменится, но пока это так.
Instance->InitStaticPermutation();  

    Дополнительно можно подёргать всякие сбросы кешей, чтобы сработало, но, по идее, это не обязательно:


Instance->RecacheUniformExpressions(true);
// UPD: 02.03.2024 Вот это вообще на 5.3.2+ начало крашить при рендеринге - причины непонятны, увы
// Впрочем код выше работает и без этого.
Instance->RecacheAllMaterialUniformExpressions(true);
FPropertyChangedEvent Evt(nullptr, EPropertyChangeType::ValueSet);
Instance->PostEditChangeProperty(Evt);
Instance->PostEditChange();

    Как-то так. Это опять же, способ, который я отыскал сам ковырянием в движке и редакторе, но если у кого-то есть более простой и красивый вариант – я буду рад узнать о нём.

четверг, 18 января 2024 г.

Про «Деконструкцию виртуальных миров» Кадикова

Недавно я натолкнулся на пост об уязвимостях в дизайне уровней.  Он довольно хороший и интересный, но я позволю себе не согласиться с одним тезисом (об этом ниже). Но вдобавок у меня оказалась книга этого же автора, так что – чтобы два раза не ходить, напишу короткое мнение  и о записи в блоге, и о книге.

пятница, 29 декабря 2023 г.

Итоги? Какие итоги? 2023

Я думал всё же делать итоги 2023, но в итоге пришёл к выводу, того, что их явно рано делать. Слишком много всего выглядит как в процессе, слишком невнятно выходит. Так, что в этом году без итогов. Думаю, авось в следующем удастся вырулить на что-то более логичное..

воскресенье, 17 декабря 2023 г.

Про Hollow Coccoon

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

пятница, 15 декабря 2023 г.

Впечатления от PROTOTYPE 1/23

Съездил на прошлой неделе на PROTOTYPE vol 1/23 и получил смешанные впечатления. 

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

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

В-третьих, зашло ощущение принадлежности к комьюнити - здесь в Волгограде, всё же никакого геймдев-комьюнити за пределами условного Кефира (если он тут ещё есть) нет. Ну и атмосфера такого подвального рейва доставила, жаль не остался на афтерпати. Была ещё классная демонстрация демок инди-игр на больших экранах - это было хорошо, жаль самих игр было маловато.

Увы, при всех достоинствах, без недостатков не обошлось.

Несмотря на то что, часть докладов намекала на презентации, их не было. Даже те доклады, где не было пометки Pro-Talk, по сути, были круглыми столами, которые, мне, как программисту, было слушать скучно. Почему? Потому что там не было ничего конкретного - ни цифр, ни каких-то интересных решений. В докладе о работе с ядрами, про условные ядра вообще ни в каком смысле не прозвучало. Единственное - в докладе про инвестиции, мимоходом, прозвучали некоторые цифры условной средней мобильной игры (ретеншен второго дня ~2%, 30 дней - ~7%). Это вызвало мой интерес, но дальше разговор выступающих свернул на другие темы. А жаль, по ощущениям от этого разговора, было видно, что мобилки вроде как и закапывают.

Это можно объяснить тем, что огромное количество людей на митапе вообще не были из программистов, а часть вообще были блогерами. При такой разношёрстной аудитории - трудно было чего-то хорошего и качественного ожидать, т.к., судя по всему, пытались угодить уж совсем начинающим.

При этом понравилась идея развивать сообщество инди-разработчиков на базе indiemaker, мне, честно говоря, интересно, что из этого выйдет. Судя по всему, в это планируются вложиться серьёзно, при таком условии можно ожидать результатов. С другой стороны — рынки не стоят на месте, а время сейчас весьма сложное.

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

Были ещё проблемы со звуком - из-за этого я два доклада потом смотрел в записи.

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

P.S. Но вот, в Волгограде, митапы с точки зрения докладов (я говорю об iT34) делаются получше. Тут тебе и презентации полноценные, и темы куда конкретнее. Жаль, только геймдева нет, увы. Да и хочется митапов, сильно заточенных на программистов, но увы.

P.P.S. Да, я понимаю, что в моём возрасте пора и самому докладываться. Жаль, темы я не придумал, а обычно набор моих задач - лезть во всякие странные места и ковыряться в странном. Увы, с тех пор как я покинул стены родного вуза, какой-то спецтемы, кроме hrtp-demake нет, но там скорее просто набор проблем, чем что-то конкретное.

пятница, 17 ноября 2023 г.

Unreal Font Cache Flush

 Чтобы кэш шрифтов при оффлайновом построении не сбрасывался из-за большого числа надписей с разными шрифтами, лучше поднимать количество возможных атласов через Slate.MaxFontAtlasPagesBeforeFlush и Slate.MaxFontNonAtlasTexturesBeforeFlush . Их нет в официальной доке, но как минимум в 5.2+ они есть.

суббота, 28 октября 2023 г.

Апдейт по разработке hrtp-demake

Маленький технический апдейт.

Второй босс-файт готов, остались исключительно технические вещи:

  • Сделать адекватный экран загрузки, чтобы загрузка не выглядела стрёмно
  • Оптимизация загрузки/выгрузки ресурсов (сейчас всё жирно грузится при старте, реально это 13 с, но память жрёт будь здоров, олдовые машины будут не рады).
  • Отдельно подтюнить загрузку экрана победы
Есть ещё мелкие задачи (подготовка следующего акта, утащить такие девлоги на отдельный хостинг), но они некритичны.

Пока займусь первым.