Как я могу процедурно визуализировать столбики здоровья неправильной формы?


35

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

Пустое здоровье Полное здоровье, частичное здоровье

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

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

Я предполагаю, что этот вопрос не зависит от языка и платформы, но не стесняйтесь предоставить конкретный пример на любом языке / библиотеке / фреймворке, если он поможет в ответе.


5
«N̶a̶n̶o̶m̶a̶c̶h̶i̶n̶e̶s̶ Шейдеры, сын»
— Мукеш Ингам

Я чувствую, что этот переход может быть определен математически, оттуда вы можете заставить компьютер вычислять координаты пикселей, чтобы показать / скрыть, а не предварительно запекать их
— Ричард Тингл

Как бар здоровья в форме сердца "легко решается"?
— MooseBoys

1
@MooseBoys Я говорил о здоровье на основе сердца, а не в форме сердца. Вспомните игры Legend of Zelda. Извините за то, что не был более ясным.
— msd7734

@RichardTingle, хорошая идея :)
— Jon

Ответы:


48

Есть очень простой способ добиться этого с помощью шейдеров, вам нужно три * текстуры: пустая полоса здоровья, текстура полоски здоровья и маска с градиентом распределения здоровья с одним экстремумом (например, самое темное, а не черное или самое прозрачное альфа-значение) на одном конце и другой на другом конце. Лучше всего это показать на изображении, в настоящее время я не могу нарисовать изогнутый градиент только линейным, но я уверен, что у ваших художников не возникнет никаких проблем: введите описание изображения здесь теперь в шейдере сэмплируйте и текстуры, и пороговое значение маски, отбрасывая все пиксели, которые не являются ярче, чем пороговое значение ввода (на основе данных о состоянии шейдера% здоровья).
Вы могли быиспользуйте математическую формулу для маскировки вместо текстуры, но если бы вы это сделали, вы все равно были бы очень ограничены фигурами, которые вы можете (= простые) создавать с помощью указанных формул - и найти одну из них нетривиально.
* см комментарии


9
Во многих случаях (включая пример ОП) использование отдельной текстуры для цвета является излишним. В большинстве случаев вы можете просто переназначить градиент маски градаций серого в цвета, указанные как унифицированные для шейдера, при этом отбрасывая любые значения маски ниже определенного порога.
— bcrist

1
На самом деле вам не нужно самое темное, а не черное, вы можете использовать альфа-канал, чтобы отсеивать ненужные пиксели.
— Джек Эйдли,

1
@JackAidley уверен, что это было бы возможно, но я хотел, чтобы решение было настолько гибким, насколько это возможно - в большинстве названий ААА hp просто «красный», но он текстурированный.
— Wondra

1
@bcrist Хорошая мысль, я подумал о том, чтобы предложить это как оптимизацию. Но я не мог нарисовать его должным образом, поэтому решил сделать его как можно более простым и оставить оптимизацию для реализации.
— Wondra

@wondra Для многих случаев, в том числе для примера, приведенного в OP, можно использовать процедурный градиент или одномерный поиск цветов (с входным уровнем маски), а не текстуру.
— Random832

34

Реализовано математически, как пиксельный шейдер:

На CPU рассчитайте HealthDirection и его точечный продукт с V2 введите описание изображения здесь

На GPU рассчитайте нормализованное направление от центральной точки для каждого пикселя. Сравните каждый точечный продукт с HealthDirections ', чтобы выбрать, следует ли оттенять «фон» или по цвету. введите описание изображения здесь

Если вы «перевернули» этот алгоритм и работали в другом направлении, вы могли бы «снять» направление каждого пикселя обратно в процент и вместо этого сравнить их с HealthPercent. С вычислением процентного соотношения каждого пикселя, изменение затухания с красного на зеленый на GPU становится тривиальным.

Сначала нарисуйте планку, применяя алгоритм к четверке; выводить цвета между rangeMin и rangeMax (может быть запечен) и clip () или выводить прозрачный каждый раз где-либо еще. Затем нарисуйте (модифицированный) спрайт поверх него, используя альфа. Я проследил ваш бар в САПР, залил его, а затем «по волшебству побрел» сплошной цвет в Paint, чтобы удалить его. Мой выглядит как дерьмо из-за смешивания AutoCAD и Paint вручную; при условии, что вы смешаете внутренние края с прозрачными, ваши будут выглядеть идеально .

Белая граница - это границы четырехугольника. Это и красные X только для справки:

введите описание изображения здесь

«Спрайт с дырой» не нужно отображать одновременно с индикатором здоровья. Они должны быть инстанцированы и нарисованы сразу после того, как все бары здоровья будут готовы. Поскольку алгоритм содержится в шейдере, вы также можете добавить к нему экземпляры, а затем также нарисовать все панели состояния одним вызовом экземпляра. Рисование каждой панели здоровья на экране должно занять 2 вызова DrawInstanced (...) и быть "сумасшедшим быстрым".


1
Если вы собираетесь маскировать таким круговым способом, вы можете реализовать его более эффективно, просто изменив треугольники, которые вы строите для кругового затухания.
— Джек Эйдли,

@JackAidley, пожалуйста, будьте более конкретны, потому что я не рассматриваю эту маскировку; Индикатор выполнения полностью отображается на месте только на двух треугольниках без выборки после первого прохода. У спрайта просто есть дыра, и в конце он «красуется». (Это своего рода маска, но не как неотъемлемая часть алгоритма?) Спасибо
— Джон

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

@JackAidley, а фонового спрайта нет? Радуга рисуется только с использованием четырех мировых позиций float3; нет ультрафиолетовых лучей, нет "фонового спрайта". Кроме того, вы обеспокоены тем, что пиксельный шейдер увязнет в работе над некоторыми крошечными квадраторами? Кроме того, RangeMin и RangeMax clip () большинство этих фрагментов, мгновенно.
— Джон

Вам потребуется фоновый спрайт, чтобы получить границы, как показано на исходном изображении; если вы их опускаете, то да, методы разные.
— Джек Эйдли,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.