OutOfMemory Исключение при рисовании куба - PullRequest
7 голосов
/ 29 июля 2010

У меня есть класс, который рисует и вращает куб. каждый раз, когда я поворачиваю куб, я перезагружаю буфер новыми значениями для куба.

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

затем вызовите метод Cube.Draw в 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);
    }

примерно через пару минут я получаю исключение OutOfMemory на линии:

buffer.SetData<VertexPositionNormalTexture>(verts);

Может кто-нибудь объяснить, почему это происходит и что я могу сделать, чтобы решить эту проблему.

Ответы [ 2 ]

8 голосов
/ 30 июля 2010

Буферы вершин - это неуправляемые ресурсы. Сборщик мусора не знает , что он использует целую кучу неуправляемой памяти (и ресурсов графического процессора) за кулисами. Все, что он знает, - это небольшая часть управляемой памяти, которую использует каждый.

Я больше говорю о неуправляемых ресурсах в XNA в моем ответе на этот вопрос .

Вы можете вызвать Dispose() для каждого VertexBuffer до того, как утечку (но после завершения рисования, поскольку она все еще будет использоваться!), Чтобы освободить неуправляемые ресурсы. Это позволит избежать ошибки нехватки памяти, но все равно будет очень медленным!

Что вы действительно должны делать, так это создавать минимально необходимые буферы вершин только один раз . Идеальное место для этого - ваша функция LoadContent (а затем Dispose() их в вашей функции UnloadContent). Если у вас есть целая связка кубов, все, что вам нужно, это один буфер вершин, описывающий куб, который вы будете использовать каждый раз, когда рисуете куб.

Очевидно, что вы не хотите рисовать все свои кубы в одном месте. Это то, для чего предназначена матрица мира. Каждый раз, когда вы рисуете куб, задайте BasicEffect.World матрицу преобразования для этого куба и вызовите Apply().

(То, как вы устанавливаете WorldViewProj напрямую, тоже хорошо. Но использование хорошего API, ну, конечно, лучше.)

Если вам нужно вращение, используйте Matrix.CreateFromYawPitchRoll(yaw, pitch, roll) для создания матрицы преобразования.

Более подробно об этом ваша проблема похожа на другой вопрос, на который я ответил .

(Обратите внимание, что, если сами вершины действительно меняют каждый кадр, вы должны использовать DrawUserPrimitives. Но обратите внимание, что это все же значительно медленнее, чем включение вершинного шейдера GPU обрабатывает любые преобразования.)

0 голосов
/ 29 июля 2010

Похоже, вы создаете новый буфер вершин каждый кадр и не позволяете старому выпадать из области видимости для сборки мусора. Фактически вы делаете это для каждого из ваших кубов.

Лучшим подходом было бы просто обновить значения вершин в каждом кадре или лучше обновить преобразование куба в каждом кадре.

...