Использование XNA ContentPipeline для экспорта файла на компьютере без полной XNA GS

9

Моя игра использует Content Pipeline для загрузки spriteSheet во время выполнения. Художник для игры отправляет мне измененную таблицу спрайтов, и я делаю сборку на своем компьютере и отправляю ему обновленный проект. Поэтому я ищу способ создания файлов xnb на своем компьютере (это вывод конвейера содержимого) без необходимости установки полной студии XNA Game.

1) Я не хочу, чтобы мой художник установил VS + Xna (я знаю, что есть бесплатная версия VS, но она не будет масштабироваться, когда мы добавим больше людей в команду). 2) Меня не интересует запуск этого редактора / инструмента в Xbox, поэтому работает только решение для Windows. 3) Я знаю о параметрах MSBuild, но они требуют полной XNA

Я исследовал блог Шона и нашел возможность использования MSBuild образца или новый параметр в XNA 4.0 , который выглядел перспективным здесь , но кажется , что это имеет такое же ограничение: необходимо установить полный XNA GS , поскольку ContentPipeline не является частью XNA REDIST.

Так кто-нибудь нашел обходной путь для этого?

krolth
источник

Ответы:

11

Похоже, правильный ответ на этот вопрос - пропустить ContentPipeline и использовать Texture2D.FromStream для загрузки текстур во время выполнения. Этот метод отлично работает на ПК, и хотя производительность будет небольшим, это то, что я могу оптимизировать, как только я подойду к дате выпуска. Пока что возможность динамического изменения контента для редактора и для игры - это как раз то, что мне нужно. Как только контент заморожен, я могу оптимизировать его, вернувшись к ContentPipeline.

Поскольку вы выбрали этот маршрут, я должен предупредить вас, что на самом деле это не так просто, как просто использовать Texture2D.FromStreamпо двум причинам:

Проблема № 1 - Отсутствие предварительно умноженной поддержки альфа

XNA4 теперь обрабатывает текстуры с цветами в предварительно умноженном альфа-формате по умолчанию. Когда вы загружаете текстуру через конвейер содержимого, эта обработка выполняется автоматически. К сожалению, Texture2D.FromStreamэто не делает то же самое, поэтому любые текстуры, которые требуют определенной степени прозрачности, будут загружены и отрисованы неправильно. Ниже приведен скриншот для иллюстрации проблемы:

введите описание изображения здесь

Поэтому, чтобы получить правильные результаты, вам нужно выполнить обработку самостоятельно. Метод, который я покажу, использует графический процессор для выполнения обработки, поэтому он довольно быстрый. Это было основано на этой замечательной статье . Конечно, вы также SpriteBatchможете указать рендеринг в старом режиме NonPremultiplyAlpha, но я не очень рекомендую делать это.

Проблема № 2 - неподдерживаемые форматы

Контентный конвейер поддерживает больше форматов, чем Texture2D.FromStream. В частности, Texture2D.FromStreamподдерживаются только png, jpg и gif. С другой стороны, конвейер контента поддерживает bmp, dds, dib, hdr, jpg, pfm, png, ppm и tga. Если вы попытаетесь загрузить формат usuported через, Texture2D.FromStreamвы получите InvalidOperationExceptionнемного дополнительной информации.

Мне действительно нужна была поддержка bmp на моем движке, поэтому для этого конкретного случая я нашел обходной путь, который, кажется, работает нормально. Я не знаю ни о каком другом формате, хотя. Суть моего метода в том, что вам нужно добавить ссылку на System.Drawingсборку в ваш проект, потому что он использует GDI, Image.FromStreamкоторый поддерживает больше форматов, чем Texture2D.FromStream.

Если вам не нужна поддержка bmp, вы можете легко отбросить эту часть моего решения и просто выполнить предварительно умноженную альфа-обработку.

Решение - простая версия (медленнее)

Прежде всего, вот самое простое решение, если вы не заботитесь о поддержке BMP. В этом примере этап обработки полностью выполняется на процессоре. Это немного медленнее, чем альтернатива, которую я покажу ниже (я тестировал оба решения), но легче понять:

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

Если вам небезразличны bmps, вам нужно сначала загрузить изображение с помощью GDI, а затем преобразовать его в формат PNG, прежде чем передать его Texture2D.FromStream. Вот код, который делает это:

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

Решение - сложная версия (быстрее)

Наконец, подход, который я использую в своих проектах, заключается в том, чтобы вместо обработки использовать графический процессор. В этом методе вам нужно создать цель рендеринга, правильно настроить некоторые состояния наложения и дважды нарисовать изображение с помощью SpriteBatch. В конце я перебираю весь RenderTarget2D и клонирую содержимое в отдельный объект Texture2D, потому что RenderTarget2D является изменчивым и не переживет такие вещи, как изменение размера буфера, поэтому безопаснее сделать копию.

Самое смешное, что, несмотря на все это, в моих тестах этот подход выполнялся примерно в 3 раза быстрее, чем процессорный подход. Так что это определенно быстрее, чем проходить каждый пиксель и вычислять цвет самостоятельно. Код немного длинный, поэтому я поместил его в каталог:

http://pastie.org/3651642

Просто добавьте этот класс в ваш проект и используйте его так же просто, как:

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

Примечание: вам нужно создать только один TextureLoaderэкземпляр для всей игры. Также я использую исправление BMP, но вы можете убрать его, если вам не нужно, и получить кучу производительности, или просто оставить needsBmpпараметр как false.

Дэвид Гувея
источник
вау, это здорово! Это мне очень поможет :) Большое спасибо Дэвид, я ценю это.
Кролт
+1 На самом деле, я использовал FromStreamпоток памяти, содержащий 32-битное растровое изображение (сохраненное в png), как и в вашем другом примере, но этот метод не создавал предварительно умноженную текстуру. Явное предварительное умножение каждого цвета сделало свое дело, спасибо.
Groo
3

Я думаю, что большинство команд передаст изменения xnb (ну, на самом деле, все изменения, включая xnb) на свой svn-сервер (который можно настроить бесплатно) и позволит другим (художнику и т. Д.) Обновлять свои собственные рабочие копии.

Фактически, это было бы хорошим механизмом для художника контролировать версию оригинального (pre-xnb) искусства. Он будет вносить изменения в это, вы обновляете свою рабочую копию, создаете ее (в процессе превращая ее в xnb), фиксируете ваши изменения, он обновляет свою рабочую копию вашей работы, и у всех есть все изменения. (У вас есть последняя необработанная работа, у него есть xnb (s).

Это тоже очень хорошо масштабируется.

Стив Н
источник
Так вы говорите, что не думаете, что это можно сделать? Ваше предложение - добавить контроль версий в XNB и спрайты, мы уже это делаем. Но мне это не нравится, потому что я становлюсь узким местом для них. Я уже написал для них инструмент для редактирования анимации, и они могут попробовать их в игре. Но если они вносят изменения в таблицу спрайтов, им нужно подождать, пока я построю ее, прежде чем они смогут ее увидеть. Как вы можете себе представить, если они совершают ошибку, им нужно сделать это снова.
Кролт
@ krolth Разве это так важно, чтобы ваши художники получили VS Express и XNA, чтобы подготовить их к работе над проектом? Я думаю, что на данном этапе компромисс с необходимостью написания руководства и помощи людям в этом намного перевесит производительность, которую вы теряете сейчас, так как художники не могут видеть свои работы в движке. Чтобы упростить процесс, предоставьте им файл .BAT, по которому они могут дважды щелкнуть, чтобы перекомпилировать все без необходимости открывать IDE. И если они работают только на OS X, ну, круто. Добро пожаловать в игру Dev. Они могут зафиксировать свои спрайты и ждать следующих совершенных XNB.
Майкл Бартнетт
это не так уж важно, просто боль. Но я думаю, что это нужно сделать. Спасибо всем за ваши ответы / комментарии!
Кролт
1

Я продолжал исследовать это и опубликую это в пользу кого-то, у кого есть тот же самый вопрос.

Похоже, правильный ответ на этот вопрос - пропустить ContentPipeline и использовать Texture2D.FromStream для загрузки текстур во время выполнения. Этот метод отлично работает на ПК и даже если будет небольшая производительность хита это то , что я могу оптимизировать когда я ближе к дате релиза.

Пока что возможность динамического изменения контента для редактора и для игры - это как раз то, что мне нужно. Как только контент заморожен, я могу оптимизировать его, вернувшись к ContentPipeline.

krolth
источник
Вы проверяли это правильно? Из моего опыта Texture2D.FromStreamсамо по себе не достаточно. Причина этого в том, что, поскольку версия 4 XNA работает с предварительно умноженными альфа-текстурами, и хотя конвейер содержимого автоматически выполняет эту обработку для вас, Texture2D.FromStreamэтого не происходит, поэтому вы, вероятно, столкнетесь с проблемами при рисовании спрайтов с прозрачностью. Я могу опубликовать рабочее решение, если хотите.
Дэвид Гувея
Кроме того, Texture2D.FromStreamне поддерживает загрузку .BMPфайлов, в то время как конвейер контента поддерживает. Это то, что, вероятно, отбросит вас, если вы ранее использовали какие-либо .BMPактивы, а затем переключились на Texture2D.FromStream. У меня также есть обходной путь для этого ограничения. Я просто продолжу и отправлю это.
Дэвид Гувея
0

Проверьте этот проект .

Это позволит вашему художнику создавать XNB практически из всего, что поддерживает конвейер содержимого XNA по умолчанию. Распространение фреймворка XNA по-прежнему необходимо, хотя вашему художнику не нужна Visual Studio.

ClassicThunder
источник
Спасибо за указатель. Глядя на код, это похоже на модификацию образца Microsoft, на которую я ссылался. Это зависит от наличия полной версии XNA Game Studio (см. ContentBuilder.cs). Почему вы думаете, что нет?
Кролт
Я не думаю, что это не так. Если вы хотите использовать конвейер контента, вам нужна полноценная игровая студия. Однако проект не позволяет вашим художникам использовать Visual Studio. Единственные другие альтернативы это переписать контентный конвейер.
ClassicThunder