我如何使用中点圆算法去除在 SDL 中绘制的圆中的这些间隙?
How would I remove these gaps in a circle drawn in SDL using the Midpoint Circle Algorithm?
我正在尝试创建一个相当简单的游戏,主要涉及使用 SDL2 绘制圆圈。我发现 SDL 缺少将圆圈绘制到 SDL_Renderer 的内置方法,但在搜索方法时,我发现了 helpful answer which details using the Midpoint Circle Algorithm to accomplish this. Since I wanted a filled circle, I wrote a rather simple function that just draws a lot of slightly smaller circles to give the appearance of a filled circle. Unfortunately, this resulted in circles being drawn with gaps that form a sort of 'X' pattern on the circle, as shown:
这是我的 draw_hollow_circle
函数:
void draw_hollow_circle(SDL_Renderer *renderer, int centerx, int centery, int radius)
{
// Draws a hollow circle with the given position and radius
const int diameter = (radius * 2);
int x = radius - 1;
int y = 0;
int tx = 1;
int ty = 1;
int error = tx - diameter;
while (x >= y)
{
// Each renders an octant of the circle
SDL_RenderDrawPoint(renderer, centerx + x, centery + y);
SDL_RenderDrawPoint(renderer, centerx + x, centery - y);
SDL_RenderDrawPoint(renderer, centerx - x, centery + y);
SDL_RenderDrawPoint(renderer, centerx - x, centery - y);
SDL_RenderDrawPoint(renderer, centerx + y, centery - x);
SDL_RenderDrawPoint(renderer, centerx + y, centery + x);
SDL_RenderDrawPoint(renderer, centerx - y, centery - x);
SDL_RenderDrawPoint(renderer, centerx - y, centery + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
这是我的 draw_circle
函数:
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, int r, int g, int b)
{
// Draws a filled circle with the given position, radius, and color
SDL_SetRenderDrawColor(renderer, r, g, b, SDL_ALPHA_OPAQUE);
// Draw a lot of slightly smaller hollow circles to give the impression of a filled circle
while (radius >= 0)
{
draw_hollow_circle(renderer, x, y, radius);
--radius;
}
}
现在,这很烦人,我想要一种避免这种差距并只得到一个纯红色圆圈的方法,但不幸的是我找不到任何这样做的方法。我尝试了一种不同的方法,涉及从圆心到边缘绘制许多半径,但这导致了类似的问题,尽管间隙在略有不同的地方。任何类型的答案都可以,无论是更适合实心圆的算法、我的代码的数学错误等。
这些漏洞是舍入误差造成的。每个点的精确定位将使用实数(想想浮点数),但像素坐标必须是整数,因此四舍五入。是的,出于类似原因绘制对角线时,您会得到类似的伪像。唯一可以在没有某种舍入的情况下绘制的线是水平线、垂直线、斜率 +1 的线和斜率 −1 的线。
填充圆的一种简单方法是绘制矩形而不是点。 draw_hollow_circle
中循环的每次迭代绘制八个点。前四个将是一个矩形的角,而后四个将形成另一个矩形。尝试绘制这两个矩形而不是八个点。 (您不再需要遍历半径。)
(坚持使用完全不透明的颜色,因为许多点将被多次绘制。这会干扰部分透明度。)
您可以用水平线或垂直线将圆周上的点连接成一个实心圆。这不会像@JaMit 描述的方法那样产生重叠,因此混合应该是可能的:
void fill_circle(SDL_Renderer *renderer, int centerX, int centerY, int radius) {
const int diameter = (radius * 2);
int x = (radius - 1);
int y = 0;
int tx = 1;
int ty = 1;
int error = (tx - diameter);
while (x >= y)
{
// top
SDL_RenderDrawLine(renderer, centerX - y, centerY - x, centerX + y, centerY - x);
// top-center piece
SDL_RenderDrawLine(renderer, centerX - x, centerY - y, centerX + x, centerY - y);
// lower-center piece
SDL_RenderDrawLine(renderer, centerX - x, centerY + y, centerX + x, centerY + y);
// lower piece
SDL_RenderDrawLine(renderer, centerX - y, centerY + x, centerX + y, centerY + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
您可以将画线语句一一注释掉,看看效果。
我正在尝试创建一个相当简单的游戏,主要涉及使用 SDL2 绘制圆圈。我发现 SDL 缺少将圆圈绘制到 SDL_Renderer 的内置方法,但在搜索方法时,我发现了 draw_hollow_circle
函数:
void draw_hollow_circle(SDL_Renderer *renderer, int centerx, int centery, int radius)
{
// Draws a hollow circle with the given position and radius
const int diameter = (radius * 2);
int x = radius - 1;
int y = 0;
int tx = 1;
int ty = 1;
int error = tx - diameter;
while (x >= y)
{
// Each renders an octant of the circle
SDL_RenderDrawPoint(renderer, centerx + x, centery + y);
SDL_RenderDrawPoint(renderer, centerx + x, centery - y);
SDL_RenderDrawPoint(renderer, centerx - x, centery + y);
SDL_RenderDrawPoint(renderer, centerx - x, centery - y);
SDL_RenderDrawPoint(renderer, centerx + y, centery - x);
SDL_RenderDrawPoint(renderer, centerx + y, centery + x);
SDL_RenderDrawPoint(renderer, centerx - y, centery - x);
SDL_RenderDrawPoint(renderer, centerx - y, centery + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
这是我的 draw_circle
函数:
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, int r, int g, int b)
{
// Draws a filled circle with the given position, radius, and color
SDL_SetRenderDrawColor(renderer, r, g, b, SDL_ALPHA_OPAQUE);
// Draw a lot of slightly smaller hollow circles to give the impression of a filled circle
while (radius >= 0)
{
draw_hollow_circle(renderer, x, y, radius);
--radius;
}
}
现在,这很烦人,我想要一种避免这种差距并只得到一个纯红色圆圈的方法,但不幸的是我找不到任何这样做的方法。我尝试了一种不同的方法,涉及从圆心到边缘绘制许多半径,但这导致了类似的问题,尽管间隙在略有不同的地方。任何类型的答案都可以,无论是更适合实心圆的算法、我的代码的数学错误等。
这些漏洞是舍入误差造成的。每个点的精确定位将使用实数(想想浮点数),但像素坐标必须是整数,因此四舍五入。是的,出于类似原因绘制对角线时,您会得到类似的伪像。唯一可以在没有某种舍入的情况下绘制的线是水平线、垂直线、斜率 +1 的线和斜率 −1 的线。
填充圆的一种简单方法是绘制矩形而不是点。 draw_hollow_circle
中循环的每次迭代绘制八个点。前四个将是一个矩形的角,而后四个将形成另一个矩形。尝试绘制这两个矩形而不是八个点。 (您不再需要遍历半径。)
(坚持使用完全不透明的颜色,因为许多点将被多次绘制。这会干扰部分透明度。)
您可以用水平线或垂直线将圆周上的点连接成一个实心圆。这不会像@JaMit 描述的方法那样产生重叠,因此混合应该是可能的:
void fill_circle(SDL_Renderer *renderer, int centerX, int centerY, int radius) {
const int diameter = (radius * 2);
int x = (radius - 1);
int y = 0;
int tx = 1;
int ty = 1;
int error = (tx - diameter);
while (x >= y)
{
// top
SDL_RenderDrawLine(renderer, centerX - y, centerY - x, centerX + y, centerY - x);
// top-center piece
SDL_RenderDrawLine(renderer, centerX - x, centerY - y, centerX + x, centerY - y);
// lower-center piece
SDL_RenderDrawLine(renderer, centerX - x, centerY + y, centerX + x, centerY + y);
// lower piece
SDL_RenderDrawLine(renderer, centerX - y, centerY + x, centerX + y, centerY + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
您可以将画线语句一一注释掉,看看效果。