इसका सही उत्तर की तरह लगता है कि ContentPipeline को छोड़ दें और Texture2D.FromStream का उपयोग करके रनटाइम पर बनावट को लोड करें। यह विधि एक पीसी में ठीक काम करती है और भले ही एक छोटा प्रदर्शन होगा हिट यह कुछ ऐसा है जिसे मैं रिलीज की तारीख के करीब होने पर अनुकूलित कर सकता हूं। अभी के लिए, संपादक और खेल दोनों के लिए सामग्री को गतिशील रूप से संशोधित करने की क्षमता होना वही है जिसकी मुझे आवश्यकता है। एक बार सामग्री जमी होने के बाद मैं इसे वापस ContentPipeline पर जाकर ऑप्टिमाइज़ कर सकता हूं।
चूंकि आपने इस मार्ग को चुना है, इसलिए मुझे आपको चेतावनी देनी चाहिए कि यह वास्तव में उतना सरल नहीं है जितना कि केवल Texture2D.FromStream
दो कारणों से उपयोग करना:
समस्या # 1 - पूर्व-गुणा अल्फा समर्थन का अभाव
XNA4 अब डिफ़ॉल्ट रूप से प्रीमियर अल्फा प्रारूप में रंगों के साथ बनावट को संभालता है। जब आप सामग्री पाइपलाइन के माध्यम से एक बनावट को लोड करते हैं, तो यह प्रसंस्करण आपके लिए स्वचालित रूप से किया जाता है। दुर्भाग्य से Texture2D.FromStream
एक ही काम नहीं करता है, इसलिए किसी भी बनावट को पारदर्शिता की कुछ डिग्री की आवश्यकता होती है जिसे गलत तरीके से लोड और प्रस्तुत किया जाएगा। समस्या का वर्णन करने के लिए नीचे एक स्क्रीनशॉट है:
तो सही परिणाम प्राप्त करने के लिए, आपको स्वयं प्रसंस्करण करने की आवश्यकता है। जिस विधि को मैं दिखाऊंगा वह प्रसंस्करण का काम करने के लिए GPU का उपयोग करता है इसलिए यह बहुत तेज़ है। यह इस महान लेख पर आधारित था । बेशक आप भी SpriteBatch
पुराने NonPremultiplyAlpha मोड में प्रस्तुत करने का निर्देश दे सकते हैं, लेकिन मैं वास्तव में ऐसा करने की सलाह नहीं देता।
समस्या # 2 - असमर्थित प्रारूप
सामग्री पाइपलाइन की तुलना में अधिक स्वरूपों का समर्थन करती है Texture2D.FromStream
। विशेष रूप से, Texture2D.FromStream
केवल png, jpg और gif का समर्थन करता है। दूसरी ओर, सामग्री पाइपलाइन bmp, dds, dib, hdr, jpg, pfm, png, ppm और tga का समर्थन करती है। यदि आप एक अनुपलब्ध प्रारूप को लोड करने का प्रयास करते हैं, Texture2D.FromStream
तो आपको InvalidOperationException
थोड़ी अतिरिक्त जानकारी मिलेगी ।
मुझे वास्तव में अपने इंजन पर bmp समर्थन की आवश्यकता थी इसलिए उस विशेष मामले के लिए मुझे एक वर्कअराउंड मिला जो ठीक काम करने लगता है। हालांकि मैं किसी भी अन्य प्रारूप के बारे में नहीं जानता। मेरी विधि के साथ पकड़ यह है कि आपको System.Drawing
अपनी परियोजना के लिए विधानसभा में एक संदर्भ जोड़ने की आवश्यकता है , क्योंकि यह जीडीआई का उपयोग Image.FromStream
करता है जो कि अन्य प्रारूपों की तुलना में समर्थन करता है Texture2D.FromStream
।
यदि आप bmp के समर्थन के बारे में परवाह नहीं करते हैं, तो आप आसानी से मेरे समाधान के उस हिस्से को छोड़ सकते हैं और सिर्फ पूर्व-गुणा अल्फा प्रसंस्करण कर सकते हैं।
समाधान - सरल संस्करण (धीमा)
सबसे पहले, यहाँ सबसे आसान समाधान है यदि आप bmps का समर्थन करने के बारे में परवाह नहीं करते हैं। इस उदाहरण में प्रसंस्करण चरण पूरी तरह से सीपीयू पर किया जाता है। यह नीचे दिए गए विकल्प की तुलना में थोड़ा धीमा है (मैंने दोनों समाधानों को बेंचमार्क किया) लेकिन समझने में आसान:
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);
}
}
समाधान - जटिल संस्करण (तेज़)
अंत में, मैं अपनी परियोजनाओं पर उपयोग होने वाला दृष्टिकोण इसके बजाय प्रसंस्करण करने के लिए GPU का उपयोग करना चाहता हूं। इस पद्धति में आपको एक रेंडर टारगेट बनाने की जरूरत है, कुछ मिश्रण राज्यों को ठीक से सेट करें, और एक स्प्राइटबैच के साथ दो बार छवि बनाएं। अंत में मैं पूरे RenderTarget2D पर जाता हूं और सामग्रियों को एक अलग Texture2D ऑब्जेक्ट में क्लोन करता हूं क्योंकि RenderTarget2D अस्थिर है और बैकबफ़र के आकार को बदलने जैसी चीज़ों से बचेगा नहीं, इसलिए इसे कॉपी बनाने के लिए सुरक्षित है।
मजेदार बात यह है कि इन सबके साथ भी, मेरे परीक्षणों में यह दृष्टिकोण सीपीयू दृष्टिकोण की तुलना में लगभग 3 गुना तेज है। तो यह प्रत्येक पिक्सेल पर जाने और रंग की गणना करने की तुलना में निश्चित रूप से तेज़ है। कोड थोड़ा लंबा है इसलिए मैंने इसे पास्टबिन में रखा:
http://pastie.org/3651642
बस उस वर्ग को अपनी परियोजना में जोड़ें, और इसे सरल रूप में प्रयोग करें:
TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");
नोट: आपको केवल TextureLoader
पूरे गेम के लिए एक उदाहरण बनाने की आवश्यकता है । इसके अलावा, मैं बीएमपी फिक्स का उपयोग कर रहा हूं, लेकिन आप इसे बाहर निकाल सकते हैं यदि आपको ज़रूरत नहीं है और प्रदर्शन का एक गुच्छा प्राप्त करें, या बस needsBmp
पैरामीटर को गलत के रूप में छोड़ दें ।