2010-05-19 12 views
9

मैं एक बहुत चारों ओर देखा है और केवल तरीकों मैं एक बिटमैप से एक Texture2D बनाने के लिए मिल गया है कर रहे हैं:क्या XNA में बिटमैप ऑब्जेक्ट से Texture2D बनाने का कोई तेज़ विकल्प है?

using (MemoryStream s = new MemoryStream()) 
{ 
    bmp.Save(s, System.Drawing.Imaging.ImageFormat.Png); 
    s.Seek(0, SeekOrigin.Begin); 
    Texture2D tx = Texture2D.FromFile(device, s); 
} 

और

Texture2D tx = new Texture2D(device, bmp.Width, bmp.Height, 
         0, TextureUsage.None, SurfaceFormat.Color); 
tx.SetData<byte>(rgbValues, 0, rgbValues.Length, SetDataOptions.NoOverwrite); 

कहाँ rgbValues ​​बिटमैप के युक्त एक बाइट सरणी है 32-बिट एआरबीबी प्रारूप में पिक्सेल डेटा।

मेरा सवाल है, क्या कोई तेज दृष्टिकोण है जिसे मैं कोशिश कर सकता हूं?

मैं कस्टम प्रारूप छवियों (मानचित्र टाइल) में पढ़ सकते हैं और उन्हें Texture2D बनावट में तब्दील प्रदर्शित करने के लिए करने के लिए है जो एक नक्शा संपादक लिख रहा हूँ। संपादक का पिछला संस्करण, जो एक सी ++ कार्यान्वयन था, ने छवियों को पहले बिटमैप्स में परिवर्तित किया और फिर डायरेक्टएक्स का उपयोग करके तैयार किए गए बनावट में। मैंने यहां एक ही दृष्टिकोण का प्रयास किया है, हालांकि उपरोक्त दोनों दृष्टिकोण काफी धीमे हैं। स्मृति में लोड करने के लिए मानचित्र के लिए आवश्यक सभी बनावट पहले दृष्टिकोण ~ 250 सेकंड के लिए लेते हैं और दूसरे दृष्टिकोण के लिए ~ एक उचित स्पेक कंप्यूटर पर 110 सेकंड (तुलना के लिए, सी ++ कोड में लगभग 5 सेकंड लगते हैं)। यदि सीधे बनावट के डेटा को संपादित करने की कोई विधि है (जैसे बिटमैप क्लास की लॉकबिट विधि के साथ) तो मैं कस्टम-प्रारूप छवियों को सीधे Texture2D में परिवर्तित करने और प्रसंस्करण समय को सहेजने में सक्षम हो जाऊंगा।

किसी भी मदद की बहुत सराहना की जाएगी।

धन्यवाद

उत्तर

9

आप लॉकबिट चाहते हैं? आपको लॉकबिट मिलते हैं।

मेरी कार्यान्वयन में मैं फोन करने वाले से GraphicsDevice में पारित कर दिया तो मैं इस विधि सामान्य और स्थिर बना सकता है।

public static Texture2D GetTexture2DFromBitmap(GraphicsDevice device, Bitmap bitmap) 
{ 
    Texture2D tex = new Texture2D(device, bitmap.Width, bitmap.Height, 1, TextureUsage.None, SurfaceFormat.Color); 

    BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat); 

    int bufferSize = data.Height * data.Stride; 

    //create data buffer 
    byte[] bytes = new byte[bufferSize];  

    // copy bitmap data into buffer 
    Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); 

    // copy our buffer to the texture 
    tex.SetData(bytes); 

    // unlock the bitmap data 
    bitmap.UnlockBits(data); 

    return tex; 
} 
+1

"कैली" के बजाय "कॉलर से" नहीं होना चाहिए? इस कोड के उपयोगकर्ता के प्रयोजनों से, यह वह कार्य है जो कैली है। – drxzcl

+0

आपकी प्रतिक्रिया के लिए धन्यवाद, हालांकि मेरा मतलब है कि मैंने अपने मूल प्रश्न में कहा था कि मैंने इस दृष्टिकोण की कोशिश की है - SetData() का उपयोग कर। मैंने कुछ और विश्लेषण चलाया, और लॉकबिट्स का उपयोग करके बिटमैप्स बनाने के लिए 2.7 सेकंड लिया। जब मैंने उस कोड में जोड़ा, प्रत्येक बिटमैप जेनरेट के लिए: बनावट 2 डी टीएक्स = नया बनावट 2 डी (डिवाइस, बीएमपी। विथथ, बीएमपी.हेइट, 0, TextureUsage.None, SurfaceFormat.Color); यह 74 सेकंड के लिए आवश्यक समय ऊपर उठाया !! बस प्रत्येक बिटमैप के लिए एक खाली बनावट बनाने के लिए, और इसे भर भी नहीं। इस प्रकार का लोडिंग समय 2 डी गेम के लिए स्वीकार्य नहीं है। मुझे नहीं लगता था कि एक्सएनए धीमा होगा। :/ –

+0

@Ranieri, धन्यवाद - तय! – bufferz

3

मैंने पाया मैं जब LockBits का उपयोग कर आप वेब कैमरा छवियों को आकर्षित करने का सुझाव के रूप में .Format32bppArgb रूप PixelFormat निर्दिष्ट करने के लिए किया था।

 BitmapData bmd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 
      System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     int bufferSize = bmd.Height * bmd.Stride; 
     //create data buffer 
     byte[] bytes = new byte[bufferSize]; 
     // copy bitmap data into buffer 
     Marshal.Copy(bmd.Scan0, bytes, 0, bytes.Length); 

     // copy our buffer to the texture 
     Texture2D t2d = new Texture2D(_graphics.GraphicsDevice, bmp.Width, bmp.Height, 1, TextureUsage.None, SurfaceFormat.Color); 
     t2d.SetData<byte>(bytes); 
     // unlock the bitmap data 
     bmp.UnlockBits(bmd); 
     return t2d; 
7

वे प्रारूप bgra से XNA 4.0 में RGBA है, ताकि विधि अजीब रंग देता है बदल दिया है, लाल और नीले रंग चैनल बंद किया जाना चाहिए। यहां एक विधि है जिसे मैंने लिखा है कि सुपर फास्ट है! (लगभग 3 सेकंड में 1500x 256x256 पिक्सेल बनावट लोड करता है)।

private Texture2D GetTexture(GraphicsDevice dev, System.Drawing.Bitmap bmp) 
    { 
     int[] imgData = new int[bmp.Width * bmp.Height]; 
     Texture2D texture = new Texture2D(dev, bmp.Width, bmp.Height); 

     unsafe 
     { 
      // lock bitmap 
      System.Drawing.Imaging.BitmapData origdata = 
       bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); 

      uint* byteData = (uint*)origdata.Scan0; 

      // Switch bgra -> rgba 
      for (int i = 0; i < imgData.Length; i++) 
      { 
       byteData[i] = (byteData[i] & 0x000000ff) << 16 | (byteData[i] & 0x0000FF00) | (byteData[i] & 0x00FF0000) >> 16 | (byteData[i] & 0xFF000000);       
      }     

      // copy data 
      System.Runtime.InteropServices.Marshal.Copy(origdata.Scan0, imgData, 0, bmp.Width * bmp.Height); 

      byteData = null; 

      // unlock bitmap 
      bmp.UnlockBits(origdata); 
     } 

     texture.SetData(imgData); 

     return texture; 
    } 
+2

अच्छा! लेकिन क्या आप बिटमैप डेटा को संशोधित नहीं कर रहे हैं क्योंकि आपने इसे केवल पढ़ने के साथ बंद कर दिया है? आप इसे पहले कॉपी कर सकते हैं फिर रूपांतरण करें। या यहां तक ​​कि सरल, बस एक कदम में रूपांतरण और कॉपी करें! (Itegata [i] को बाइटडाटा [i] के बजाय असाइन करें, तो आपको प्रतिलिपि की आवश्यकता नहीं है!) – Cameron

+0

ओह, धन्यवाद, यह मेरे लिए काम करता है। –

+1

+1 यह आसान है, हालांकि (जैसा कि @ कैमरॉन ने सुझाव दिया है) यदि आपने मूल बिटमैप को नहीं बदला है तो बेहतर होगा, लेकिन इसके बजाय 'imgData' सरणी पर सीधे काम किया (आपको' असुरक्षित ' उस स्तिथि में)। – Groo

1

जब मैं पहली बार इस सवाल पढ़ा है, मुझे ग्रहण यह SetData प्रदर्शन उस सीमा था। हालांकि शीर्ष जवाब में ओपी की टिप्पणियां पढ़ते हुए, वह लॉटबड़े बनावट 2 डी के आवंटित प्रतीत होता है।

एक विकल्प के रूप में,, Texture2D के एक पूल रखने पर विचार आप आवंटित है कि जब अब जरूरत के रूप में की जरूरत है, पूल में वापस लौटें।

पहली बार प्रत्येक बनावट फ़ाइल की आवश्यकता होती है (या आपकी प्रक्रिया की शुरुआत में "प्री-लोड" में, जहां आप देरी चाहते हैं) के आधार पर, प्रत्येक फ़ाइल को byte[] सरणी में लोड करें। (एक LRU कैश में उन लोगों के byte[] सरणियों स्टोर - जब तक आप सुनिश्चित हैं कि आप उन सभी को हर समय के आसपास रखने के लिए पर्याप्त स्मृति है।) फिर जब आप उन बनावट को जरूरत है, पूल बनावट को हड़पने, (एक नई आवंटन एक, यदि कोई उचित आकार उपलब्ध नहीं है), अपने बाइट सरणी से सेटडाटा - व्हायोला, आपके पास एक बनावट है।

[मैंने एक महत्वपूर्ण डिवाइस से जुड़े एक बनावट की आवश्यकता जैसे महत्वपूर्ण विवरण छोड़े हैं - लेकिन आप पैरामीटर से किसी भी जरूरत को निर्धारित करने के तरीकों से निर्धारित कर सकते हैं। जो बिंदु मैं बना रहा हूं वह Texture2D कन्स्ट्रक्टर को कॉल को कम करना है, खासकर यदि आपके पास बहुत सारे बड़े बनावट हैं।]

यदि आप वास्तव में फैंसी प्राप्त करते हैं, और कई अलग-अलग आकार के बनावट से निपट रहे हैं, तो आप एलआरयू भी लागू कर सकते हैं पूल में कैश सिद्धांत। विशेष रूप से, अपने पूल में आयोजित "मुक्त" वस्तुओं के बाइट्स की कुल संख्या को ट्रैक करें। यदि वह कुल कुछ थ्रेसहोल्ड से अधिक है जो आप सेट करते हैं (शायद "मुक्त" ऑब्जेक्ट्स की कुल संख्या के साथ संयुक्त हो), तो अगले अनुरोध पर, अपनी अनुमति के नीचे रहने के लिए सबसे पुराना मुफ्त पूल आइटम (गलत आकार या अन्य गलत पैरामीटर) को फेंक दें "बर्बाद" कैश स्पेस की दहलीज।

Btw, आप बस सीमा पर नज़र रखने, और सभी मुक्त वस्तुओं दूर फेंक जब सीमा पार हो गई है ठीक हो सकता है। अगली बार जब आप नए बनावट का एक गुच्छा आवंटित करते हैं, तो नकारात्मकता एक क्षणिक हिचकी है - यदि आप के बारे में जानकारी है कि आपको किस आकार के आसपास रखना चाहिए, तो आप बेहतर हो सकते हैं। यदि यह पर्याप्त नहीं है, तो आपको एलआरयू की आवश्यकता है।

+0

हालांकि यह 8 साल हो गया है, मैं आपको अपने प्रश्न का उत्तर लिखने की सराहना करता हूं। मुझे लगता है कि Texture2D कन्स्ट्रक्टर को कॉल बाधा है तो आपका दृष्टिकोण वास्तव में अच्छी तरह से काम कर सकता है। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^