Wie kann ich unregelmäßig geformte Gesundheitsriegel prozedural rendern?

35

Das Problem des traditionellen rechteckigen oder herzbasierten Gesundheitsriegels ist gut verstanden und leicht zu lösen. Aber was ist die akzeptierte Lösung für mehr "kreativ geformte" Gesundheitsriegel, wie das Modell, das ich unten gemacht habe?

Leere Gesundheit Volle Gesundheit, teilweise Gesundheit

Der naheliegende Weg, dies zu tun, wäre, "Zwischen" -Sprites zu haben, so dass das dritte Bild sein eigenes Sprite sein würde, zusammen mit vielen anderen Übergängen für verschiedene Gesundheitsstufen. Aber das scheint wirklich unelegant zu sein, und die Anzahl der Zwischenschritte, die erforderlich sind, um einen reibungslosen Übergang zwischen Gesundheitszuständen zu erreichen, wäre groß.

Die einzige andere Idee, die ich mir einfallen lassen kann, ist, das Sprite "voller Zustand" über das Sprite "leerer Zustand" zu legen und Pixelkoordinatensätze vorab zu backen, um jeden Tick des Zustands darzustellen und sie dann als Zustand undurchsichtig oder transparent zu machen geht rauf oder runter.

Ich beabsichtige, dass diese Frage sprach- und plattformunabhängig ist, kann aber gerne ein konkretes Beispiel in einer beliebigen Sprache / Bibliothek / einem Framework bereitstellen, wenn dies für die Antwort hilfreich ist.

msd7734
quelle
5
"N̶a̶n̶o̶m̶a̶c̶h̶i̶n̶e̶s̶ Shaders, Sohn"
Mukesh Ingham
Ich habe das Gefühl, dass der Übergang mathematisch definiert werden kann. Von dort aus kann der Computer die Pixelkoordinaten berechnen, um sie anzuzeigen / auszublenden, anstatt sie vorzubacken
Richard Tingle
Wie ist der herzförmige Gesundheitsriegel "leicht zu lösen"?
MooseBoys
1
@MooseBoys Ich sprach über herzbasierte Gesundheit, nicht herzförmig. Denken Sie an die Legende von Zelda-Spielen. Es tut mir leid, dass ich nicht klarer bin.
msd7734
@ RichardTingle, gute Idee :)
Jon

Antworten:

48

Es gibt eine sehr einfache Möglichkeit, dies mit Shadern zu erreichen. Sie benötigen drei * Texturen: Leere Gesundheitsleiste, Textur der Gesundheitsleiste und Maske mit Gradient der Gesundheitsverteilung mit einem Extrem (z. B. dunkelster nicht schwarzer oder transparentester Alphawert) an einem Ende und dem andere am anderen Ende. Es wird am besten auf dem Bild gezeigt, ich kann derzeit keinen gekrümmten Farbverlauf nur linear zeichnen - aber ich bin sicher, dass Ihre Künstler keine Probleme haben werden: Bildbeschreibung hier eingeben Jetzt werden im Shader-Beispiel sowohl Texturen als auch Schwellenwerte für den Maskenwert verwendet, wobei alle nicht vorhandenen Pixel verworfen werden Heller als der Eingabeschwellenwert (basierend auf der Eingabe von Health% Shader).
Sie könntenVerwenden Sie anstelle einer Textur eine mathematische Formel zum Maskieren, aber wenn Sie dies tun, sind Sie immer noch stark auf Formen beschränkt, die Sie mit diesen Formeln erstellen können (= einfache) - und es ist nicht trivial, eine zu finden.
* siehe Kommentare

wondra
quelle
9
In vielen Fällen (einschließlich des OP-Beispiels) ist die Verwendung einer separaten Textur für die Farbe übertrieben. In den meisten Fällen können Sie den Graustufen-Maskenverlauf nur den Farben zuordnen, die als Uniformen für den Shader festgelegt wurden, und dennoch alle Maskenwerte unterhalb eines bestimmten Schwellenwerts verwerfen.
bcrist
1
Sie brauchen nicht das dunkelste, nicht das schwarze, Sie können den Alpha-Kanal verwenden, um nicht gewünschte Pixel auszublenden.
Jack Aidley
1
@JackAidley sicher, dass wäre möglich, aber ich wollte die Lösung so flexibel wie möglich - in den meisten AAA-Titeln haben Sie nicht nur "rot", aber es ist texturiert.
Wondra
1
@bcrist guter Punkt, ich dachte darüber nach, es als Optimierung vorzuschlagen. Da ich es nicht richtig zeichnen konnte, beschloss ich, es so einfach wie möglich zu halten und die Optimierung für die Implementierung zu überlassen.
Wunder
@wondra In vielen Fällen, einschließlich des Beispiel-Looks im OP, können Sie anstelle einer Textur einen prozeduralen Farbverlauf oder einen eindimensionalen Farb-Lookup (mit der Maskenebene als Eingabe) verwenden.
Random832
34

Mathematisch implementiert als Pixel Shader:

Berechnen Sie auf der CPU HealthDirection und sein Skalarprodukt mit V2 Bildbeschreibung hier eingeben

Berechnen Sie auf der GPU für jedes Pixel eine normalisierte Richtung vom Mittelpunkt weg. Vergleichen Sie jedes Punktprodukt mit HealthDirections, um zu entscheiden, ob "Hintergrund" oder Farbe verwendet werden soll. Bildbeschreibung hier eingeben

Wenn Sie diesen Algorithmus "invertiert" und aus der anderen Richtung gearbeitet haben, können Sie die Richtung jedes Pixels wieder in einen Prozentsatz "auflösen" und sie stattdessen mit HealthPercent vergleichen. Wenn der Prozentsatz jedes Pixels berechnet ist, wird das Verblassen von Rot zu Grün auf der GPU trivial.

Zeichnen Sie den Balken, indem Sie den Algorithmus zuerst auf ein Quad anwenden. Gibt Farben zwischen rangeMin und rangeMax (kann gebacken werden) und clip () aus oder gibt sie überall transparent aus. Als Nächstes zeichnen Sie das (modifizierte) Sprite mit Alpha darüber. Ich habe Ihre Leiste in CAD nachgezeichnet, sie mit Fluten gefüllt und dann die Volltonform in Paint mit einem Zauberstab "umwandelt", um sie zu löschen. Meins sieht nach Mist aus, weil AutoCAD und Paint von Hand gemischt wurden. Vorausgesetzt, Sie mischen die Innenkanten transparent, wird Ihre perfekt aussehen .

Der weiße Rand ist die Grenze des Quadrats. Es und die roten X dienen nur als Referenz:

Bildbeschreibung hier eingeben

Das "Sprite mit Loch" muss nicht gleichzeitig mit der Gesundheitsleiste gerendert werden. Sie sollten alle auf einmal instanziiert und gezeichnet werden, nachdem alle Gesundheitsriegel vollständig sind. Da der Algorithmus im Shader in sich geschlossen ist, können Sie ihm auch eine Instanz hinzufügen und dann alle Healthbars mit einem instanziierten Draw-Aufruf zeichnen. Das Zeichnen jeder Healthbar auf dem Bildschirm sollte zwei DrawInstanced-Aufrufe (...) annehmen und "verrückt schnell" sein.

Jon
quelle
1
Wenn Sie auf diese Weise kreisförmig maskieren, können Sie dies effizienter implementieren, indem Sie einfach die Dreiecke ändern, die Sie für eine kreisförmige Überblendung zeichnen.
Jack Aidley
@ JackAidley, bitte genauer, da ich diese Maskierung nicht betrachte. Der Fortschrittsbalken wird auf nur zwei Dreiecken ohne Abtastung nach dem ersten Durchgang vollständig angezeigt. Das Sprite hat zufällig ein Loch und "verschönert" das Ganze am Ende. (Es ist eine Art Maske, aber nicht als integraler Bestandteil des Algorithmus?) Danke
Jon
Was Sie tun, entspricht dem Zeichnen einer maskierten Version der farbigen Leiste über einem Hintergrundsprite, das bereits die graue Farbe aufweist. Da Ihre Methode einen benutzerdefinierten Shader erfordert und auf jedes Pixel schreibt, ist die Methode langsamer als das Zeichnen nur des gewünschten Teils der Form.
Jack Aidley
@JackAidley, aber es gibt kein Hintergrundsprite? Der Regenbogen wird mit nur vier float3-Weltpositionen gezeichnet. Keine UVs, kein "Hintergrundsprite". Sie befürchten außerdem, dass der Pixel-Shader bei der Arbeit an einigen winzigen Quads hängen bleibt? Außerdem schneiden RangeMin und RangeMax die meisten dieser Fragmente sofort ab ().
Jon
Sie benötigen ein Hintergrundsprite, um die im Originalbild gezeigten Ränder zu erhalten. Wenn Sie diese dann weglassen, unterscheiden sich die Methoden.
Jack Aidley