2010-07-29 26 views
7

tengo una clase que dibuja y rota un cubo. cada vez que giro el cubo, vuelvo a cargar el buffer con los nuevos valores para el cubo.OutOfMemory Excepción al dibujar el cubo

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); 
    } 

continuación, llamar al método Cube.Draw en 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); 
    } 

después de un par de minutos o así obtengo una excepción OutOfMemory en la línea:

buffer.SetData<VertexPositionNormalTexture>(verts); 

Podría alguien por favor explique por qué sucede esto y qué puedo hacer para resolverlo.

+0

Hola , @harryovers, encontraste una solución alternativa, con este tipo de "ERROR", me siento demasiado triste para elegir XNA. –

+0

@DuSijun hice que esto funcionara, pero fue 2.Hace 5 años, así que realmente no recuerdo mucho de los detalles sobre lo siento. – harryovers

Respuesta

8

Los buffers de vértices son recursos no administrados. El recolector de elementos no utilizados no sabe que están utilizando una gran cantidad de memoria no administrada (y recursos de GPU) detrás de las escenas. Todo lo que sabe es la pequeña cantidad de memoria administrada que cada uno usa.

Hablo más sobre recursos no administrados en XNA en my answer to this question.

Puede llamar al Dispose() en cada VertexBuffer antes de filtrarlo (pero una vez que finaliza el dibujo, ya que todavía estará en uso), para liberar los recursos no administrados. Esto evitará el error de falta de memoria, ¡pero seguirá siendo muy lento!

Lo que realmente debería hacer es crear los búferes de vértices mínimos necesarios solo una vez. El lugar ideal para hacerlo es en su función LoadContent (y luego en Dispose() en su función UnloadContent). Si tiene un montón de cubos, todo lo que necesita es un único búfer de vértices que describa un cubo, que reutilizará cada vez que dibuje un cubo.

Obviamente, no desea dibujar todos sus cubos en el mismo lugar. Para eso está la matriz mundial. Cada vez que dibuja un cubo, configure BasicEffect.World en su matriz de transformación para ese cubo y llame al Apply().

(La forma en que está configurando directamente WorldViewProj está bien también. Pero el uso de la API agradable es, así, más agradable.)

Si la rotación es lo que desea, utilice Matrix.CreateFromYawPitchRoll(yaw, pitch, roll) para crear su matriz de transformación.

Para obtener más detalles al respecto, el problema es similar al another question I have answered.

(Tenga en cuenta que, si los vértices mismos realmente cambio de cada fotograma, se debe utilizar DrawUserPrimitives. Pero tenga en cuenta que esto sigue siendo considerablemente más lento que dejar que el vertex shader en la GPU manejar cualquier transformación.)

0

Parece que está creando un nuevo búfer de vértice en cada fotograma y no permite que el anterior se salga del alcance para ser basura. De hecho, estás haciendo esto para cada uno de tus cubos.

Un mejor enfoque sería simplemente actualizar los valores de los vértices en cada cuadro o, mejor aún, actualizar la transformación en el cubo de cada cuadro.

+0

Se eliminan todas las referencias a cada búfer, por lo que yo diría que si el recolector de basura fuera bueno, debería saber eliminar los almacenamientos intermedios que ya no se usan. No es como si los buffers viejos estuvieran almacenados en una lista o algo así. ¿Me equivoco? En cualquier caso, ciertamente no es el camino a seguir, ya que la asignación y desasignación repetidas es terriblemente ineficiente, como lo accionó el "nuevo VertexBuffer" con cada llamada a LoadBuffer. – Ricket

+0

@Ricket - la asignación repetida fue lo que me llamó la atención, y sin ninguna evidencia en contrario se presta a la idea de que el antiguo buffer no se está liberando. – ChrisF

+0

@Ricket el GC no conoce los recursos no administrados que respaldan los búferes de vértices. Es por eso que cree que tiene montones de memoria, cuando no es así. –

Cuestiones relacionadas