2011-01-29 18 views
6

Próbuję rysować na ekranie piksel po pikselu za pomocą XNA, ale mam problemy z zasobami. Sądziłem, że najlepszym sposobem jest posiadanie 1 tekstury, która aktualizuje każdą klatkę, ale mam problem z jej aktualizacją. Oto co mam do tej pory, tylko jako test:Jak narysować 2D piksel po pikselu w XNA?

Texture2D canvas; 
Rectangle tracedSize; 
UInt32[] pixels; 

protected override void Initialize() 
    { 
     tracedSize = GraphicsDevice.PresentationParameters.Bounds; 
     canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color); 
     pixels = new UInt32[tracedSize.Width * tracedSize.Height];    

     base.Initialize(); 
    } 

protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(Color.CornflowerBlue); 

     pixels[100] = 0xFF00FF00; 
     canvas.SetData<UInt32>(pixels, 0, tracedSize.Width * tracedSize.Height); 

     spriteBatch.Begin(); 
     spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White); 
     spriteBatch.End(); 

     base.Draw(gameTime); 
    } 

Kiedy Draw() jest wywoływana po raz drugi pojawia się następujący błąd:.

„Operacja została przerwana, nie może zmodyfikuj zasób, który został ustawiony na urządzeniu lub po jego użyciu w nawiasie klamrowym. "

Jeśli spróbuję utworzyć nowy Texture2D w Draw(), szybko wystąpi błąd braku pamięci. Dotyczy to systemu Windows Phone. Wygląda na to, że próbuję zrobić to w niewłaściwy sposób, jakie mam inne opcje, aby to zadziałało?

+0

Nie znałem odpowiedzi, więc szukałem w Google "tekstur proceduralnych xna" (co tak się nazywa). Wydaje się, że nie ma prostego, wbudowanego sposobu, aby to zrobić. Istnieją co najmniej trzy wspólne sugestie (buforowanie, polecenia tekstur GPU, robienie tego w module cieniującym). Ten ostatni jest oczywiście optymalny, ale wymaga wiedzy o programowaniu shaderów. Możesz wykonać to samo wyszukiwanie i przejrzeć, co tam jest. – Tergiver

Odpowiedz

5

Spróbuj ustawić GraphicsDevice.Textures[0] = null przed wywołaniem SetData. W zależności od pożądanego efektu może być bardziej wydajna metoda, możesz także rozważyć Silverlights WriteableBitmap.

Edit: Jest to kod I przetestowane w emulatorze:

Texture2D canvas; 
Rectangle tracedSize; 
UInt32[] pixels; 

protected override void Initialize() 
{ 
    tracedSize = GraphicsDevice.PresentationParameters.Bounds; 
    canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color); 
    pixels = new UInt32[tracedSize.Width * tracedSize.Height]; 

    base.Initialize(); 
} 
Random rnd = new Random(); 
protected override void Draw(GameTime gameTime) 
{ 
    GraphicsDevice.Clear(Color.CornflowerBlue); 

    GraphicsDevice.Textures[0] = null; 
    pixels[rnd.Next(pixels.Length)] = 0xFF00FF00; 
    canvas.SetData<UInt32>(pixels, 0, tracedSize.Width * tracedSize.Height); 

    spriteBatch.Begin(); 
    spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White); 
    spriteBatch.End(); 

    base.Draw(gameTime); 
} 
+0

GraphicsDevice.Textures [0] = null nie działa. – Curyous

+0

Dziękuję bardzo, mam to do pracy ze swojego przykładu. Myślę, że za pierwszym razem, gdy próbowałem, mogłem być nowością w Texture2D w Draw(). – Curyous

3

Zasadniczo trzeba zrobić, gdyż pyta wyjątkiem:

aby zapewnić, że struktura nie jest ustawiona na grafikę urządzenie, umieścić to w końcu Draw:

GraphicsDevice.Textures[0] = null; 

, aby zapewnić, że nie czerpią wewnątrz wspornika kafli, nie używaj SetData wewnątrz z Draw w ogóle. Przenieś wywołanie na numer SetData do Update. Informacje


Bonus: Twój out-of-memory jest błąd, ponieważ nie jesteś zwalniając niezarządzanych zasobów, które Texture2D przydziela (garbage collector nie może ich torze, więc nie wiem, jesteś na wyczerpaniu pamięciowy). Musisz zadzwonić pod numer Dispose na fakturze. Jednak tworzenie nowej tekstury w każdej klatce to i tak zły pomysł (nie ma możliwości uniknięcia problemów z wydajnością i fragmentacją pamięci, które powoduje).