Welche Rendering-Techniken würde ich verwenden, um einen Schlagschatteneffekt für Karten in einem Kartenspiel zu zeichnen?


13

Welche Art von Schattierungsalgorithmus könnte verwendet werden, um solche Schatten zu erzeugen? Bildbeschreibung hier eingeben

Das, was ich mache, ist ähnlich, aber es wird alles mit einer 2D-Zeichnungs-API durchgeführt, die von OpenGL unterstützt wird, sodass es keine Z-Koordinate gibt.

Zusätzlich möchte ich für die Hand selbst ein schattiertes Gefühl wie hier erhalten: Bildbeschreibung hier eingeben

Ich bin mir nur nicht sicher, wie ich einen schattierten Look in der Nähe erzielen soll.

Die Anzahl der Karten wird sich zwangsläufig ändern und die Karten werden auf den Tisch geworfen, so dass ich keine Art von Lichtkarte verwenden kann.

Welche Art von Algorithmen sollte ich untersuchen (abgesehen von Unschärfe, die ich wissen muss?)

Vielen Dank

Aktualisieren

Ich mache ein 2D-Kartenspiel. Ich möchte Dropshadows-Offset von den Karten hinzufügen, ein bisschen wie:

Bildbeschreibung hier eingeben

Die Art und Weise, wie ich daran denke, ist:

  • Behalten Sie eine Textur bei, die dieselbe Größe wie der Backbuffer hat.
  • Zeichne dunkle Rechtecke als provisorische Karten auf diese Textur.

  • Verwischen Sie diese Textur.

  • Ziehe meine Karten auf diese Textur.
  • Beleuchten Sie die Karten zusätzlich.
  • Zeichne diese Textur in den Backbuffer.

Meine Fragen sind:

  • Ist das der richtige Weg, um dies zu tun?

  • Gibt es eine Möglichkeit, dies zu tun, ohne die Textur zu rendern (eine Bitmap
    so groß wie der Backbuffer zu halten)?

  • Ist es sicher anzunehmen, dass die maximale Texturgröße
    von der Backbuffer-Größe nicht überschritten wird? (Was ich meine ist, wenn der Backbuffer
    2000x3000 ist, kann ich dann mit Sicherheit sagen, dass ich eine Textur in einem
    Videospeicher dieser Größe erstellen kann ?

Vielen Dank


1
Ein ästhetischer Punkt auf Ihrer zweite Frage: die nicht wirklich möglich ist , wenn Sie tatsächlich sind halten die Karten in der Hand. Karten, die nebeneinander gedrückt werden, spiegeln sich nicht nennenswert. Nicht, wenn Sie nicht viele davon in der Hand haben. Sie können Karten nicht so halten, wie sie in diesem Bild dargestellt sind. Diese Karten sehen aus, als wären sie mehrere Millimeter voneinander entfernt. Sie sind nicht flach gegeneinander. Ich würde mir einfach keine Sorgen machen.
Nicol Bolas

Antworten:


18

Ich denke, alle geben zu komplizierten Lösungen für dieses Problem nach.

Bildbeschreibung hier eingeben

Wir haben also zuerst die Karte (oder was auch immer Sie ziehen möchten), die hier durch (a) dargestellt ist. Als nächstes nehmen wir eine Kopie davon, füllen sie schwarz aus und lassen eine Gaußsche Unschärfe auf ihr entstehen (b). All dies geschieht in Photoshop oder einem beliebigen anderen Kunstwerkzeug.

Wenn wir im Spiel die Karte ziehen möchten, zeichnen Sie zuerst das verschwommene schwarze Bild mit multiplikativer (oder Alpha) Mischung, etwas versetzt in eine Richtung, und ziehen Sie dann die Karte darüber. Voilá.

Für weitere Tricks kannst du zwischen Schatten und Karten-Render wechseln, um einen Effekt wie (d) zu erzielen, oder erst alle Schatten und dann die Karten wie in (e) zeichnen (ich habe die Karten in der (e) -Hülle gefärbt, um zu zeigen, dass sie sind bist noch getrennt =)

Es ist auch am besten, kein reines Schwarz (oder vollständiges Alpha) für den Schatten zu verwenden, um subtilere, transparentere Schatten zu erzeugen.


2
+1 für Schatten außerhalb des Spiels. Sie können auch einen Schritt weiter gehen und die Position des Schattens ändern, wenn die Szene ein Licht enthält.
FrenchyNZ

+1, schöne Illustration. In Fall E können Sie außerdem dunkle Schatten auf den Tisch rendern und Karten mit Schablone halbhell gestalten. Das wird komplizierter, aber der Effekt wird noch schöner sein :)
Kromster sagt, dass er Monica

2

Der erste ist nicht zu schwer. Wenn Sie einen Alphakanal für Ihre Kartenhand rendern (der für ein Pixel mit einer Karte so einfach wie Schwarz und für Transparent weiß sein kann), können Sie jede Art von Unschärfe nur für den Alphakanal und ausführen Versetzen Sie ihn dann und steuern Sie damit die Beleuchtung des Tisches. (Vermutlich müssten Sie, wenn Sie keinen Z-Buffer haben, zuerst den Alphakanal außerhalb des Bildschirms rendern, dann die Tabelle mit der Maske erstellen und dann die eigentlichen Karten rendern.)

Der zweite sieht ein bisschen aus wie SSAO (Screen-Space Ambient Occlusion). Diese Technik erfordert eine Z-Koordinate. Wenn Sie jedoch nicht die unterschiedlichen Winkel zwischen den Karten haben (was ich denke, wenn Sie keinen Z-Puffer haben), können Sie wahrscheinlich eine ziemlich gute Annäherung treffen, indem Sie für jede Karte einen Schlagschatten (wie den ersten) rendern Karte. Die Leistung könnte jedoch etwas schwierig sein - jedes Flugzeug würde einen unscharfen Alphakanal für alle darüber liegenden Flugzeuge benötigen, und wenn ein Bündel Karten auf dem Tisch liegt, könnte dies eine ganze Reihe von Renderpässen bedeuten.


SSAO ist Overkill =) Es ist sehr schwierig zu sagen, welche Shadow-Technik verwendet wird, ohne das Beispiel animiert zu sehen. Wenn die Karten immer in dieser Reihenfolge und mit diesem Abstand übereinander liegen, ist es am einfachsten, die Schatten vorab zu rendern, aber Sie würden nie wissen, ob das Spiel in Aktion ist.
Patrick Hughes

0

Könntest du keine Schattenkarte machen? Rendern Sie die Szene in einem FBO. Speichern Sie nur die Tiefenwerte und führen Sie im Shader die normale Tiefenwertprüfung durch, um festzustellen, ob ein Schatten gerendert werden soll oder nicht.


Ich benutze keinen Z-Buffer, es gibt keine "Tiefe".
jmasterx

0

Für den folgenden Vorgang ist kein Off-Screen-Rendering-Ziel erforderlich. Doch dabei gewinnt er die Forderung , dass der Tisch gezogen wird zuerst . Oder es wird zumindest nichts auf die Pixel gezeichnet, die die Tabelle abdeckt, bevor die Tabelle gezeichnet wird. Es ist auch erforderlich, dass der Tisch selbst ein einzelnes, nicht überlappendes Teil ist: ein Bild.

Außerdem benötigt Ihr Framebuffer eine Alpha-Komponente.

  1. Erhalten Sie ein Graustufenbild einer Karte. Machen Sie es an den Rändern verschwommen und vergrößern Sie es möglicherweise. Dies ist Ihr Schattenkartenbild. Beachten Sie, dass dies ein Einkanalbild ist. Wenn Sie in Ihrem Shader auf diese Textur zugreifen, sollten Sie sicherstellen, dass Sie den Einzelwert in die Alpha-Komponente einfügen. Dies kann in Ihrem Shader oder anderswo erfolgen.

    Ein Wert von 0,0 im Bild bedeutet, dass kein Schatten vorhanden ist. Ein Wert von 1,0 im Bild bedeutet Gesamtschatten . Das heißt, völlig pechschwarz. Sie möchten wahrscheinlich einen Wert von etwa 0,5 als dunkelste Farbe.

  2. Löschen Sie den Bildschirm, sodass das Alpha auf Null gesetzt wird .

  3. Bevor Sie etwas rendern (oder zumindest etwas, das "unter" der Tabelle gerendert wird), rendern Sie für jede Karte die unscharfe Textur, versetzt von der tatsächlichen Position der Karte (aber mit derselben Ausrichtung). Die vom Shader ausgegebene Farbe sollte lauten. Die Mischkonfiguration dafür sollte lauten (in OpenGL):

    glBlendEquation(GL_MAX);

    Dieser Mischmodus verhindert, dass überlappende Schatten immer dunkler oder heller werden. Es wird einfach der dunkelste Wert verwendet, der in dieses Pixel geschrieben wurde. Es sollte gut genug aussehen.

    Sie sollten auch die Farbschreibmaske verwenden, um Farbschreibvorgänge zu deaktivieren.

  4. Rendern Sie die Tabelle. Dabei sollte das Blending wie folgt eingestellt werden:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);

Wenn die Einschränkungen für Sie zu restriktiv sind, müssen Sie ein Renderziel verwenden. Dies geschieht wie folgt:

  1. Erstellen Sie das Schattenkartenbild wie zuvor.

  2. Rendern Sie zuerst die Schatten. Binden Sie den Schatten-Framebuffer (der nur ein Einkanal-Image sein muss, wenn Ihre Hardware auf einen von diesen rendern kann). Löschen Sie den Wert auf Null.

  3. Rendern Sie für jede Karte das Schattenkartenbild wie zuvor versetzt. Ihr Shader sollte auf alle vier Komponenten der Ausgabefarbe den gleichen Wert schreiben. Der Mischmodus sollte wieder sein glBlendEquation(GL_MAX).

  4. Wechseln Sie zurück zum normalen Framebuffer. Zeichne alles, was du beschatten möchtest.

  5. Zeichnen Sie nun ein Vollbild-Quad mit dem von uns gerenderten Schattenbild. Der Shader sollte das aus dem Schattenbild abgerufene Texel im Alpha der Ausgabe speichern. das RGB ist irrelevant. Der Mischmodus sollte sein:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);

Bei der ersten Methode haben Sie Schritt 5 vergessen: Deaktivieren Sie das Mischen und rendern Sie die Karten. Beachten Sie außerdem, dass Sie mit der ersten Methode keine Schatten zwischen den Karten erhalten können, wie im zweiten Screenshot des OP dargestellt.
Nathan Reed

@ NathanReed: Ich dachte, er wüsste, wie man die Dinge selbst abstellt. Auch die "Schatten zwischen Karten" ergeben keinen Sinn, wie ich in meinem Kommentar unter der Frage ausgeführt habe.
Nicol Bolas

1
Es kann nicht realistisch darstellen, wie Sie tatsächlich Karten halten würden, aber es sieht cool aus! Es ist nicht wirklich "sinnvoll", dass die Karten über dem Tisch schweben, wie es auch beim ersten Schuss der
Nathan Reed

0

Ich würde den Schablonenpuffer verwenden. Löschen Sie es auf 1 (vorzugsweise zur gleichen Zeit, wenn Sie die Tiefe löschen), und zeichnen Sie Ihren Tisch. Aktivieren Sie dann den Schablonentest, zeichnen Sie die Schatten mit einer verschwommenen Rechtecktextur, erhöhen Sie sie, wenn Schablone und Tiefe durchlaufen, tun Sie nichts, wenn Schablone fehlschlagen, nichts, wenn Tiefe fehlschlägt, und setzen Sie die Schablonenfunktion auf GL_EQUAL (Ref. 1, Maske 0xff). Deaktivieren Sie den Schablonentest . (Ich habe das noch nicht vollständig getestet, aber es ist von Code abgeleitet, der sich ähnlich verhält und gut funktionieren sollte. Möglicherweise müssen Sie die Parameter anpassen.) Dann zeichne alles andere.

Die Anrufe wären:

glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_EQUAL, 1, 2);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);

// draw shadow textures

glDisable (GL_STENCIL_TEST);

Dies kann nur dann zu Problemen führen, wenn sich zwei unscharfe Kanten leicht überlappen. Ansonsten braucht es nichts Besonderes als das, was OpenGL 1.1 anbietet und funktioniert auf jeder Hardware. (Erwarten Sie vielleicht alte 3DFX-Karten, von denen ich annehme, dass Sie sich keine Sorgen um die Unterstützung machen ...)

Eine zweite Alternative, die in einem nicht leistungskritischen Spiel sehr gut funktionieren sollte, ist glCopyTexSubImage2D. Das funktioniert auch mit einer Textur, die kleiner als der Backbuffer ist, und wird auch auf jeder Hardware gut unterstützt (sie ist Teil von OpenGL 1.1 und wird von Doom 3 verwendet, sodass Sie erwarten können, dass die Unterstützung sehr gut ist).

Das Grundsetup würde so aussehen:

  • Klare Farbe zu Schwarz.
  • Deaktivieren Sie das Tiefenschreiben (obwohl für diese Methode kein Tiefenpuffer erforderlich ist, können Sie diesen Teil ignorieren, da Sie keinen verwenden).
  • Legen Sie ein Ansichtsfenster mit den gleichen Abmessungen wie Ihre Textur fest.
  • Ziehe Karten als weiße Geometrie.
  • glCopyTexSubImage2D an deine Textur an.
  • Schalten Sie das Ansichtsfenster auf die volle Fenstergröße zurück.
  • Zeichne den Tisch wie gewohnt.
  • Zeichnen Sie die Textur als Quad mit Vollbild-Überblendung und verwenden Sie einen Shader, um sie zu verwischen und die Farbe zu invertieren.
  • Alles andere zeichnen.

Das sollte auch sehr gut funktionieren, es ist ein bisschen GPU-intensiver als die Stencil-Buffer-Methode, behandelt aber den überlappenden Fall korrekt und - wie gesagt - ich denke, ein Spiel wie Ihr wird GPU-Power zum Brennen haben, auch auf einem Low-End Karte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.