Bunun doğru cevabı ContentPipeline'ı atlamak ve dokuları çalışma zamanında yüklemek için Texture2D.FromStream kullanmaktır. Bu yöntem bir PC'de iyi çalışıyor ve küçük bir performans isabeti olsa da, çıkış tarihine yaklaştıktan sonra optimize edebileceğim bir şey. Şimdilik, hem editör hem de oyun için içeriği dinamik olarak değiştirme yeteneğine sahip olmak tam olarak ihtiyacım olan şey. İçerik donduğunda, bunu ContentPipeline'a giderek optimize edebilirim.
Bu rotayı seçtiğiniz için sizi sadece Texture2D.FromStream
iki nedenden dolayı kullanmak kadar basit olmadığı konusunda uyarmalıyım :
Sorun # 1 - Önceden çarpılmış alfa desteğinin olmaması
XNA4 artık varsayılan olarak renkler ile önceden çarpılmış alfa formatında dokular işliyor. İçerik kanalından bir doku yüklediğinizde, bu işlem sizin için otomatik olarak yapılır. Ne yazık ki Texture2D.FromStream
aynı şeyi yapmaz, bu nedenle bir miktar şeffaflık gerektiren dokular yanlış yüklenir ve işlenir. Aşağıda sorunu göstermek için bir ekran görüntüsü verilmiştir:
Bu yüzden doğru sonuçları elde etmek için işlemi kendiniz yapmanız gerekir. Göstereceğim yöntem, işlemi yapmak için GPU'yu kullanır, bu yüzden oldukça hızlıdır. Bu harika makaleye dayanıyordu . Tabii ki SpriteBatch
eski NonPremultiplyAlpha modunda da oluşturma talimatı verebilirsiniz ama bunu gerçekten tavsiye etmiyorum.
Sorun # 2 - Desteklenmeyen biçimler
İçerik ardışık düzeninden daha fazla format desteklenir Texture2D.FromStream
. Özellikle, Texture2D.FromStream
yalnızca png, jpg ve gif'i destekler. Öte yandan, içerik boru hattı bmp, dds, dib, hdr, jpg, pfm, png, ppm ve tga'yı destekler. Üzerinden usuported bir format yüklemeye çalışırsanız, ek bilgilerle Texture2D.FromStream
bir alırsınız InvalidOperationException
.
Motorumda gerçekten bmp desteğine ihtiyacım vardı, bu nedenle bu durumda iyi çalışıyor gibi görünen bir geçici çözüm buldum. Diğer formatlardan hiçbirini bilmiyorum. Benim yöntemim ile yakalamak System.Drawing
, projenize derleme bir referans eklemeniz gerektiğidir , çünkü Image.FromStream
daha fazla formatı destekleyen GDI'ları kullanır Texture2D.FromStream
.
Eğer bmp'yi desteklemeyi umursamıyorsanız, çözümümün bu kısmını kolayca bırakabilir ve sadece önceden çoğaltılmış alfa işlemini yapabilirsiniz.
Çözüm - Basit Sürüm (Daha Yavaş)
Her şeyden önce, bmp'leri desteklemeyi umursamıyorsanız en basit çözüm. Bu örnekte, işleme aşaması tamamen CPU üzerinde yapılır. Aşağıda göstereceğim alternatiften biraz daha yavaş (her iki çözümü de kıyasladım) ama anlaşılması daha kolay:
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;
}
Eğer bmp'leri önemsiyorsanız, yapmanız gereken şey önce görüntüyü GDI ile yüklemek ve daha sonra onu geçmeden önce dahili olarak PNG'ye dönüştürmektir Texture2D.FromStream
. İşte bunu yapan kod:
// 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);
}
}
Çözüm - Karmaşık Sürüm (Daha Hızlı)
Son olarak, projelerimde kullandığım yaklaşım, işlem yapmak için GPU'yu kullanmaktır. Bu yöntemde bir oluşturma hedefi oluşturmanız, bazı karışım durumlarını doğru şekilde ayarlamanız ve görüntüyü bir SpriteBatch ile iki kez çizmeniz gerekir. Sonunda tüm RenderTarget2D üzerinden gidiyorum ve içeriği ayrı bir Texture2D nesnesine klonluyorum çünkü RenderTarget2D uçucudur ve backbuffer boyutunu değiştirmek gibi şeylerden hayatta kalamaz, böylece bir kopya yapmak daha güvenlidir.
Komik olan şey, tüm bunlarla bile, testlerimde bu yaklaşımın CPU yaklaşımından yaklaşık 3 kat daha hızlı gerçekleşmesidir. Bu yüzden, her bir pikselin üzerinden geçip rengi kendiniz hesaplamaktan kesinlikle daha hızlıdır. Kod biraz uzun, bu yüzden bir çöp kutusuna yerleştirilir:
http://pastie.org/3651642
Bu sınıfı projenize eklemeniz ve aşağıdaki kadar basit bir şekilde kullanmanız yeterlidir:
TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");
Not: TextureLoader
Tüm oyun için sadece bir örnek oluşturmanız gerekir . Ayrıca BMP düzeltmesini kullanıyorum, ancak bir demet performansa ihtiyacınız yoksa veya sadece needsBmp
parametreyi yanlış olarak bırakırsanız çıkarabilirsiniz .