Похоже, правильный ответ на этот вопрос - пропустить 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.
FromStream
поток памяти, содержащий 32-битное растровое изображение (сохраненное в png), как и в вашем другом примере, но этот метод не создавал предварительно умноженную текстуру. Явное предварительное умножение каждого цвета сделало свое дело, спасибо.Я думаю, что большинство команд передаст изменения xnb (ну, на самом деле, все изменения, включая xnb) на свой svn-сервер (который можно настроить бесплатно) и позволит другим (художнику и т. Д.) Обновлять свои собственные рабочие копии.
Фактически, это было бы хорошим механизмом для художника контролировать версию оригинального (pre-xnb) искусства. Он будет вносить изменения в это, вы обновляете свою рабочую копию, создаете ее (в процессе превращая ее в xnb), фиксируете ваши изменения, он обновляет свою рабочую копию вашей работы, и у всех есть все изменения. (У вас есть последняя необработанная работа, у него есть xnb (s).
Это тоже очень хорошо масштабируется.
источник
Я продолжал исследовать это и опубликую это в пользу кого-то, у кого есть тот же самый вопрос.
Похоже, правильный ответ на этот вопрос - пропустить ContentPipeline и использовать Texture2D.FromStream для загрузки текстур во время выполнения. Этот метод отлично работает на ПК и даже если будет небольшая производительность хита это то , что я могу оптимизировать когда я ближе к дате релиза.
Пока что возможность динамического изменения контента для редактора и для игры - это как раз то, что мне нужно. Как только контент заморожен, я могу оптимизировать его, вернувшись к ContentPipeline.
источник
Texture2D.FromStream
само по себе не достаточно. Причина этого в том, что, поскольку версия 4 XNA работает с предварительно умноженными альфа-текстурами, и хотя конвейер содержимого автоматически выполняет эту обработку для вас,Texture2D.FromStream
этого не происходит, поэтому вы, вероятно, столкнетесь с проблемами при рисовании спрайтов с прозрачностью. Я могу опубликовать рабочее решение, если хотите.Texture2D.FromStream
не поддерживает загрузку.BMP
файлов, в то время как конвейер контента поддерживает. Это то, что, вероятно, отбросит вас, если вы ранее использовали какие-либо.BMP
активы, а затем переключились наTexture2D.FromStream
. У меня также есть обходной путь для этого ограничения. Я просто продолжу и отправлю это.Проверьте этот проект .
Это позволит вашему художнику создавать XNB практически из всего, что поддерживает конвейер содержимого XNA по умолчанию. Распространение фреймворка XNA по-прежнему необходимо, хотя вашему художнику не нужна Visual Studio.
источник