Wie kann ich eine reibungslose Beleuchtung auf Fliesenbasis implementieren?

8

Ich habe an einem 2D-Kachelspiel gearbeitet und eine scharfkantige Beleuchtung implementiert:

Geben Sie hier die Bildbeschreibung ein

Ich möchte, dass es ein bisschen geglättet wird. Ich brauche keine Schatten oder ähnliches, nur einfache Beleuchtung. Ich möchte, dass es eher so aussieht:

Geben Sie hier die Bildbeschreibung ein

Mein aktuelles System verwendet Lichtstärken für jede Kachel auf der Welt und sie werden neu berechnet, wenn eine Kachel platziert oder entfernt wird. Ich benutze, batch.setColor(...)um die Fliesen zu beschatten. Was ist ein guter Weg, um diese gleichmäßige Beleuchtung zu erreichen?

Ich möchte die Light Map Overlay-Methode nicht verwenden, das habe ich bereits versucht und war mit dem Ergebnis nicht zufrieden. Ich möchte einstellen können, wie viel Licht durch einen Block hindurchtreten kann. Zum Beispiel sollte ein Schmutzblock einen Teil des Lichts absorbieren, aber ein Glasblock sollte kein Licht blockieren. Dies war mit der Light Map Overlay-Methode nicht wirklich möglich. UPDATE: Ich habe falsch verstanden, was diese Methode eigentlich ist. Ich verstehe jetzt. Ich habe falsch gedacht. Es tut uns leid!

ProRed
quelle
Um ehrlich zu sein, sieht es mit scharfkantiger Beleuchtung stilvoller aus.
S. Tarık Çetin
Ich mag es nicht so sehr, außerdem ist es ein bisschen schwierig, Hintergrund- und Vordergrundkacheln mit diesem Stil zu unterscheiden.
ProRed

Antworten:

15

Eine einfache Möglichkeit, in einem auf Kacheln basierenden Spiel eine gleichmäßige Beleuchtung zu erzielen, besteht darin, eine "Lichtkarte" auf ein Renderziel zu zeichnen und dieses Renderziel dann über Ihre Szene zu zeichnen, während Sie es mit Alpha mischen.

Ihr Lichtkarten-Rendering-Ziel hat die Größe Ihrer Kachelkarte, jedoch in Pixel. Jedes Pixel würde die helle Farbe seiner entsprechenden Kachel darstellen. Diese Rendertextur würde ungefähr so ​​aussehen (Textur oben links in Schwarzweiß):

Geben Sie hier die Bildbeschreibung ein

Sobald Sie diese leichte Kartentextur haben, können Sie sie als Überlagerung über Ihre Spielwelt zeichnen (ausgestreckt). Sie müssen es richtig festklemmen, damit es sich perfekt über Ihre Kacheln in der Spielwelt erstreckt.

Dann geht es darum, diese Textur in libGDX auf Ihre Spielwelt zu mischen. Um LibGDX zu integrieren (ich persönlich weiß nicht wie), müssen Sie sich möglicherweise die Gdx.gl.glBlendFuncFunktion ansehen .

jgallant
quelle
2
Mit diesem System können Sie die Beleuchtung nach Ihren Wünschen steuern. Sie sind sich nicht sicher, worauf Sie sich beziehen, wenn Sie sagen, dass Sie das Licht nicht blockieren können. Sie sind sich auch nicht ganz sicher, wie Sie Ihr aktuelles System glätten möchten, da Sie buchstäblich nur Ihre Kacheln färben.
Jgallant
4
Dieses System ist übrigens so, wie es Starbound macht.
Qqwy
2
Dies ist ein großartiger Ansatz und ermöglicht Flexibilität dort, wo sie benötigt wird. Ich benutze dies in meinem kachelbasierten Spiel, in dem ich keinen Zugriff auf Shader habe, und es funktioniert großartig!
Tyyppi_77
1
UPDATE : Dies scheint der richtige Weg zu sein. Ich habe diese Methode missverstanden und verstehe sie jetzt vollständig! Ich werde versuchen, diese Methode jetzt zu implementieren, und ich werde dies als die beste Antwort markieren und Ihnen das Kopfgeld geben!
ProRed
2
Wenn Sie weitere Fragen dazu haben, können Sie diese gerne stellen. Ich habe dies implementiert und @ Tyyppi_77 hat es auch kürzlich getan. Ich habe es in XNA / Monogame und Unity gemacht. Tyyppi hat es in SDL gemacht.
Jgallant
4

Ein motorunabhängiger Weg, dies zu tun, ist die Verwendung einer durchschnittlichen Lichtabbildung. Zunächst müssen Sie eine Schwarzweißkarte als 2D-Array von Booleschen Werten generieren, die der Größe der Welt entspricht, in der die Blöcke wahr und leer falsch sind.

So (1 ist schwarz, 0 ist weiß): Karte

Anschließend müssen Sie ein neues 2D-Array erstellen, das dieselbe Größe wie das erste Array hat, jedoch ein Array von Floats ist. Dann wechseln Sie vom schwarzen (True) Block zum schwarzen Block im Array und mitteln den nahegelegenen Abtastwert (siehe unten).

Dieses Bild hilft: gemittelt

Dieses Bild stellt die Stichprobe dar (wobei + falsch und | wahr bedeutet). Wir behandeln True-Werte als 1 und False-Werte als 0. Dann mitteln Sie die 9 Zahlen und fügen sie in den richtigen Teil des Arrays ein. HINWEIS: Stellen Sie sicher, dass Sie beim Abtasten von Kanten äußere Werte als kontextsensitiv behandeln. Zum Beispiel: Unterirdisch könnte die Karte außerhalb der Welt 1 sein und der Himmel sollte 0 sein.

Es sollte so aussehen (aus einem anderen Beitrag):Ende

Dann müssen Sie nur noch jeden Block im Array mit tönen

rgba(tint,tint,tint,1)

(Farbton = der aktuell gemittelte Blockwert im zweiten Array und Alpha spielt keine Rolle). Hinweis: Dies setzt voraus, dass die Pseudofunktion rgba Gleitkommazahlen von 0-1 anstelle von 0-255 nimmt. Wenn dies der Fall ist, gehen Sie einfach wie folgt vor:

rgba(tint*255,tint*255,tint*255,255)

Hoffe das hat ein wenig Sinn gemacht :) Wenn Sie Code wollen, fragen Sie bitte!

UDXS
quelle
Ich danke Ihnen für Ihre Antwort, aber die Sache ist, dass ich in meinem Spiel ( hier ) bereits eine harte Beleuchtung habe . Ich fragte, wie ich dies ändern könnte, um glatter auszusehen ( so )
ProRed
1

Da Sie über Dinge sprechen, die Licht blockieren, gehe ich davon aus, dass Sie ein Modell dafür haben, wie sich Licht ausbreiten soll. Zum Beispiel ist alles ohne Blöcke vollständig beleuchtet, das Licht breitet sich auf alle benachbarten Zellen aus, verliert jedoch eine gewisse Helligkeit.

Sie sollten in der Lage sein, diese Regeln auf der Softwareseite ziemlich einfach zu implementieren, zumindest ist der Glättungsteil nur eine Frage des Werfens eines Shaders auf die von Ihnen erzeugte Lichtkarte.

Die Methoden, die andere beim Überlagern einer Lichtkarte vorgeschlagen haben, sollten Sie sowieso tun. Sie können jedoch ändern, wie Sie diese Lichtkarte erstellen. Sie können es zunächst nur mit den Blockinformationen füllen, dann aber beispielsweise skalieren und in einem Shader glätten. Ein zusätzlicher Vorteil des Lichtkartenansatzes besteht darin, dass Sie einfach auch dynamisches Licht in Ihre Lichtkarte zeichnen können, um Explosionen hervorzuheben oder was Sie haben, und es wird sich natürlich mit dem Rest Ihrer Welt vermischen.

Additive Blend-Inhalte in Ihre Lichtkarte und multiplikative Mischung Ihrer Lightmap mit der Spielwelt.

Ich habe das vor einiger Zeit gemacht, wobei die gleichen Prinzipien angewendet wurden. Dieses System unterstützt nicht, dass der Lichteinfall für verschiedene Geländetypen unterschiedlich ist, sollte jedoch zumindest die Nützlichkeit der Überlagerung einer Lichtkarte veranschaulichen.

Nils Ole Timm
quelle
Ich verstehe, also würde ich die Lichtverhältnisse in Form von Rechtecken rendern, die genau die Größe der entsprechenden Kachel für ein zweites Renderziel haben. Und wie würde ich es glätten?
ProRed
Sie können die GPU damit umgehen lassen, indem Sie sie herunterabtasten, da sie beim Rendern nur linear für Sie interpoliert. Wenn das nicht gut genug ist, können Sie in einem Shader eine Art Unschärfe darüber ausführen. Sie können auch eine feinere Granularität als die Kachelauflösung in Betracht ziehen, wenn Sie sie abhängig von benachbarten Kacheln unterschiedlich zeichnen möchten. Grundsätzlich besteht der schwierige Teil darin, die spezifischen Regeln zu finden, die für welchen Bereich wie viel beleuchtet werden sollen. Wenn Sie diese Regeln aufschreiben, finden Sie normalerweise einen ziemlich einfachen Weg, dies zu tun.
Nils Ole Timm
1

Für eine Taschenlampe ist es ziemlich einfach: Mit einem benutzerdefinierten Pixel-Shader berechnen Sie den Abstand zwischen jedem Fragment und der Taschenlampe. Sie können dann berechnen, wo sich die erste dichte Kachel befindet, die das von der Fackel kommende Licht blockiert. Sie berechnen dann die Entfernung, in der das Licht nicht blockiert ist, multiplizieren diese mit etwas <1, damit die Fackel die Sonne nicht beleuchtet, subtrahieren diese von der Gesamtentfernung und wiederholen sie für den Rest der Entfernung (wo das Licht um um blockiert wurde) mindestens eine Kachel) mit einem viel kleineren Multiplikationswert ... Ich weiß, wie man diese Mathematik macht und es ist nicht zu kompliziert, sie in opengl zu implementieren.

BEARBEITEN: Für eine einfache Lichtquelle mit einem bestimmten Mittelpunkt ist meine Methode extrem einfach. Meins funktioniert jedoch nicht mit Sonnenlicht, aber während die Alpha-Karte für Sonnenlicht sehr gut funktioniert, wäre es für eine Taschenlampe KEINE gute Idee, da es sich möglicherweise um ein sich bewegendes Objekt handelt und das Erstellen einer neuen Karte für jeden Frame nicht angenehm ist Lebenserfahrung. Die beste Lösung ist meiner Meinung nach eine Mischung: Entfernungsberechnung für bestimmte Lichter, die tatsächlich Objekte im Spiel sind, ein separater Shader, den Sie einfach auf die Alpha-Karte werfen, die Sie prozedural mithilfe der oben genannten Technik generiert haben: eine Textur von allen Die Kacheln alphas von Ihrer harten Schattierung, als viele Quadrate, und spielen mit Techniken herum, um es zu glätten.

Paul Boursin
quelle
0

Verwendet Ihr Rendering Scheitelpunktfarben (oder können Sie diese ändern)?

Angenommen, jeder Block ist ein Quadrat mit 4 Scheitelpunkten, das Ihnen einige Optionen bietet, zum Beispiel:

Wenn Ihr aktueller Beleuchtungsalgorithmus einen Lichtwert pro Block anzeigt, können Sie diesen ändern, um einen Wert pro Scheitelpunkt zu erhalten. Alternativ können Sie an jedem Scheitelpunkt die helle Farbe des aktuellen Blocks plus seiner drei Nachbarn mitteln. Jede Lösung wäre kostengünstig.

Chronischer Spielprogrammierer
quelle