Używanie XNA ContentPipeline do eksportowania pliku na maszynie bez pełnego XNA GS

9

Moja gra wykorzystuje potok treści do ładowania spriteSheet w czasie wykonywania. Artysta do gry wysyła mi zmodyfikowany arkusz sprite, a ja robię kompilację na moim komputerze i przesyłam mu zaktualizowany projekt. Więc szukam sposobu na wygenerowanie plików xnb na jego komputerze (jest to wyjście potoku zawartości) bez konieczności instalowania pełnego studia XNA Game.

1) Nie chcę, aby mój artysta zainstalował VS + Xna (wiem, że jest darmowa wersja VS, ale nie będzie skalowana, gdy dodamy więcej osób do zespołu). 2) Nie jestem zainteresowany uruchomieniem tego edytora / narzędzia na Xbox, więc działa tylko rozwiązanie Windows. 3) Mam świadomość opcji MSBuild, ale wymagają one pełnego XNA

Przejrzałem blog Shawna i znalazłem opcję użycia Msbuild Sample lub nową opcję w XNA 4.0, która wyglądała tutaj obiecująco , ale wygląda na to, że ma takie samo ograniczenie: Musisz zainstalować pełną wersję XNA GS, ponieważ ContentPipeline nie jest częścią redisty XNA.

Czy ktoś znalazł rozwiązanie tego problemu?

krolth
źródło

Odpowiedzi:

11

Wydaje się, że właściwą odpowiedzią na to jest pominięcie ContentPipeline i użycie Texture2D.FromStream do załadowania tekstur w czasie wykonywania. Ta metoda działa dobrze na PC i choć będzie niewielki wzrost wydajności, mogę to zoptymalizować, gdy będę bliżej daty premiery. Na razie potrzebuję możliwości dynamicznego modyfikowania zawartości zarówno edytora, jak i gry. Po zablokowaniu zawartości mogę to zoptymalizować, wracając do ContentPipeline.

Ponieważ wybrałeś tę trasę, muszę cię ostrzec, że tak naprawdę nie jest tak prosta, jak skorzystanie Texture2D.FromStreamz dwóch powodów:

Problem nr 1 - Brak wstępnie pomnożonej obsługi alfa

XNA4 domyślnie obsługuje teraz tekstury z kolorami we wstępnie zmultiplikowanym formacie alfa. Gdy ładujesz teksturę przez potok zawartości, przetwarzanie jest wykonywane automatycznie. Niestety Texture2D.FromStreamnie robi tego samego, więc wszelkie tekstury wymagające pewnego stopnia przejrzystości zostaną załadowane i renderowane niepoprawnie. Poniżej znajduje się zrzut ekranu ilustrujący problem:

wprowadź opis zdjęcia tutaj

Aby więc uzyskać prawidłowe wyniki, musisz sam wykonać przetwarzanie. Metoda, którą pokażę, wykorzystuje procesor graficzny do przetworzenia, więc jest dość szybka. Został oparty na tym świetnym artykule . Oczywiście możesz również poinstruować, SpriteBatchaby renderować w starym trybie NonPremultiplyAlpha, ale tak naprawdę nie polecam tego robić.

Problem nr 2 - Nieobsługiwane formaty

Potok treści obsługuje więcej formatów niż Texture2D.FromStream. W szczególności Texture2D.FromStreamobsługuje tylko png, jpg i gif. Z drugiej strony, potok treści obsługuje bmp, dds, dib, hdr, jpg, pfm, png, ppm i tga. Jeśli spróbujesz załadować obsługiwany format Texture2D.FromStream, otrzymasz InvalidOperationExceptionniewiele dodatkowych informacji.

Naprawdę potrzebowałem wsparcia bmp w moim silniku, więc w tym konkretnym przypadku znalazłem obejście, które wydaje się działać dobrze. Nie znam jednak żadnego z innych formatów. Złap z moją metodą polega na tym, że musisz dodać odwołanie do System.Drawingzestawu do swojego projektu, ponieważ korzysta on z GDI, Image.FromStreamktóre obsługują więcej formatów niż Texture2D.FromStream.

Jeśli nie zależy ci na obsłudze bmp, możesz łatwo upuścić tę część mojego rozwiązania i po prostu wykonać wstępnie pomnożone przetwarzanie alfa.

Rozwiązanie - prosta wersja (wolniejsza)

Po pierwsze, oto najprostsze rozwiązanie, jeśli nie zależy ci na obsłudze bmps. W tym przykładzie etap przetwarzania odbywa się całkowicie na CPU. Jest nieco wolniejszy niż alternatywa, którą pokażę poniżej (przeprowadziłem testy porównawcze obu rozwiązań), ale łatwiej zrozumieć:

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;
}

Jeśli zależy Ci na bmps, musisz najpierw załadować obraz za pomocą GDI, a następnie przekonwertować go do formatu PNG przed przekazaniem go do Texture2D.FromStream. Oto kod, który to robi:

// 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);
    }
}

Rozwiązanie - wersja złożona (szybsza)

Wreszcie podejście, które stosuję w moich projektach, polega na wykorzystaniu procesora graficznego do przetwarzania zamiast tego. W tej metodzie musisz utworzyć cel renderowania, poprawnie ustawić niektóre stany mieszania i narysować obraz dwukrotnie za pomocą SpriteBatch. Na koniec przeglądam cały RenderTarget2D i klonuję zawartość do osobnego obiektu Texture2D, ponieważ RenderTarget2D jest niestabilny i nie przetrwa takich rzeczy, jak zmiana rozmiaru bufora, więc bezpieczniej jest wykonać kopię.

Zabawne jest to, że pomimo tego wszystkiego, w moich testach to podejście działało około 3 razy szybciej niż procesor. Jest to więc zdecydowanie szybsze niż przesuwanie każdego piksela i samodzielne obliczanie koloru. Kod jest nieco długi, więc umieściłem go w koszu z kodami:

http://pastie.org/3651642

Po prostu dodaj tę klasę do swojego projektu i użyj jej tak prosto, jak:

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

Uwaga: Musisz utworzyć tylko jedną TextureLoaderinstancję dla całej gry. Używam również poprawki BMP, ale możesz ją usunąć, jeśli nie potrzebujesz i zyskać sporo wydajności, lub po prostu zostaw needsBmpparametr jako fałszywy.

David Gouveia
źródło
wow, to świetnie! Bardzo mi to pomoże :) Bardzo dziękuję David, doceniam to.
krolth
+1 Właściwie używałem FromStreamze strumieniem pamięci zawierającym 32-bitową mapę bitową (zapisaną do png), tak jak twój inny przykład, ale ta metoda nie stworzyła wstępnie pomnożonej tekstury. Dzięki oczywiste wstępne zastosowanie każdego koloru załatwiło sprawę, dzięki.
Groo,
3

Myślę, że większość zespołów zatwierdziłaby zmiany xnb (cóż, wszystkie zmiany naprawdę, w tym xnb włącznie) na swoim serwerze svn (który można skonfigurować za darmo) i pozwolić innym (artystom itp.) Na aktualizację własnych kopii roboczych.

W rzeczywistości byłby to dobry mechanizm dla artysty do kontroli wersji oryginalnej (poprzedniej) sztuki. Popełniłby zmiany w tym, zaktualizowałbyś jego roboczą kopię, skompilowałeś (czyniąc go xnb w procesie), zatwierdził twoje zmiany, aktualizował swoją roboczą kopię twojej pracy i wszyscy mają wszystkie zmiany. (Masz najnowszą surową grafikę, on ma xnb (s).

To również skaluje się bardzo dobrze.

Steve H.
źródło
Więc mówisz, że nie sądzisz, że da się to zrobić? Twoja sugestia polega na dodaniu kontroli wersji do XNB i duszków, już to robimy. Ale nie podoba mi się to, ponieważ stałem się dla nich wąskim gardłem. Napisałem już dla nich narzędzie do edycji animacji i mogą je wypróbować w grze. Ale jeśli wprowadzą zmiany w arkuszu sprite, muszą poczekać, aż zbuduję go, zanim będą mogli go zobaczyć. Jak możesz sobie wyobrazić, jeśli popełnią błąd, muszą to zrobić ponownie.
krolth
@krolth Czy to wielka sprawa, że ​​twoi artyści otrzymują VS Express i XNA w ramach przygotowania ich do pracy nad projektem? Myślę, że w tym momencie kompromis polegający na napisaniu przewodnika i pomocy ludziom przez niego znacznie przewyższy wydajność, którą tracisz teraz, ponieważ artyści nie mogą zobaczyć swojej pracy w silniku. Aby usprawnić proces, podaj plik .BAT, który można kliknąć dwukrotnie, aby ponownie skompilować wszystko bez konieczności otwierania IDE. A jeśli działają tylko na OS X, to ciężkie gówno. Witamy w Game Dev. Mogą zatwierdzić swoje duszki i czekać na kolejne zatwierdzone XNB.
michael.bartnett
to nie jest taka wielka sprawa, tylko ból. Ale chyba będzie trzeba. Dziękujemy wszystkim za odpowiedzi / komentarze!
krolth
1

Ciągle to badam i opublikuję to na korzyść osoby, która ma to samo pytanie.

Wydaje się, że właściwą odpowiedzią na to jest pominięcie ContentPipeline i użycie Texture2D.FromStream do załadowania tekstur w czasie wykonywania. Ta metoda działa dobrze na PC i choć będzie niewielki wzrost wydajności , mogę to zoptymalizować, gdy będę bliżej daty premiery.

Na razie potrzebuję możliwości dynamicznego modyfikowania zawartości zarówno edytora, jak i gry. Po zablokowaniu zawartości mogę to zoptymalizować, wracając do ContentPipeline.

krolth
źródło
Czy przetestowałeś to poprawnie? Z mojego doświadczenia Texture2D.FromStreamnie wystarczy. Powodem tego jest to, że skoro wersja 4 XNA działa ze wstępnie powielokrotnionymi teksturami alfa, a podczas gdy potok treści zajmuje się tym przetwarzaniem automatycznie, Texture2D.FromStreamnie robi to, więc prawdopodobnie będziesz mieć problemy podczas rysowania duszków z przezroczystością. Mogę jednak opublikować działające rozwiązanie.
David Gouveia
Ponadto Texture2D.FromStreamnie obsługuje ładowania .BMPplików, gdy działa potok treści. Jest to coś, co prawdopodobnie Cię zrzuciłoby, gdybyś używał .BMPwcześniej jakichkolwiek zasobów, a następnie przestawiał się na Texture2D.FromStream. Mam również obejście tego ograniczenia. Po prostu pójdę naprzód i opublikuję to.
David Gouveia
0

Sprawdź ten projekt .

Umożliwi Twojemu twórcy tworzenie XNB z niemal wszystkiego, co obsługuje domyślny potok treści XNA. Redystrybucyjny szkielet XNA jest nadal potrzebny, chociaż twój artysta nie potrzebuje Visual Studio.

ClassicThunder
źródło
Dzięki za wskaźnik. Patrząc na kod, wygląda to na modyfikację próbki Microsoft, o której wspomniałem. Zależy to od zainstalowania pełnej wersji XNA Game Studio (patrz ContentBuilder.cs). Jak myślisz, dlaczego tak nie jest?
krolth
Nie sądzę, żeby tak było. Jeśli chcesz korzystać z potoku treści, musisz mieć pełne studio gier. Jednak projekt nie pozwala twoim artystom na korzystanie z Visual Studio. Jedyne inne alternatywy to przepisanie potoku treści.
ClassicThunder