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

35

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

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

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

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

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

msd7734
источник
5
«N̶a̶n̶o̶m̶a̶c̶h̶i̶n̶e̶s̶ Шейдеры, сын»
Мукеш Ингам
Я чувствую, что этот переход может быть определен математически, оттуда вы можете заставить компьютер вычислять координаты пикселей, чтобы показать / скрыть, а не предварительно запекать их
Ричард Тингл
Как бар здоровья в форме сердца "легко решается"?
MooseBoys
1
@MooseBoys Я говорил о здоровье на основе сердца, а не в форме сердца. Вспомните игры Legend of Zelda. Извините за то, что не был более ясным.
msd7734
@RichardTingle, хорошая идея :)
Jon

Ответы:

48

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

wondra
источник
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 () большинство этих фрагментов, мгновенно.
Джон
Вам потребуется фоновый спрайт, чтобы получить границы, как показано на исходном изображении; если вы их опускаете, то да, методы разные.
Джек Эйдли,