NickMcCrea

Hi all,

Standard preamble, new to this, having a go at c# and XNA for the first time, having a blast, absolutely sterling job by the devs, etc.

I'm playing around, drawing primitives and the like. Currently, I've got a little bit of code that I use to draw a grid on the screen. Pretty simple. A Line class, and a LineManager class. Now, it works, but it's obviously horrendously inefficient. It's like an idiots first day at coding school, I know. I've got objects re-instantiated inside loops and all sorts.

So after compilation I see my grid, all well and good, but because of the horrendous inefficiency I presume I'm falling afoul of the GC, getting a regular stutter every second or so.

The problem, it seems to me, is the createLine() called in the Draw() method, as I'm creating a new vertex buffer, setting the data and making a new vertex declaration for every line in my line list. Now, that was the most obvious way to do it (to me), and now I'm looking for the right way.

The generic question is, when you want to draw multiple instances of the same type of primitive, how do you go about it without creating whole new vertexbuffers etc in each draw loop Code below...


class Lines
{
public Vector3 leftpoint, rightpoint;


public Lines(float x, float y, float z, float x2, float y2, float z2)
{
this.leftpoint = new Vector3(x,y,z);
this.rightpoint = new Vector3(x2,y2,z2);
}

}


class LineManager
{

VertexDeclaration vdec2;
VertexBuffer vbuff2;
GraphicsDeviceManager graphics;
BasicEffect effect;
VertexPositionColor[] vertices2 = new VertexPositionColor[2];



public void Init(GraphicsDeviceManager graphics, BasicEffect effect)
{
this.graphics = graphics;
this.effect = effect;

}

private void createLine(Lines line)
{

vertices2[0] = new VertexPositionColor(line.leftpoint, Color.White);
vertices2[1] = new VertexPositionColor(line.rightpoint, Color.White);


vbuff2 = new VertexBuffer(graphics.GraphicsDevice,
VertexPositionColor.SizeInBytes * vertices2.Length, ResourceUsage.None,
ResourceManagementMode.Automatic);

vbuff2.SetData<VertexPositionColor>(vertices2);

vdec2 = new VertexDeclaration(graphics.GraphicsDevice,
VertexPositionColor.VertexElements);

}



public void Draw(List<Lines> linelist)
{
foreach (Lines line in linelist)
{
createLine(line);
graphics.GraphicsDevice.VertexDeclaration = vdec2;
graphics.GraphicsDevice.Vertices[0].SetSource(vbuff2, 0, VertexPositionColor.SizeInBytes);
graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
graphics.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, 1);
}

}

}


Re: XNA Game Studio Express Vertex Buffers, draw methods and associated nonsense...

Brandon Bloom

You really want to allocate a lot less vertex buffers and perform a lot less draw calls. For dynamic data, you can use GraphicsDevice.DrawUserPrimatives

VertexPositionColor[] verts = new VertexPositionColor[MaxLines * 2];
VertexDeclaration vertDecl;

public void Init(GraphicsDeviceManager graphics, BasicEffect effect)
{
this.graphics = graphics;
this.effect = effect;

vertDecl = new VertexDeclaration(graphics.GraphicsDevice,
VertexPositionColor.VertexElements);
}

public void Draw(List<Line> lines)
{
for (int i = 0; i < lines.Count; i++)
{
Line line = lines[i ];
verts[i * 2] = new VertexPositionColor(line.Begin, line.Color);
verts[i * 2 + 1] = new VertexPositioNColor(line.End, line.Color);
}
graphics.GraphicsDevice.VertexDeclaration = vertDecl;
graphics.GraphicsDevice.DrawUserPrimatives(verts, PrimativeType.LineList, 0, lines.Count);
}





Re: XNA Game Studio Express Vertex Buffers, draw methods and associated nonsense...

manders

Or build up a big array in Draw containing vertices for all your lines, and submit them all at once. This should help even if you're using DrawUserPrimitives, and especially if you're using vertex buffers. You could make a vertex buffer with enough space for 1000 lines, and fill in data for as many as you need, and draw them all in one shot.

Or if you want to get fancy, you could transform the lines in the shader...then you're just passing different shader constants per line, instead of new vertex data. That's the approach I use in my thick line code (http://blogs.msdn.com/manders/archive/2007/01/07/lines-2d-thick-rounded-line-segments-for-xna-programs.aspx), but it ends up making a lot of little calls to Draw. Seems pretty fast anyway.

-Mike





Re: XNA Game Studio Express Vertex Buffers, draw methods and associated nonsense...

NickMcCrea

Thanks for the replies, both of you. So, as for the generic case, what's a nice rule of thumb for when you should be creating vertex buffers etc, and what for Obviously they should never be created in each draw loop, as I was originally doing.

I'm trying to look at as many different examples of code as possible to get a feel for how people draw their primitives. It's helping, but....sloooowly :)




Re: XNA Game Studio Express Vertex Buffers, draw methods and associated nonsense...

Brandon Bloom

A nice rule of thumb is one VB/IB per "object" and only as many draw calls per object as there are different effects in use.

Obviously you can violate this rule a bunch and the 360 is powerful enough that any game a beginner (or even many experts) could fathom creating probably won't feel any pain from it.

Why don't you try .NET Reflector and simply look at how Model, ModelMesh, ModelMeshPart work (for static geometry) or how SpriteBatch works (for dynamic geometry). Probably great starting points, but that's how I learn best, so don't quote me on that :-P