Sign in to follow this  
ironwill96

Circle not being rendered completely

Recommended Posts

I spent a long time trying to use Bresenham's algorithm to render a circle in Managed DX9 in C# and could never figure out how to fully implement the algorithm to actually draw the pixels as points into a VertexBuffer so that I could then draw them to the screen (if anyone easily knows how to do that in C# i'd love to hear it as well).

I ended up just using the sin/cos way of drawing circles, but my issue is that it only draws 359 degrees of the circle to the screen. I am using a Primitive.Linestrip to draw the points out of the VertexBuffer that they are stored in. The issue is that if I have it draw all of the points + 1 (to make it close the circle) DX seems to cull it off the screen and I end up getting nothing drawn. Does anyone know how I can close up the circle and not have it disappear? Thanks, Nathan

Share this post


Link to post
Share on other sites
OK, here is the relevant Circle-Filling code. I will post the actual drawing method below this block:


public void drawCircle(float r, float angle, int numEdges, System.Drawing.Color circleColor)
{
//calculate the increment amount for the loop counter (basically the segment of the
//circle that we are currently drawing on in the loop)
float fltCounter = 360.0f / numEdges;

//set up an array to put the vertices in temporarily..set this array's
//size to be equal to the number of "wedges" that have been calculated before hand
this.aryCircleVB = new CustomVertex.PositionColored [numEdges];

//two vars representing the location in x,y co-ord pairs of our circle points
float x, y;
int incrInt = 0;

for(float i = 0; i < 360; i += fltCounter)
{
x = (float) (r * Math.Cos(i * Math.PI / 180.0f));
y = (float) (r * Math.Sin(i * Math.PI / 180.0f));
//we now have x,y co-ords for one section of the circle, put this in an array
//which will then be set into a vertexbuffer!
this.aryCircleVB[incrInt] = new CustomVertex.PositionColored(x, y, 2.0f, circleColor.ToArgb());

//use an external int incrementer variable b/c we need an integer to index into the array
incrInt++;
}

//this.aryCircleVB[incrInt] = this.aryCircleVB[0];

//initialize our vertexbuffer before setting it
this.vbCircle = new VertexBuffer(typeof(CustomVertex.PositionColored), numEdges,
this.device, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);

//now the array is filled with or points, set this into our local VertexBuffer!
this.vbCircle.SetData(this.aryCircleVB, 0, LockFlags.None);
}
}
}



And here's the draw code:

private void unitSelectionDisplay()
{
//figure out which units are selected, and then use each unit's animateObject to draw
//the selection box around them
//do some device translation to move the circle to the right spot (same as selected object!)
this.device.Transform.World = this.animateObject.returnObjectTranslation();

//scale the circle to have the same radius as the object (for each one)
//this.device.Transform.World.Scale = Matrix.Scaling(someX, someY, someZ);

//draw the circle on any selected units here - need to do translations/scaling before displaying it
device.VertexFormat = CustomVertex.PositionColored.Format;
device.SetStreamSource(0, this.our2DDrawObject.CircleVertBuff, 0);
device.DrawPrimitives(PrimitiveType.LineStrip, 0, (this.our2DDrawObject.ArrayCircle.Length) - 1);
}



If I remove the - 1 from the 2nd set of code it will supposedly "close" the last linestrip up and make a complete circle, but the circle disappears when I do this.

Thanks,
Nathan

Share this post


Link to post
Share on other sites
To solve your problem, allocate one more element to the vertex buffer, and duplicate the first vertex into it - effectively closing the circle.

Your original code tries to draw the last line from outside the boundary of your vertex buffer, if the "-1" is taken out. This causes an access violation in the video hardware, and it protests by not drawing the figure at all.

Share this post


Link to post
Share on other sites
That still doesnt work :-( I put in this line right after the loop that fills the VertexBuffer with data (incrInt will be 360 in the case of the code above after the loop is done executing):

this.aryCircleVB[incrInt] = this.aryCircleVB[0];

I also changed the size of the array to allow this extra vertex:

this.aryCircleVB = new CustomVertex.PositionColored [numEdges + 1];

Then in my drawing code I took out the -1 modifier on the draw call and the circle still disappears. Now, in fact, I have to put -2 to get it to draw the same circle (that is missing the last line still!). Any ideas?

Nathan

Share this post


Link to post
Share on other sites
Change this code:

this.vbCircle = new VertexBuffer(typeof(CustomVertex.PositionColored), numEdges,
this.device, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);


to


this.vbCircle = new VertexBuffer(typeof(CustomVertex.PositionColored), numEdges + 1,
this.device, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);

, hence actually allocating the extra element as I suggested [smile]
Your last modification only sets the source array size - however, that wasn't the sole problem here (even though you do need the extra element there too, given your approach to copying the data to the vb).

Share this post


Link to post
Share on other sites
I'd like to elaborate the reason for the geometry to disappear:
If the DrawPrimitive needs more data than is available in your vertex buffer (in your case, the VB didn't have the space for the last vertex to close the circle), the graphics device will commit an access violation. Depending on the gfx device architecture, access violation here means that the card considers the geometry to be invalid altogether, and therefore doesn't send it to rasterizer, to avoid possible further errors.

Even though this error may not seem so critical as to "stop the factory" at first, it could potentially be very destructive. Consider that the final, unallocated element would be used in the rasterizer, even though it 's values could very well be inadvertedly set to positive or negative infinities (a distant, but real possibility). The rasterizer could time out, causing possibly an IRQ lag and a system stop error (aka BSOD) in the worst case.

To conclude: to not draw the geometry in the case of such error is just a way of the card and the driver to protect both themselves and the host machine from a catastrophic error that could "grow" from the minor error.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this