Isometrischer glatter Nebel

7

Ich arbeite an einem einfachen 2D-Spiel mit direct3d 9. Es ist ein isometrisches Spiel mit Diamantplättchen und einer versetzten Karte. Das habe ich:

Diamanten isometrisches Spiel

Wie Sie sehen, habe ich eine Art Nebel, der durch eine Nebelmatrix ergänzt wird, die wahr (klares Gelände) oder falsch (obskurer Terraner) ist. Aber das Ergebnis ist sehr klobig. Der Nebel bewegt sich, während sich der Spieler um Kacheln bewegt, aber nicht um Pixel. Grundsätzlich überprüfe ich für jede Fliese, ob es Nebel gibt, wenn ja, ändere ich einfach die Farbe dieser Fliese:

D3DCOLOR tile_color = 0xffffffff;
if(scene->fog[i+mapx][j+mapy] == FOG_NONE) { tile_color = 0x666666FF; }
g_pSprite->Draw(texTilesNew,&rect,NULL, &D3DXVECTOR3(pantx,panty,0.0f), tile_color);

Wo der Parameter tile_color ist:

Eine Farbstruktur. Die Farb- und Alphakanäle werden durch diesen Wert moduliert. Der transparente Wert behält die ursprüngliche Quellfarbe und die Alpha-Daten bei.

Ich möchte auch, dass der Nebel glatter wird, dafür habe ich dieses "Tutorial" befolgt, aber ich habe es nicht geschafft, es herauszufinden, weil ich denke, dass das Tutorial eine andere Art von Nebel implementiert als ich.

http://www.appsizematters.com/2010/07/how-to-implement-a-fog-of-war-part-2-smooth/

marcg11
quelle
Wie wäre es mit mehr Nebel statt nur Ein-Aus, abhängig von der Entfernung? IMO, die Kacheln geben eine Art Retro-Effekt, der für Ihr spezifisches Spiel positiv sein kann.
Panda Pyjama
Möchten Sie glatte Kanten?
Bandrewk
Ich habe bereits darüber nachgedacht, anstelle von Ein- oder Aus-Kacheln einige Ebenen hinzuzufügen. Aber die Sache ist, der Spieler bewegt sich reibungslos um Pixel, die Karte "Kamera" bewegt sich auch um Pixel. Wenn sich der Spieler beispielsweise um 5 Pixel bewegt, sollte sich der Nebel auch nur um 5 Pixel bewegen und nicht warten, bis sich ein vollständiges Plättchen bewegt.
März 11
5
Okay, wie wäre es, wenn Sie ein halbtransparentes dunkles Bild mit einem vollständig transparenten Loch in der Mitte über den gesamten Bildschirm legen?
Panda Pyjama
@PandaPajama, die Sache ist, dass der sichtbare Bereich nicht zentriert und konstant ist, er bewegt sich abhängig von der Richtung des Charakters. Außerdem muss es einen Weg geben, bei dem keine Bilder hinzugefügt werden müssen, um den Trick auszuführen.
März 11

Antworten:

3

In Ordnung, die Frage ist viel komplexer geworden, daher werde ich meinen Kommentar zu einer Antwort aufrüsten.

Es gibt viele Möglichkeiten, das zu tun, was Sie tun möchten. Je genauer Sie Ihre Beleuchtungsberechnungen wünschen, desto komplexer wird das Programm. Ich rate Ihnen daher, sich darauf zu konzentrieren, es einfach zu halten, und mehr Zeit darauf zu verwenden, dass das Spiel Spaß macht, anstatt sich auf technische Details zu beschränken.

Aber wie auch immer, hier sind einige Methoden, die ich mir vorstellen kann, um das zu erreichen, was Sie wollen:

  1. Machen Sie die Beleuchtung als Nachbearbeitungseffekt! Sie werden nicht glauben, wie häufig diese einfachen Ansätze in AAA-Spielen verwendet werden. Fügen Sie ein schwarzes Sprite hinzu, das sich über den gesamten Spielbereich erstreckt und in der Mitte ein transparentes Loch aufweist. PNG und DXT unterstützen 8-Bit-Alphas, sodass Sie es so reibungslos gestalten können, wie Sie möchten. Der Hauptnachteil ist, dass die Form des Schattens meist statisch ist. Sie können einige interessante Tricks machen, indem Sie mit der Perspektivmatrix herumspielen, aber es ist kaum optimal.

  2. Wenn Sie die Beleuchtung für jede Kachel separat berechnen können, multiplizieren Sie die Sprite-Farbe mit der Schattenstufe auf jeder Kachel oder überlagern Sie eine schwarze Kachel mit dem Alpha-Wert, der auf die Schattenstufe für jede Kachel festgelegt ist. Der Hauptnachteil besteht darin, dass Sie die Abweichungen zwischen den Kacheln leicht bemerken, wenn die Kacheln zu groß sind oder wenn der Schattenbereich zu klein ist. Dies ist übrigens das, was sie in vielen Ultima-Spielen getan haben.

  3. Anstatt die Beleuchtung für jede Kachel zu berechnen, berechnen Sie sie für die Ränder und lassen Sie die Grafik-Engine die Beleuchtung über jede Kachel interpolieren. Legen Sie dazu die Farbe für jeden Scheitelpunkt Ihres Sprite-Netzes fest und legen Sie fest SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD). Das Hauptproblem bei dieser Lösung tritt bei sehr hellen Lichtern mit sehr kurzen Ausbreitungen auf. Möglicherweise bemerken Sie einige Artefakte in der Nähe des Zentrums.

  4. Eine viel komplexere Lösung wäre die Berechnung der Beleuchtung pro Pixel. Dazu können Sie die Position Ihres Players als Konstante für Ihren Pixel-Shader festlegen, an dem Sie die Beleuchtungsberechnung durchführen. Dies ist auf die Pixelebene genau, erfordert jedoch, dass Sie Ihre Grafikpipeline auf die programmierbare ändern (falls Sie die feste Pipeline verwenden). Das ist relativ komplex. Das Hauptproblem bei dieser Lösung (und allen anderen oben genannten) besteht darin, dass sie keine Schatten unter der Kachel betreffen. In welchem ​​Fall...

  5. Sie können die Beleuchtung auch manuell implementieren. Das ist wirklich komplex und nicht für schwache Nerven, aber auch sehr lustig. Es gibt unzählige Ansätze, um dies zu tun. Sie können also anfangen, Prof. Google etwas in Anlehnung an "2D Dynamic Lighting" zu fragen.

Viel Glück mit deinem Spiel.

Panda Pyjama
quelle
Es ist also keine einfache Lösung ...
März 11
Wie einfach soll Ihre Lösung sein? Je komplexer Ihre Antwort sein soll, desto komplexer wird die Implementierung.
Panda Pyjama
Nun, die Sache ist, dass ich kein Experte für direct3d bin. Ich habe gerade vor einigen Wochen angefangen, mit dieser API zu programmieren. Aber ich denke, es gibt keinen Weg, dies zu erreichen (außer Punkt 1), ohne ein Experte in dieser Angelegenheit zu sein.
März 11
Ich weiß nicht, wie Sie g_pSpriteaussehen, aber wenn es sich lediglich um zwei mit 2D-Perspektive gezeichnete Dreiecke handelt, können Sie Option 3 einfach implementieren, indem Sie für jeden Scheitelpunkt unterschiedliche Farben festlegen. Aber wenn Sie ein Anfänger sind, ist Direct3D vielleicht zu überwältigend. Warum probieren Sie nicht eine einfachere Engine aus, damit Sie alle Details einer Grafik-Pipeline verstehen, bevor Sie in Direct3D eintauchen, was möglicherweise absichtlich unnötig schwierig zu bedienen war? Eine einfache Frage: Haben Sie dieses Programm geschrieben? oder kopieren Sie eine Art Beispielcode?
Panda Pyjama
g_pSprite ist vom Typ LPD3DXSPRITE. Die Load-Sprite-Methode mache ich gerade D3DXCreateSprite( g_pD3DDevice, &g_pSprite );und lade dann alle notwendigen Texturen mit D3DXCreateTextureFromFileEx. Ich nehme an, es sind alles Quads, aber ich bin mir nicht sicher. Und ja, es ist mein Programm.
März 11
2

Hier ist ein einfacher Vorschlag: Sie können versuchen, die Nebelintensität für jede Zelle zu modulieren. Hier ist ein Beispiel für die Anwendung eines einfachen Faltungsfilters:

float fog = 0.0;
for (int dj = -3; dj <= 3; dj++)
for (int di = -3; di <= 3; di++)
    if (scene->fog[i+di+mapx][j+dj+mapy] == FOG_NONE)
        fog += 0.0903142 / (0.5 + di * di + dj * dj);
if (fog > 0.0)
    tile_color = (int)(0xff - 0x99 * fog) * 0x01010100 + 0x000000FF;
Sam Hocevar
quelle
Dies funktioniert perfekt, aber der Farbverlauf liegt zwischen Kacheln und nicht zwischen Pixeln in einer einzelnen Kachel.
März 11
@ marcg11 kannst du vielleicht zeigen, wie du Kacheln renderst? Ich kann sehen, dass Sie eine haben tile_color, aber wie wirkt sich das wirklich auf das Rendering aus?
Sam Hocevar
Ich habe den ursprünglichen Beitrag für den Code bearbeitet. Ich zeichne nur die Kachel und die tile_color ist wie ein Tweak zum Kolorieren ...
marcg11
@ marcg11 Danke. Gibt es dann eine Chance, einen Blick auf die DrawMethode zu werfen ?
Sam Hocevar
link
marcg11
1

Anstatt Boolesche Werte in Ihrer Nebelmatrix zu speichern, können Sie Gleitkommawerte speichern. Dies würde die Nebelmenge auf jeder Kachel zwischen 0 und 1 darstellen. Mischen Sie dann einfach Ihre Farbe in Abhängigkeit von der Nebelmenge der Kachel:

float fog_amount = scene->fog[i+mapx][j+mapy];
tile_color = tile_color * (1.0f - fog_amount) + 0x666666FF * fog_amount;

Es gibt wahrscheinlich mehrere Möglichkeiten, diese Nebelmatrix zu erzeugen, aber eine Möglichkeit, die ich mir vorstellen kann, ist:

  • Erstellen Sie Ihre Matrix wie jetzt (mit true = no fog = 0.0 und false = full fog = 1.0).
  • Und wenden Sie ein wenig Gaußsche Unschärfe darauf an.

BEARBEITEN

Ich bin mir nicht sicher, ob dies notwendig sein wird (dies ist einfach eine künstlerische Entscheidung), aber wenn Sie möchten, dass sich die Nebelmenge direkt mit den Bewegungen des Spielers ändert, müssen Sie diese Nebelmatrix unter Verwendung direkter Abstände vom Spieler generieren. Wenn Sie beispielsweise einen einfachen Nebelkreis wünschen, können Sie dies für eine Kachel bei (i, j) in Ihrer Nebelmatrix tun:

float distance_to_player = distance(tile_pos[i][j], player_pos);
fog[i][j] = (distance_to_player - FOG_START) / (FOG_END - FOG_START);

BEARBEITEN 2

Das ist, wenn Sie einen "gekachelten" Nebel halten wollen. Das Überlagern eines durchscheinenden Bildes, wie es von Panda Pyjama in seinen Kommentaren vorgeschlagen wurde, ist möglicherweise eine viel einfachere Lösung, führt jedoch zu einem anderen Ergebnis. Auch dies ist eine künstlerische Entscheidung, die Sie treffen müssen.

Laurent Couvidou
quelle
Aber was ist mit dem Nebel, der sich bewegt, während sich der Spieler bewegt, nach Pixel und nicht nach Kacheln? Es ist so ziemlich das gleiche Ergebnis wie die Antwort unten.
März 11
"0x666666FF * fog_amount"? Was ist das "0x666666FF"?
API-Beast
@ Mr.Beast Das ist die Nebelfarbe, wie im OP
Laurent Couvidou
@ marcg11 Ja, das entspricht der Antwort von Sam Hocevar. Er gibt Ihnen nur den Code, um die Gaußsche Unschärfe direkt pro Pixel auszuführen.
Laurent Couvidou
@ marcg11 Bearbeitet, um Spielerzüge zu berücksichtigen.
Laurent Couvidou