Was ist eine gute Methode zum Färben von Texturen basierend auf einer Palette in XNA?

8

Ich habe versucht, mit XNA an einem Spiel mit dem Aussehen eines 8-Bit-Spiels zu arbeiten, insbesondere mit dem NES als Leitfaden.

Das NES hat eine sehr spezifische Palette und jedes Sprite kann bis zu 4 Farben aus dieser Palette verwenden. Wie könnte ich das emulieren? Derzeit habe ich eine Textur mit definierten Werten, die als Indizes für ein Array von Farben dienen, die ich an die GPU übergebe. Ich stelle mir vor, es muss einen besseren Weg geben, aber vielleicht ist dies der beste Weg?

Ich möchte nicht einfach sicherstellen, dass ich jedes Sprite mit den richtigen Farben zeichne, weil ich die Palette dynamisch ändern möchte. Ich würde es auch vorziehen, die Textur nicht direkt mit der CPU zu ändern.

Bob
quelle

Antworten:

7

Ich denke, was du tust, ist in Ordnung.

Wenn Sie mehr als vier Farben hatten, könnte ich vorschlagen, eine abhängige Textur zu lesen: Anstatt den Wert der Textur zum Nachschlagen eines Arrays von Farben zu verwenden (ich nehme an, Sie übergeben diese als Shader-Parameter), können Sie ihn zum Nachschlagen verwenden Eine Farbe in einer anderen 1D-Textur, die Ihre Palette enthält.

Dies hat jedoch einige Auswirkungen auf die Leistung - und ich denke, es beschränkt Sie auf PS 2.0.

(Es sind einige andere hinterhältige Optimierungen möglich, wenn Sie bei jedem Sprite die Palette wechseln müssen und alle zusätzlichen Stapel die Leistung beeinträchtigen. Aber ich stelle mir vor, dass dies in einem NES-ähnlichen Spiel nicht der Fall ist.)

Ich denke, was in Ihrer Situation nützlich sein könnte, ist die Verwendung der XNA-Inhaltspipeline, um eine leicht bearbeitbare Farbversion des Sprites zu erstellen. Überprüfen Sie, ob nur vier Farben verwendet werden, und konvertieren Sie sie in eine Textur mit Ihren vier Graustufenebenen (die von Ihnen verwendet werden kann Shader) und geben möglicherweise auch die ursprüngliche Farbpalette neben der Textur aus.

Die Creators Club- Beispiele für die Inhaltspipeline sind möglicherweise ein guter Ausgangspunkt.

Andrew Russell
quelle
1
+1 Die Inhaltspipeline kann manchmal dein Freund sein. Nutzen Sie es zu Ihrem Vorteil.
Michael Coleman
1

Wäre es zu langsam, eine zusammengesetzte Klasse zu erstellen, die bis zu 4 Objekte enthalten kann, die jeweils eine Farbe für das Sprite haben, und diese zu dem Sprite zu kombinieren, das gezeichnet wird. Jedes Sprite besteht also aus bis zu 4 Sprites, die kombiniert und dann gezeichnet werden.

Dann könnten Sie über diese Klasse 1 Farbe ändern und das gesamte Sprite würde sich ändern.

(Beachten Sie, dass ich XNA noch nicht durchgeführt habe, aber dies könnte einige Ideen bei Ihnen auslösen.)

Ólafur Waage
quelle
1

Wenn Sie sich überhaupt nicht für die Speicherleistung interessieren, können Sie Ihre Sprites unkomprimiert speichern, sodass Pixel mit der Farbe 0 rein rot, 1 rein grün, 2 rein blau und 3 rein alpha sind.

Wenn Sie ein Sprite rendern möchten, legen Sie eine Matrix-Pixel-Shader-Konstante fest, die aus vier Vektoren besteht, die den Farben 0, 1, 2, 3 entsprechen. Führen Sie im Pixel-Shader den folgenden Code aus, um das Sprite-Texel neu einzufärben:

float4 unpaletted = tex2D( texture, uv );
float4 paletted = mul( unpaletted, paletteMatrix );

Dies funktioniert, weil ein Pixel, wenn es die Farbe 0 hat, rein rot ist und daher als endet

1 * palette[0] + 0 * palette[1] + 0 * palette[2] + 0 * palette[3]

oder

1 * palette[0]

Gleiches gilt für die Farben 1, 2 und 3.

Wenn Sie sich für die Speicherleistung interessieren, speichern Sie Ihre NES-Palette auf jeden Fall als unkomprimierte 256x1-RGB-Textur, stellen Sie die Texturfilterung auf den nächsten Nachbarn ein, speichern Sie Ihre Sprites als unkomprimierte 8-Bit-Einkanaltexturen und führen Sie Shader-Code wie diesen aus ::

float palette_index = tex2D( texture, uv );
float4 color = tex1D( palette, palette_index * 255 );
bmcnett
quelle