- Патч Alternative HP Bars / Альтернативные полоски здоровья 7.72
- Мод: Индикатор урона 1.16
- Unity: отрисовываем множество полосок здоровья за один drawcall
- Почему бы не использовать Canvas?
- Вкратце о моём решении
- Что такое Instancing?
- Класс Damageable
- Объект HealthBar: позиция/поворот
- Шейдер HealthBar
- Материал Healthbar
- Обновление свойства HealthBar Fill
- Панель Stats
- Отладчик кадров
Патч Alternative HP Bars / Альтернативные полоски здоровья 7.72
Патч заменяет оригинальные полоски здоровья, маны, выносливости, отравления, дыхания под водой, полоски здоровья обычных/редких/легендарных/эпических противников, а также полосу загрузки/сохранения.
Изменения были внесены в файлы, которые находятся в RET2_Textures_01.vdf и RET2_Textures_02.vdf. В которых, в свою очередь, находятся текстуры Возвращения 2.0, 66 версии, 2 Ревизии, и уж никак не АБ. При условии, что в последующих версиях Возвращения 2.0 за нижеописанные текстуры интерфейса отвечают те же файлы, данный патч имеет все шансы также встать и на Возвращение 2.0.
Тестировался исключительно на моём древнем AMD ноуте с Windows 7 x64, без DX11, на актуальных на данный момент скриптах(AB_Scripts_2019_10_06). Замена файлов текстур не должна вызвать проблем на другом железе, ОС, а также при включенном DX11. На всякий случай, установившим, просьба отписаться здесь в обсуждениях.
Для установки всего текстурного пакета, G1_BARS_7.11.vdf или G2_BARS_7.12.vdf распаковать в папку Data.
Для установки отдельных текстур из пака, закинуть соответствующий vdf из архива BARS_separated.rar в папку Data.
G1_BARS_7.11.vdf — версия с полосками из первой Готики;
G2_BARS_7.12.vdf — версия с полосками из Готики 2, а также Готики 2: Ночь Ворона;
Источник
Мод: Индикатор урона 1.16
Вы хотите, чтобы ваш опыт игры в Minecraft PE (Bedrock Edition) был больше похож на RPG (ролевую) игру? Итак, чего же не хватает? Индикатора повреждений! Да! Многие хотели бы видеть урон, который мы наносим врагам. Этот аддон сделает всю работу за вас.
Функции:
- Показывает урон, нанесенный противнику;
- Точный контроль над здоровьем;
- Максимальное расстояние рендеринга 20 блоков;
- Шрифт Mojang;
- Доступны 2 варианта отображения — полоска и сердца.
Обновление v2.3
В этом обновлении убран пакет параметров, чтобы вы могли получать и сохранять ваши достижения.
Стало доступно 3 варианта аддона:
- Индикатор здоровья + повреждений;
- Только индикатор здоровья;
- Только индикатор повреждений.
Индикатор здоровья боссов:
- Исправлены давние ошибки;
- Новая полоска здоровья + индикатор здоровья босса;
- Увеличено максимальное расстояние отображения до 20 блоков;
- Добавлено 3 варианта аддона (Только индикатор здоровья, только индикатор повреждений, индикатор здоровья + повреждений);
- Убран набор параметров (чтобы вы получали достижения).
Скачать мод Damage Indicator (Индикатор здоровья + повреждений) v2.3 (.mcpack)
Скачать мод Damage Indicator (Только индикатор здоровья) v2.3 (.mcpack)
Скачать мод Damage Indicator (Только индикатор повреждений) v2.3 (.mcpack)
Скачать шрифт для Damage Indicator (.mcpack)
Источник
Unity: отрисовываем множество полосок здоровья за один drawcall
Недавно мне нужно было решить задачу, достаточно распространённую во многих играх с видом сверху: рендерить на экране целую кучу полосок здоровья врагов. Примерно вот так:
Очевидно, что я хотел сделать это как можно эффективнее, желательно за один вызов отрисовки. Как обычно, прежде чем приступать к работе, я провёл небольшое онлайн-исследование решений других людей, и результаты были очень разными.
Я не буду никого стыдить за код, но достаточно сказать, что некоторые из решений были не совсем блестящими, например, кто-то добавлял к каждому врагу объект Canvas (что очень неэффективно).
Метод, к которому я в результате пришёл, немного отличается от всего того, что я видел у других, и не использует вообще никаких классов UI (в том числе и Canvas), поэтому я решил задокументировать его для общества. А для тех, кто хочет изучить исходный код, я выложил его на Github.
Почему бы не использовать Canvas?
По одному Canvas для каждого врага — это очевидно плохое решение, но я мог использовать общий Canvas для всех врагов; единственный Canvas тоже бы привёл батчингу вызовов отрисовки.
Однако мне не нравится связанный с таким подходом объём выполняемой в каждом кадре работы. Если вы используете Canvas, то в каждом кадре придётся выполнять следующие операции:
- Определять, какие из врагов находятся на экране, и выделять каждому из них из пула полоску UI.
- Проецировать позицию врага в камеру, чтобы расположить полоску.
- Изменять размер «заливки» части полоски, вероятно, как Image.
- Скорее всего изменять размер полосок в соответствии с типом врагов; например, у крупных врагов должны быть большие полоски, чтобы это не выглядело глупо.
Как бы то ни было, всё это загрязняло бы буферы геометрии Canvas и приводило к перестройке всех данных вершин в процессоре. Я не хотел, чтобы всё это выполнялось для столь простого элемента.
Вкратце о моём решении
Краткое описание процесса моей работы:
- Прикрепляем объекты полосок энергии к врагам в 3D.
- Это позволяет автоматически располагать и усекать полоски.
- Позицию/размер полоски можно настраивать в соответствии с типом врага.
- Полоски мы направим на камеру в коде с помощью transform, который всё равно есть.
- Шейдер гарантирует, что они всегда будут рендериться поверх всего.
- Используем Instancing для рендеринга всех полосок за один вызов отрисовки.
- Используем простые процедурные UV-координаты для отображения уровня заполненности полоски.
А теперь давайте рассмотрим решение подробнее.
Что такое Instancing?
В работе с графикой уже давно используется стандартная техника: несколько объектов объединяются вместе, чтобы они имели общие данные вершин и материалы и их можно было отрендерить за один вызов отрисовки. Нам нужно именно это, потому что каждый вызов отрисовки — это дополнительная нагрузка на ЦП и GPU. Вместо выполнения по одному вызову отрисовки на каждый объект мы рендерим их все одновременно и используем шейдер для добавления вариативности в каждую копию.
Можно делать это вручную, дублируя данные вершин меша X раз в одном буфере, где X — максимальное количество копий, которое может быть отрендерено, а затем использовав массив параметров шейдера для преобразования/окраски/варьирования каждой копии. Каждая копия должна хранить знание о том, каким нумерованным экземпляром она является, чтобы использовать это значение как индекс массива. Затем мы можем использовать индексированный вызов рендера, который приказывает «рендерить только до N», где N — это число экземпляров, которое на самом деле нужно в текущем кадре, меньшее, чем максимальное количество X.
В большинстве современных API код для этого уже есть, поэтому вручную это делать не требуется. Эта операция называется «Instancing»; по сути, она автоматизирует описанный выше процесс с заранее заданными ограничениями.
Движок Unity тоже поддерживает instancing, в нём есть собственный API и набор макросов шейдеров, помогающие в его реализации. Он использует определённые допущения, например, о том, что в каждом экземпляре требуется полное 3D-преобразование. Строго говоря, для 2D-полосок оно нужно не полностью — мы можем обойтись упрощениями, но поскольку они есть, мы будем использовать их. Это упростит наш шейдер, а также обеспечит возможность использования 3D-индикаторов, например, кругов или дуг.
Класс Damageable
У наших врагов будет компонент под названием Damageable , дающий им здоровье и позволяющий им получать урон от коллизий. В нашем примере он довольно прост:
Объект HealthBar: позиция/поворот
Объект полосы здоровья очень прост: по сути, это всего лишь прикреплённый к врагу Quad.
Мы используем scale этого объекта, чтобы сделать полоску длинной и тонкой, и разместим её прямо над врагом. Не беспокойтесь о её повороте, мы исправим его с помощью кода, прикреплённого к объекту в HealthBar.cs :
Этот код всегда направляет quad в сторону камеры. Мы можем выполнять изменение размера и поворота в шейдере, но я реализую их здесь по двум причинам.
Во-первых, instancing в Unity всегда использует полный transform каждого объекта, и поскольку мы всё равно передаём все данные, можно их и использовать. Во-вторых, задание масштаба/поворота здесь гарантирует, что ограничивающий параллелограмм для усечения полоски всегда будет верным. Если бы мы сделали задание размера и поворота обязанностью шейдера, то Unity мог бы усекать полоски, которые должны быть видимы, когда они находятся близко к краям экрана, потому что размер и поворот их ограничивающего параллелограмма не будут соответствовать тому, что мы собираемся рендерить. Разумеетсяя, мы могли бы реализовать свой собственный способ усечения, но обычно при возможности лучше использовать то, что у нас есть (код Unity является нативным и имеет доступ к большему количеству пространственных данных, чем мы).
Я объясню, как рендерится полоска, после того, как мы рассмотрим шейдер.
Шейдер HealthBar
В этой версии мы создадим простую классическую красно-зелёную полоску.
Я используют текстуру размером 2×1, с одним зелёным пикселем слева и одним красным справа. Естественно, я отключил mipmapping, фильтрацию и сжатие, а для параметра addressing mode задал значение Clamp — это значит, что пиксели нашей полоски всегда будут идеально зелёными или красными, а не растекутся по краям. Это позволит нам изменять в шейдере координаты текстуры для сдвига линии, разделяющей красный и зелёный пиксели вниз и вверх по полоске.
(Так как здесь всего два цвета, я мог просто использовать в шейдере функцию step для возврата в точке одного или другого. Однако в этом методе удобно то, что при желании можно использовать более сложную текстуру, и это будет работать аналогично, пока переход находится в середине текстуры.)
Для начала мы объявим необходимые нам свойства:
_MainTex — это красно-зелёная текстура, а _Fill — значение от 0 до 1, где 1 — это полное здоровье.
Далее нам нужно приказать полоске рендериться в очереди overlay, а значит, игнорировать всю глубину в сцене и рендериться поверх всего:
Следующая часть — это сам код шейдера. Мы пишем шейдер без освещения (unlit), поэтому нам не нужно беспокоиться об интеграции с различными моделями поверхностных шейдеров Unity, это простая пара вершинного/фрагментного шейдеров. Для начала напишем бутстреппинг:
По большей мере это стандартный bootstrap, за исключением #pragma multi_compile_instancing , которая сообщает компилятору Unity, что нужно компилировать для Instancing.
Вершинная структура должна включать в себя данные экземпляров, поэтому мы сделаем следующее:
Также нам нужно задать, что именно будет находиться в данных экземляров, кроме того, что за нас обрабатывает Unity (transform):
Так мы сообщаем, что Unity должен создать буфер под названием «Props» для хранения данных каждого экземпляра, и внутри него мы будем использовать по одному float на экземпляр для свойства под названием _Fill .
Можно использовать и несколько буферов; это стоит делать, если у вас есть несколько свойств, обновляемых с разной частотой; разделив их, можно, например, не менять один буфер при изменении другого, что более эффективно. Но нам этого не требуется.
Наш вершинный шейдер почти полностью выполняет стандартную работу, потому что размер, позиция и поворот и так передаются в transform. Это реализуется с помощью UnityObjectToClipPos , который автоматически использует transform каждого экземпляра. Можно представить, что без instancing это обычно было бы простым использованием одного матричного свойства. но при использовании instancing внутри движка это выглядит как массив матриц, и Unity самостоятельно выбирает матрицу, подходящую к данному экземпляру.
Также нем нужно изменять UV, чтобы менять расположение точки перехода из красного в зелёный в соответствии со свойством _Fill . Вот соответствующий фрагмент кода:
UNITY_SETUP_INSTANCE_ID и UNITY_ACCESS_INSTANCED_PROP выполняют всю магию, осуществляя доступ к нужной версии свойства _Fill из буфера констант для этого экземпляра.
Мы знаем, что в обычном состоянии UV-координаты четырёхугольника (quad) покрывают весь интервал текстуры, и что разделительная линия полоски находится посередине текстуры по горизонтали. Поэтому небольшие математические расчёты по горизонтали сдвигают полоску влево или вправо, а значение Clamp текстуры обеспечивают заполнение оставшейся части.
Фрагментный шейдер не мог быть проще, потому что вся работа уже выполнена:
Полный код шейдера с комментариями доступен в репозитории GitHub.
Материал Healthbar
Дальше всё просто — нам всего лишь нужно назначить нашей полоске материал, который использует этот шейдер. Больше почти ничего делать не нужно, достаточно только выбрать нужный шейдер в верхней части, назначить красно-зелёную текстуру, и, что самое важное, поставить флажок «Enable GPU Instancing».
Обновление свойства HealthBar Fill
Итак, у нас есть объект полоски здоровья, шейдер и материал, который нужно рендерить, теперь нужно задать для каждого экземпляра свойство _Fill . Мы делаем это внутри HealthBar.cs следующим образом:
Мы превращаем CurrentHealth класса Damageable в значение от 0 до 1, разделив его на MaxHealth . Затем мы передаём его свойству _Fill с помощью MaterialPropertyBlock .
Если вы ещё не использовали MaterialPropertyBlock для передачи данных в шейдеры, даже без instancing, то вам нужно изучить его. Он не так хорошо объяснён в документации Unity, но является самым эффективным способом передачи данных каждого объекта в шейдеры.
В нашем случае, когда используется instancing, значения для всех полосок здоровья упаковываются в буфер констант, чтобы их можно было передать их все вместе и отрисовать за один раз.
Здесь нет почти ничего, кроме бойлерплейта для задания переменных, и код довольно скучный; подробности см. в репозитории GitHub.
В репозитории GitHub есть тестовое демо, в котором куча злых синих кубиков уничтожается героическими красными сферами (ура!), получая урон, отображаемый описанными в статье полосками. Демо написано в Unity 2018.3.6f1.
Эффект от использования instancing можно наблюдать двумя способами:
Панель Stats
Нажав Play, щёлкните на кнопку Stats над панелью Game. Здесь вы можете увидеть, сколько вызовов отрисовки экономится благодаря instancing (батчингу):
Запустив игру, вы можете нажать на материал HealthBar и снять флажок с «Enable GPU Instancing», после чего число сэкономленных вызовов снизится до нуля.
Отладчик кадров
Запустив игру, перейдите в меню Window > Analysis > Frame Debugger, а затем нажмите в появившемся окне «Enable».
Слева внизу вы увидите все выполняемые операции рендеринга. Заметьте, что пока там есть множество отдельных вызовов для врагов и снарядов (при желании можно реализовать instancing и для них). Если прокрутить до самого низа, то вы увидите пункт «Draw Mesh (instanced) Healthbar».
Этот единственный вызов рендерит все полоски. Если нажать на эту операцию, а затем на операцию над ней, то вы увидите, что все полоски исчезнут, потому что они отрисовываются за один вызов. Если находясь во Frame Debugger, вы снимете у материала флажок «Enable GPU Instancing», то увидите, что одна строка превратилась в несколько, а после установки флажка — снова в одну.
Источник