Effizientes 2D-Tile-basiertes Beleuchtungssystem

7

Was ist der effizienteste Weg, um Beleuchtung für eine Kachel-basierte Engine in Java zu tun? Würde es einen schwarzen Hintergrund hinter die Kacheln stellen und das Alpha der Kacheln verändern? Oder einen schwarzen Vordergrund setzen und das Alpha davon ändern? Oder irgendetwas anderes?

Dies ist ein Beispiel für die Art der Beleuchtung, die ich möchte:

    
Kyranstar 30.08.2013, 04:55
quelle

3 Antworten

19

Es gibt viele Möglichkeiten, dies zu erreichen. Nehmen Sie sich Zeit, bevor Sie Ihre endgültige Entscheidung treffen. Ich werde kurz einige Techniken zusammenfassen, die Sie verwenden könnten, und am Ende Code bereitstellen.

Hartes Licht

Wenn Sie einen Lichteffekt mit harten Kanten erzeugen möchten (wie Ihr Beispielbild), Einige Ansätze kommen mir in den Sinn:

Schnell und schmutzig (wie Sie vorgeschlagen haben)

  • Verwenden Sie einen schwarzen Hintergrund
  • Legen Sie die Alpha-Werte der Kacheln entsprechend ihrem Dunkel -Wert fest
  

Ein Problem ist, dass Sie eine Kachel weder heller als zuvor machen (Lichter) noch die Farbe des Lichts ändern können. Beides sind Aspekte, die die Beleuchtung in Spielen normalerweise gut aussehen lassen.

Ein zweiter Satz von Kacheln

  • Verwenden Sie eine zweite Gruppe von (schwarzen / farbigen) Kacheln
  • Legen Sie diese über die Hauptkacheln
  • Legen Sie den Alpha-Wert der neuen Kacheln fest, je nachdem wie stark die neue Farbe sein soll.
  

Dieser Ansatz hat die gleiche Wirkung wie der erste, mit dem Vorteil, dass Sie die Überlagerungsfliese jetzt in einer anderen Farbe als schwarz färben können, was sowohl farbige Lichter als auch helle Lichter erlaubt.

Beispiel:

  

Auch wenn es einfach ist, ein Problem ist, dass dies in der Tat ein sehr ineffizienter Weg ist. (Zwei gerenderte Kacheln pro Kachel, konstantes Nachfärben, viele Renderoperationen usw.)

Effizientere Ansätze (harte und / oder weiche Beleuchtung)

Wenn ich Ihr Beispiel betrachte, stelle ich mir vor, dass das Licht immer von einer bestimmten Quelle kommt (Zeichen, Fackel, etc.)

  • Für jede Art von Licht (große Taschenlampe, kleine Taschenlampe, Charakterbeleuchtung) Erstellen Sie ein Bild, das das spezifische Beleuchtungsverhalten relativ zur Quellkachel (Lichtmaske) darstellt. Vielleicht so etwas für eine Fackel (weiß ist Alpha):

  • Für jede Kachel, die eine Lichtquelle ist, rendern Sie dieses Bild an der Position der Quelle als Überlagerung.
  • Um ein bisschen helle Farbe hinzuzufügen, können Sie z.B. 10% opak orange statt voll Alpha.

Ergebnisse

Hinzufügen von weichem Licht

Weiches Licht ist jetzt keine große Sache, verwenden Sie einfach mehr Details in der Lichtmaske im Vergleich zu den Fliesen. Wenn Sie nur 15% Alpha in der normalerweise schwarzen Region verwenden, können Sie einen niedrigen Sichteffekt hinzufügen, wenn eine Kachel nicht leuchtet:

  

Sie können sogar komplexere Beleuchtungsformen (Kegel usw.) einfach durch Ändern des Maskenbildes erreichen.

Mehrere Lichtquellen

Bei der Kombination mehrerer Lichtquellen führt dieser Ansatz zu einem Problem: Das Zeichnen von zwei Masken, die sich überschneiden, könnte sich aufheben:

Wir wollen, dass sie ihre Lichter hinzufügen, anstatt sie zu subtrahieren. Vermeiden Sie das Problem:

  • Invertiere alle Lichtmasken (mit Alpha als dunklen Bereichen, undurchsichtig als helle Bereiche)
  • Rendern Sie alle diese Lichtmasken in ein temporäres Bild mit den gleichen Abmessungen wie das Ansichtsfenster
  • Invertiere und rende das neue Bild (als ob es die einzige Lichtmaske wäre) über die gesamte Szenerie.

Dies würde etwas Ähnliches ergeben:

Code für die Methode zum Invertieren von Masken

Wenn Sie alle Kacheln in BufferedImage zuerst rendern, Ich werde einen Führungscode zur Verfügung stellen, der der zuletzt gezeigten Methode ähnelt (nur Graustufenunterstützung).

Mehrere Lichtmasken für z.B. Eine Fackel und ein Spieler können so kombiniert werden:

%Vor%

Die letzte Maske wird mit dieser Methode erstellt und angewendet:

%Vor%

Wie bereits erwähnt, ist dies ein primitives Beispiel. Das Implementieren von Farbmischen könnte ein bisschen mehr Arbeit sein.

    
bricklore 09.12.2013, 19:16
quelle
9

Raytracing könnte der einfachste Weg sein.

  • Sie können speichern, welche Kacheln angezeigt wurden (wird für das Automapping verwendet, verwendet für 'Erinnern Sie sich an Ihre Karte, während Sie geblendet werden', vielleicht für die Minikarte usw.)
  • du zeigst nur, was du siehst - vielleicht blockiert ein Monster einer Mauer oder eines Hügels deine Sicht, dann hält Raytracing an diesem Punkt an.
  • entfernte "glühende Objekte" oder andere Lichtquellen (Fackellava) können gesehen werden, auch wenn die eigene Lichtquelle nicht sehr weit reicht.
  • Die Länge Ihrer Strahlen wird verwendet, um Menge Licht (verblassendes Licht) zu überprüfen
  • Vielleicht haben Sie einen speziellen Sensor (ESP, Gold / Lebensmittelerkennung), mit dem Sie Objekte finden, die Sie nicht sehen können? raytrace könnte auch helfen ^^

Wie ist das einfach?

  • Zeichnen Sie eine Linie von Ihrem Player zu jedem Punkt der Grenze Ihrer Karte (mit Hilfe des Breshehams-Algorithmus Ссылка ) gehe entlang dieser Linie (von deinem Charakter bis zum Ende), bis deine Sicht blockiert ist; An dieser Stelle stoppen Sie Ihre Suche (oder machen Sie vielleicht eine letzte letzte Wiederholung, um zu sehen, was Sie getan hat)
  • Setzen Sie für jeden Punkt auf Ihrer Linie die Beleuchtung (vielleicht 100% für die Entfernung 1, 70% für die Entfernung 2 usw.) und markieren Sie die Kachel als besucht

vielleicht gehst du nicht über die ganze Map, vielleicht ist es genug, wenn du deine Raytrace für eine 20x20-Ansicht einstellst? Hinweis: Sie müssen wirklich entlang der Grenzen des Ansichtsfensters gehen, es ist nicht erforderlich, jeden Punkt zu verfolgen.

Ich füge den Zeilenalgorithmus hinzu, um Ihre Arbeit zu vereinfachen:

%Vor%

Ich habe dieses ganze Blitzzeug vor einiger Zeit gemacht, ein * pathfindin fühle mich frei, weitere Fragen zu stellen

Anhang: vielleicht füge ich einfach die kleinen algorithmen für raytracing ^^

hinzu

um den Norden zu bekommen & amp; South Border Point benutze einfach dieses Snippet:

%Vor%

und die Raytrace funktioniert so:

%Vor%     
Martin Frank 12.12.2013 09:49
quelle
1

Ich bin jetzt seit ungefähr drei Jahren in der Entwicklung von Indie-Spielen. Die Art und Weise, wie ich dies tun würde, ist zunächst einmal OpenGL, damit Sie alle Vorteile der grafischen Rechenleistung der GPU nutzen können (hoffentlich tun Sie das schon). Angenommen, wir beginnen mit allen Kacheln in einem vollständig beleuchteten VBO. Jetzt gibt es mehrere Möglichkeiten, um zu erreichen, was Sie wollen. Abhängig davon, wie komplex Ihr Beleuchtungssystem ist, können Sie einen anderen Ansatz wählen.

  • Wenn Ihr Licht rund um den Player ist, unabhängig davon, ob Hindernisse das Licht im wirklichen Leben blockieren würden, könnten Sie sich für einen Beleuchtungsalgorithmus entscheiden, der im Vertex-Shader implementiert ist. Im Vertex-Shader können Sie den Abstand des Eckpunkts zum Player berechnen und eine Funktion anwenden, die definiert, wie helle Objekte in Abhängigkeit von der berechneten Entfernung funktionieren sollen. Verwenden Sie kein Alpha, sondern multiplizieren Sie einfach die Farbe der Textur / Kachel mit dem Lichtwert.

  • Wenn Sie eine benutzerdefinierte Lightmap verwenden möchten (was wahrscheinlicher ist), würde ich vorschlagen, ein zusätzliches Vertex-Attribut hinzuzufügen, das die Helligkeit der Kachel angibt. Aktualisieren Sie die VBO bei Bedarf. Dieselbe Vorgehensweise gilt hier: Multiplizieren Sie das Pixel der Textur mit dem Lichtwert. Wenn Sie das Licht rekursiv mit der Spielerposition als Startpunkt füllen, aktualisieren Sie den VBO jedes Mal, wenn der Spieler sich bewegt.

  • Wenn Ihre Lichtkarte davon abhängt, wo das Sonnenlicht auf Ihr Niveau trifft, können Sie zwei Arten von Beleuchtungstechniken kombinieren. Erstellen Sie ein Vertex-Attribut für die Sonnenhelligkeit und ein weiteres Vertex-Attribut für das Licht, das von Lichtpunkten ausgesandt wird (wie eine Fackel, die vom Spieler gehalten wird). Jetzt können Sie diese beiden Werte im Vertex-Shader kombinieren. Angenommen, Ihre Sonne geht auf und geht unter, wie bei Tag und Nacht. Nehmen wir an, die Sonnenhelligkeit ist sun , was ein Wert zwischen 0 und 1 ist. Dieser Wert kann als Uniform an den Vertex-Shader übergeben werden. Das Scheitelpunktattribut, das die Sonnenhelligkeit darstellt, ist s , und das Scheitelpunktattribut, das die Sonnenhelligkeit darstellt, ist l und das für Licht, das von Lichtpunkten emittiert wird, ist flicker Dann könntest du das gesamte Licht für diese Kachel so berechnen:

    %Vor%

    Wo %code% (auch eine Vertex-Shader-Uniform) ist eine Art winkender Funktion, die die kleinen Varianten in der Helligkeit Ihrer Lichtpunkte repräsentiert.
    Dieser Ansatz macht die Szene dynamisch, ohne ständig VBOs neu erstellen zu müssen. Ich habe diesen Ansatz in einem Proof-of-Concept-Projekt implementiert. Es funktioniert großartig. Sie können sehen, wie es hier aussieht: Ссылка . Beachte wie das Fackellicht im Video um 0:40 flackert. Das geschieht durch das, was ich hier erklärt habe.

Martijn Courteaux 11.12.2013 23:04
quelle

Tags und Links