I'm new in Monogame (OpenGL).
I want to draw 10.000+ primitives, just rectangles.
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);
}
}
I want to rotate/translate/scale each rectangle object, because each object have 3 matrices. Application is loading content creating 100*100 grid of RectangleObjects and in Draw() method I'm calling DrawRectangle() method of RectangleObject. When I try to draw 50*50, it keeps 60FPS. But if I try to draw 10.000 rectangles, application running with 15-25FPS.
The questions are:
I suspect your game is re-sending the same geometry each frame to the GPU whether the geometry was changed or not (which from what you have said should be static). Also I think you would benefit from indexed primitives for performance reasons (see below).
According to Riemer, you should call SetVertexBuffer()
prior to calling DrawIndexedPrimitives()
:
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...
e.g. (from Riemer)
device.Indices = myIndexBuffer; // <------------- NEW
device.SetVertexBuffer(myVertexBuffer);
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, //
0,
0,
vertices.Length,
0,
indices.Length / 3);
Note the use of DrawIndexedPrimitives
. I recommend you investigate that over DrawUserPrimitives
. Note also you'll need to change your code to use indices.
Don't call game.GraphicsDevice.SetVertexBuffer(vertexBuffer)
in your RectangleObject()
constructor. I can't think of a reason you should ever do any GPU alteration in such objects. Do so in your drawxxx()
methods.
With these changes you'll have the performance of what is essentially VBO vs your current, what the GPU is currently considering as a "dynamic" VAO.
You can achieve great performance by using instancing of the same geometry rather than having the same geometry multiplied out 10,000 times.