Verwenden von XNA ContentPipeline zum Exportieren einer Datei auf einem Computer ohne vollständige XNA GS

9

Mein Spiel verwendet die Inhaltspipeline, um das SpriteSheet zur Laufzeit zu laden. Der Künstler für das Spiel sendet mir das modifizierte Spritesheet und ich baue meine Maschine ein und sende ihm ein aktualisiertes Projekt. Daher suche ich nach einer Möglichkeit, die xnb-Dateien auf seinem Computer zu generieren (dies ist die Ausgabe der Inhaltspipeline), ohne dass er das vollständige XNA Game Studio installieren muss.

1) Ich möchte nicht, dass mein Künstler VS + Xna installiert (ich weiß, dass es eine kostenlose Version von VS gibt, diese wird jedoch nicht skaliert, sobald wir dem Team weitere Personen hinzufügen). 2) Ich bin nicht daran interessiert, diesen Editor / dieses Tool auf Xbox auszuführen, sodass eine Windows-Lösung funktioniert. 3) Ich kenne die MSBuild-Optionen, aber sie erfordern eine vollständige XNA

Ich habe in Shawns Blog recherchiert und die Option gefunden, Msbuild Sample oder eine neue Option in XNA 4.0 zu verwenden, die hier vielversprechend aussah , aber die gleiche Einschränkung zu haben scheint: Es muss die vollständige XNA GS installiert werden, da die ContentPipeline nicht Teil der XNA-Redist ist.

Hat jemand eine Problemumgehung dafür gefunden?

krolth
quelle

Antworten:

11

Die richtige Antwort darauf scheint darin zu bestehen, die ContentPipeline zu überspringen und Texture2D.FromStream zu verwenden, um die Texturen zur Laufzeit zu laden. Diese Methode funktioniert gut in einem PC und obwohl es einen kleinen Leistungseinbruch geben wird, kann ich diese optimieren, sobald ich mich dem Veröffentlichungsdatum nähere. Im Moment ist die Fähigkeit, den Inhalt sowohl für den Editor als auch für das Spiel dynamisch zu ändern, genau das, was ich brauche. Sobald der Inhalt eingefroren ist, kann ich dies optimieren, indem ich zur ContentPipeline zurückkehre.

Da Sie diese Route gewählt haben, muss ich Sie warnen, dass es Texture2D.FromStreamaus zwei Gründen nicht so einfach ist, sie nur zu verwenden :

Problem Nr. 1 - Mangel an vormultiplizierter Alpha-Unterstützung

XNA4 verarbeitet jetzt standardmäßig Texturen mit Farben im vormultiplizierten Alpha-Format. Wenn Sie eine Textur über die Inhaltspipeline laden, erfolgt diese Verarbeitung automatisch für Sie. Leider Texture2D.FromStreamfunktioniert nicht dasselbe, sodass Texturen, die ein gewisses Maß an Transparenz erfordern, geladen und falsch gerendert werden. Unten sehen Sie einen Screenshot, um das Problem zu veranschaulichen:

Geben Sie hier die Bildbeschreibung ein

Um die richtigen Ergebnisse zu erhalten, müssen Sie die Verarbeitung selbst durchführen. Die Methode, die ich zeigen werde, verwendet die GPU, um die Verarbeitung durchzuführen, so dass es ziemlich schnell ist. Es basiert auf diesem großartigen Artikel . Natürlich können Sie auch anweisen SpriteBatch, im alten NonPremultiplyAlpha-Modus zu rendern, aber ich empfehle dies nicht wirklich.

Problem Nr. 2 - Nicht unterstützte Formate

Die Inhaltspipeline unterstützt mehr Formate als Texture2D.FromStream. Insbesondere Texture2D.FromStreamunterstützt nur png, jpg und gif. Andererseits unterstützt die Inhaltspipeline bmp, dds, dib, hdr, jpg, pfm, png, ppm und tga. Wenn Sie versuchen, ein usuportiertes Format zu laden, erhalten Texture2D.FromStreamSie ein InvalidOperationExceptionmit wenig zusätzlichen Informationen.

Ich brauchte wirklich BMP-Unterstützung für meine Engine, also fand ich für diesen speziellen Fall eine Problemumgehung, die in Ordnung zu sein scheint. Ich kenne jedoch keines der anderen Formate. Der Haken bei meiner Methode ist, dass Sie System.DrawingIhrem Projekt einen Verweis auf die Assembly hinzufügen müssen , da GDIs verwendet werden, Image.FromStreamdie mehr Formate als unterstützen Texture2D.FromStream.

Wenn Sie sich nicht für die Unterstützung von bmp interessieren, können Sie diesen Teil meiner Lösung einfach löschen und einfach die vormultiplizierte Alpha-Verarbeitung durchführen.

Lösung - Einfache Version (langsamer)

Hier ist zunächst die einfachste Lösung, wenn Sie sich nicht für die Unterstützung von BMPS interessieren. In diesem Beispiel wird die Verarbeitungsstufe vollständig auf der CPU ausgeführt. Es ist etwas langsamer als die Alternative, die ich unten zeigen werde (ich habe beide Lösungen verglichen), aber leichter zu verstehen:

public static Texture2D FromStream(GraphicsDevice graphicsDevice, Stream stream)
{
    Texture2D texture = Texture2D.FromStream(graphicsDevice, stream);
    Color[] data = new Color[texture.Width * texture.Height];
    texture.GetData(data);
    for (int i = 0; i != data.Length; ++i)
        data[i] = Color.FromNonPremultiplied(data[i].ToVector4());
    texture.SetData(data);
    return texture;
}

Wenn Sie sich für BMPS interessieren, müssen Sie das Image zuerst mit GDI laden und dann intern in PNG konvertieren, bevor Sie es an übergeben Texture2D.FromStream. Hier ist der Code, der das macht:

// Load image using GDI because Texture2D.FromStream doesn't support BMP
using (Image image = Image.FromStream(stream))
{
    // Now create a MemoryStream which will be passed to Texture2D after converting to PNG internally
    using (MemoryStream ms = new MemoryStream())
    {
        image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        ms.Seek(0, SeekOrigin.Begin);
        texture = Texture2D.FromStream(_graphicsDevice, ms);
    }
}

Lösung - Komplexe Version (schneller)

Schließlich verwende ich bei meinen Projekten die GPU, um stattdessen die Verarbeitung durchzuführen. Bei dieser Methode müssen Sie ein Renderziel erstellen, einige Mischzustände ordnungsgemäß einrichten und das Bild zweimal mit einem SpriteBatch zeichnen. Am Ende gehe ich das gesamte RenderTarget2D durch und klone den Inhalt in ein separates Texture2D-Objekt, da das RenderTarget2D flüchtig ist und Dinge wie das Ändern der Backbuffer-Größe nicht überlebt, sodass es sicherer ist, eine Kopie zu erstellen.

Das Lustige ist, dass dieser Ansatz trotz alledem bei meinen Tests etwa dreimal schneller war als der CPU-Ansatz. Es ist also definitiv schneller, als jedes Pixel zu durchlaufen und die Farbe selbst zu berechnen. Der Code ist etwas lang, also habe ich ihn in einen Pastebin gelegt:

http://pastie.org/3651642

Fügen Sie diese Klasse einfach Ihrem Projekt hinzu und verwenden Sie sie so einfach wie:

TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");

Hinweis: Sie müssen nur eine TextureLoaderInstanz für das gesamte Spiel erstellen . Ich verwende auch den BMP-Fix, aber Sie können ihn entfernen, wenn Sie keine Leistung benötigen, oder den needsBmpParameter einfach als false belassen.

David Gouveia
quelle
Wow, das ist großartig! Es wird mir sehr helfen :) Vielen Dank David, ich schätze es.
Krolth
+1 Eigentlich habe ich FromStreammit einem Speicherstrom verwendet, der eine 32-Bit-Bitmap enthält (in PNG gespeichert), genau wie in Ihrem anderen Beispiel, aber diese Methode hat keine vormultiplizierte Textur erstellt. Das explizite Vormultiplizieren jeder Farbe hat den Trick getan, danke.
Groo
3

Ich denke, die meisten Teams würden die xnb-Änderungen (nun ja, alle Änderungen wirklich, einschließlich xnb) auf ihren SVN-Server übertragen (der kostenlos eingerichtet werden kann) und anderen (dem Künstler usw.) erlauben, ihre eigenen Arbeitskopien zu aktualisieren.

Tatsächlich wäre dies ein guter Mechanismus für den Künstler, um die Originalkunst (vor xnb) zu versionieren. Er würde Änderungen daran festschreiben, Sie würden Ihre Arbeitskopie davon aktualisieren, sie erstellen (was sie zu einem xnb im Prozess macht), Ihre Änderungen festschreiben, er würde seine Arbeitskopie Ihrer Arbeit aktualisieren und jeder hat alle Änderungen. (Sie haben die neuesten Rohgrafiken, er hat die xnb (s).

Das lässt sich auch sehr gut skalieren.

Steve H.
quelle
Sie sagen also, Sie glauben nicht, dass dies möglich ist? Ihr Vorschlag ist, der XNB und den Sprites eine Versionskontrolle hinzuzufügen. Das machen wir bereits. Aber ich mag es nicht, weil ich der Engpass für sie werde. Ich habe bereits ein Tool für sie geschrieben, mit dem sie die Animationen bearbeiten können, und sie können sie im Spiel ausprobieren. Wenn sie jedoch Änderungen am Spritesheet vornehmen, müssen sie warten, bis ich es erstellt habe, bevor sie es sehen können. Wie Sie sich vorstellen können, müssen sie es erneut tun, wenn sie einen Fehler machen.
Krolth
@krolth Ist es so wichtig, dass Ihre Künstler VS Express und XNA erhalten, um sie für die Arbeit an einem Projekt einzurichten? Ich denke, an diesem Punkt wird der Kompromiss, einen Leitfaden schreiben und den Menschen dabei helfen zu müssen, die Produktivität, die Sie jetzt verlieren, bei weitem überwiegen, da Künstler ihre Arbeit nicht im Motor sehen können. Um den Prozess zu optimieren, geben Sie ihnen eine .BAT-Datei, auf die sie doppelklicken können, um alles neu zu kompilieren, ohne die IDE öffnen zu müssen. Und wenn sie nur OS X ausführen, na ja, harte Scheiße. Willkommen bei Game Dev. Sie können ihre Sprites festschreiben und auf die nächsten festgeschriebenen XNBs warten.
michael.bartnett
Es ist keine so große Sache, nur ein Schmerz. Aber ich denke, es muss reichen. Vielen Dank an alle für Ihre Antworten / Kommentare!
Krolth
1

Ich habe dies weiter untersucht und werde dies zugunsten von jemandem veröffentlichen, der die gleiche Frage hat.

Die richtige Antwort darauf scheint darin zu bestehen, die ContentPipeline zu überspringen und Texture2D.FromStream zu verwenden, um die Texturen zur Laufzeit zu laden. Diese Methode funktioniert gut in einem PC und obwohl es eine kleine Leistung seinen Hit dies etwas ist , dass ich optimieren kann , wenn ich näher an den Veröffentlichungstermin bin.

Im Moment ist die Fähigkeit, den Inhalt sowohl für den Editor als auch für das Spiel dynamisch zu ändern, genau das, was ich brauche. Sobald der Inhalt eingefroren ist, kann ich dies optimieren, indem ich zur ContentPipeline zurückkehre.

krolth
quelle
Hast du das richtig getestet? Aus meiner Erfahrung Texture2D.FromStreamallein reicht das nicht aus. Der Grund dafür ist, dass XNA in Version 4 mit vormultiplizierten Alpha-Texturen arbeitet und die Inhaltspipeline diese Verarbeitung zwar automatisch für Sie übernimmt, dies Texture2D.FromStreamjedoch nicht der Fall ist, wenn Sie Sprites mit Transparenz zeichnen. Ich kann eine funktionierende Lösung veröffentlichen, wenn Sie möchten.
David Gouveia
Außerdem Texture2D.FromStreamunterstützt keine Lade .BMPDateien während der Inhalt Pipeline tut. Dies ist etwas, das Sie wahrscheinlich abschrecken würde, wenn Sie zuvor .BMPAssets verwendet und dann zu gewechselt hätten Texture2D.FromStream. Ich habe auch eine Problemumgehung für diese Einschränkung. Ich werde einfach weitermachen und es posten.
David Gouveia
0

Schauen Sie sich dieses Projekt an .

Damit kann Ihr Künstler XNB aus nahezu allem erstellen, was die Standard-XNA-Inhaltspipeline unterstützt. Das weiterverteilbare XNA-Framework ist weiterhin erforderlich, obwohl Ihr Künstler Visual Studio nicht benötigt.

ClassicThunder
quelle
Danke für den Zeiger. Wenn ich mir den Code anschaue, scheint es eine Änderung des Microsoft-Beispiels zu sein, auf das ich Bezug genommen habe. Dies hängt davon ab, ob das vollständige XNA Game Studio installiert ist (siehe ContentBuilder.cs). Warum glaubst du, ist das nicht der Fall?
Krolth
Ich glaube nicht. Wenn Sie die Content-Pipeline verwenden möchten, müssen Sie über das vollständige Spielestudio verfügen. Das Projekt verhindert jedoch, dass Ihre Künstler Visual Studio verwenden müssen. Die einzige andere Alternative ist das Umschreiben der Inhaltspipeline.
ClassicThunder