XNA Monogame 有效绘制原语

XNA Monogame effective draw primitives

我是 Monogame (OpenGL) 的新手。

我想绘制 10.000 多个图元,只是矩形。

public class RectangleObject
{
    public BasicEffect Effect { get; set; }
    public Matrix PointTranslation { get; set; }
    public Matrix PointRotation { get; set; }
    public Matrix PointScale { get; set; }
    public VertexPositionColor[] VerticesList { get; set; }
    private VertexBuffer vertexBuffer;
    private Game game;

    public RectangleObject(Game game)
    {
        this.game = game;

        Effect = new BasicEffect(game.GraphicsDevice) { VertexColorEnabled = true };
        VerticesList = new VertexPositionColor[4];

        vertexBuffer = new VertexBuffer(game.GraphicsDevice, 
                                        typeof(VertexPositionColor), 
                                        VerticesList.Length, 
                                        BufferUsage.WriteOnly);

        vertexBuffer.SetData<VertexPositionColor>(VerticesList.ToArray());
        game.GraphicsDevice.SetVertexBuffer(vertexBuffer);
    }

    public void DrawRectangle()
    {
        Effect.World = PointScale * PointRotation * PointTranslation;
        Effect.CurrentTechnique.Passes[0].Apply();
        game.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                          PrimitiveType.TriangleStrip, 
                          VerticesList, 
                          0, 
                          vertexBuffer.VertexCount / 2);
    }
}

我想rotate/translate/scale每个矩形对象,因为每个对象有3个矩阵。 应用程序正在加载创建 100*100 矩形对象网格的内容,在 Draw() 方法中我调用了 RectangleObject 的 DrawRectangle() 方法。 当我尝试绘制 50*50 时,它保持 60FPS。但是如果我尝试绘制 10.000 个矩形,应用 运行 15-25FPS。

附上dotTrace日志:

问题是:

我怀疑您的游戏每帧都将相同的几何图形重新发送到 GPU,无论几何图形是否更改(从您所说的来看应该是静态的)。此外,出于性能原因,我认为您将从 索引原语 中受益(见下文)。

根据 Riemer,您应该在调用 DrawIndexedPrimitives() 之前调用 SetVertexBuffer()

With that being done, you only need to instruct your graphics card to fetch the vertex and index data from its own memory using the DrawIndexedPrimitives method instead of the DrawUserIndexedPrimitives method. Before our call this method, we need to let your graphics card know it should read from the buffers stored in its own memory: Tell me more...

例如(来自里默)

 device.Indices = myIndexBuffer;  // <------------- NEW
 device.SetVertexBuffer(myVertexBuffer);
 device.DrawIndexedPrimitives(PrimitiveType.TriangleList,  //
                              0, 
                              0, 
                              vertices.Length, 
                              0, 
                              indices.Length / 3); 

注意 DrawIndexedPrimitives 的用法。我建议您调查 DrawUserPrimitives。另请注意,您需要更改代码以使用索引。

不要在 RectangleObject() 构造函数中调用 game.GraphicsDevice.SetVertexBuffer(vertexBuffer)。我想不出您应该对此类对象进行任何 GPU 更改的原因。在你的 drawxxx() 方法中这样做。

结论

通过这些更改,您将拥有本质上是 VBO 的性能与您当前的性能,即 GPU 当前正在考虑的 "dynamic" VAO。

您可以通过使用相同几何体的实例化而不是将相同几何体乘以 10,000 次来获得出色的性能。

告诉我更多