2010-07-29 6 views
7

J'ai une classe qui dessine et fait pivoter un cube. Chaque fois que je fais tourner le cube, je recharge le tampon avec les nouvelles valeurs pour le cube.OutOfMemory Exception lors du dessin d'un cube

public void LoadBuffer(GraphicsDevice graphicsDevice) 
    { 
     buffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, triangles * 3, BufferUsage.None); 
     buffer.SetData<VertexPositionNormalTexture>(verts); 
     graphicsDevice.SetVertexBuffer(buffer); 
    } 

    public void Draw(GraphicsDevice graphicsDevice) 
    { 
     graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, triangles); 
    } 

puis appeler la méthode Cube.Draw dans Game.Draw

protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.White, 1f, 0); 

     basicEffect.Parameters["WorldViewProj"].SetValue(world * view * projection); 

     EffectPass pass = basicEffect.CurrentTechnique.Passes[0]; 
     if (pass != null) 
     { 
      pass.Apply(); 
      cube1.LoadBuffer(GraphicsDevice); 
      cube1.Draw(GraphicsDevice); 
      cube2.LoadBuffer(GraphicsDevice); 
      cube2.Draw(GraphicsDevice); 
      cube3.LoadBuffer(GraphicsDevice); 
      cube3.Draw(GraphicsDevice); 
     } 
     base.Draw(gameTime); 
    } 

après quelques minutes ou si je reçois une exception OutOfMemory sur la ligne:

buffer.SetData<VertexPositionNormalTexture>(verts); 

quelqu'un pourrait s'il vous plaît expliquer pourquoi cela se passe et ce que je peux faire pour le résoudre.

+0

Salut , @harryovers, avez-vous trouvé un travail autour, avec ce genre de "BUG", je me sens trop triste de choisir XNA. –

+0

@DuSijun J'ai réussi à faire marcher ça mais c'était 2.Il y a 5 ans donc je ne me souviens vraiment pas beaucoup des détails à ce sujet désolé. – harryovers

Répondre

8

Les tampons Vertex sont des ressources non managées. Le garbage collector ne sait pas qu'ils utilisent un tas de mémoire non gérée (et de ressources GPU) en coulisses. Tout ce qu'il sait, c'est le tout petit peu de mémoire gérée que chacun utilise. Je parle plus de ressources non managées dans XNA dans my answer to this question.

Vous pouvez appeler Dispose() sur chaque VertexBuffer avant de le filtrer (mais une fois le dessin terminé, car il sera toujours utilisé!), Pour libérer les ressources non gérées. Cela permettra d'éviter l'erreur de mémoire insuffisante, mais sera toujours très lent!

Ce que vous devez faire est de créer les tampons de vertex minimum nécessaires seulement une fois. L'endroit idéal pour cela est dans votre LoadContent fonction (puis Dispose() eux dans votre fonction UnloadContent). Si vous avez un tas de cubes, tout ce dont vous avez besoin est un seul tampon de vertex qui décrit un cube, que vous réutilisez chaque fois que vous dessinez un cube.

De toute évidence, vous ne voulez pas dessiner tous vos cubes au même endroit. C'est à cela que sert la matrice mondiale. Chaque fois que vous dessinez un cube, définissez BasicEffect.World sur votre matrice de transformation pour ce cube et appelez le Apply().

(La façon dont vous définissez WorldViewProj directement est ok aussi. Mais en utilisant l'API est agréable, bien plus agréable.)

Si la rotation est ce que vous voulez, utilisez Matrix.CreateFromYawPitchRoll(yaw, pitch, roll) pour créer votre matrice de transformation.

Pour plus de détails à ce sujet, votre problème est similaire à another question I have answered.

(Notez que, si les sommets eux-mêmes vraiment faire changer chaque image, vous devez utiliser DrawUserPrimitives. Mais notez que cela est encore beaucoup plus lent que de laisser le vertex shader sur le GPU gérer toutes les transformations.)

0

Il semble que vous créiez un nouveau tampon de vertex à chaque image et que vous ne permettez pas à l'ancien de tomber hors de la portée pour être collecté. En fait, vous le faites pour chacun de vos cubes.

Une meilleure approche serait de simplement mettre à jour les valeurs de vertex chaque image, ou mieux encore de mettre à jour la transformation sur le cube chaque image.

+0

Toutes les références à chaque tampon sont supprimées, donc je dirais que si le garbage collector était bon, il devrait savoir supprimer les anciens tampons non utilisés. Ce n'est pas comme si les anciens tampons étaient stockés dans une liste ou quelque chose comme ça. Ai-je tort? En tout cas, ce n'est certainement pas la bonne façon de procéder, car l'allocation et la désallocation répétées sont terriblement inefficaces, comme le fait le "nouveau VertexBuffer" à chaque appel de LoadBuffer. – Ricket

+0

@Ricket - l'allocation répétée a été la chose qui m'a frappé, et sans preuve du contraire se prête à l'idée que l'ancien tampon n'est pas libéré. – ChrisF

+0

@Ricket le GC ne connaît pas les ressources non managées sauvegardant les buffers de vertex. C'est pourquoi il pense qu'il a des tas de mémoire, quand ce n'est pas le cas. –

Questions connexes