我有一个绘制和旋转立方体的类。每次我旋转立方体时,我都会使用新的立方体值重新加载缓冲区。
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);
}
然后在Game.Draw中调用Cube.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);
有人可以解释为什么会这样,以及我能做些什么来解决它。
答案 0 :(得分:8)
顶点缓冲区是非托管资源。垃圾收集器不知道他们在幕后使用了一大堆非托管内存(和GPU资源)。它所知道的只是每个人使用的微小的托管内存。
我在my answer to this question中详细介绍了XNA中的非托管资源。
您可以在泄漏之前调用每个Dispose()
上的VertexBuffer
(但在绘制完成后,因为它仍然在使用!),以释放非托管资源。这样可以避免内存不足错误,但仍然会很慢!
你真正应该做的是只创建一次所需的最小顶点缓冲区。执行此操作的理想位置在LoadContent
函数中(然后在Dispose()
函数中UnloadContent
)。如果你有一大堆立方体,你需要的只是一个描述立方体的顶点缓冲区,每次绘制立方体时都会重复使用。
显然,您不希望在同一个地方绘制所有立方体。这就是World矩阵的用途。每次绘制多维数据集时,请将BasicEffect.World
设置为该多维数据集的转换矩阵,然后调用Apply()
。
(您直接设置WorldViewProj
的方式也可以。但是,使用漂亮的API会更好。)
如果您想要轮换,请使用Matrix.CreateFromYawPitchRoll(yaw, pitch, roll)
创建转换矩阵。
有关此问题的详细信息,您的问题与another question I have answered类似。
(注意,如果顶点本身确实改变了每一帧,你应该使用DrawUserPrimitives
。但请注意,这仍然比让GPU上的顶点着色器处理要慢得多任何转变。)
答案 1 :(得分:0)
看起来你每帧都在创建一个新的顶点缓冲区,并且不允许旧的顶点缓冲区超出范围而被垃圾收集。事实上,你正在为每个立方体做这件事。
更好的方法是每帧更新顶点值,或者更好地更新每帧的立方体变换。