从头开始绘制大圆圈

Drawing big circles from scratch

本文关键字:绘制 从头开始      更新时间:2023-10-16

我是C 的新手,但是语言对我来说似乎还不错。作为一个学习项目,我决定制作次要的2D图形引擎。这似乎是一个艰难的项目,但是我有一个好主意。

我还没有真正开始,但是当我遇到这个问题时,我正在脑海中形成东西:在某个时候,我将不得不发挥功能来在屏幕上绘制圆圈。我现在对此的方法就是这样:

in a square with sides from (x-r) to (x+r) loop through x and y,
if at each point, the current distance sqr(x^2+y^2) is less than or equal to r
, then draw a pixel at that point.

这将起作用,如果不这样做,请不要理会我,我会弄清楚。如果X R&Y R在屏幕上。

问题在于我有时需要绘制非常大的圆圈。例如,如果我需要绘制一个半径5000的圆,则(如果像素回路计算需要循环总计10000^2次)。因此,对于2GHz的处理器,这个单个圆只能渲染2GHz/(10000^2),在占用整个核心的同时,它是〜22次/s(认为它只需一个计算每个像素,这无处不在真相)。

现在哪种方法是正确的?我想这与使用GFX进行这些简单计算有关。如果是这样,我可以将OpenGL用于C 吗?我也想了解这一点:)

我的第一个C/C 项目实际上也是图形库。我没有OpenGL或DirectX,当时正在使用DOS。我从中学到了很多东西,因为我不断地发现了在屏幕上绘制的新方法。

现代操作系统的问题在于,他们真的不允许您做我当时所做的事情。您不能只是开始直接使用硬件。坦率地说,这些天您不想再这样做了。

您仍然可以自己画所有东西。如果要放置自己的像素,请看一下SDL。这是一个C库,您可以将其包装到自己的C 对象中。它可以在不同的平台(包括Linux,Windows,Mac,...)上使用,并且内部将使用DirectX或OpenGl之类的东西。

对于实际图形,不仅要画自己的像素。那不是有效的。或至少在无法直接使用硬件的设备上...

但是出于您的目的,我认为SDL绝对是必经之路!祝您好运。

您不通过手动绘制像素来屏幕上的图形,这样疯狂就在于。

您要使用的是DirectX或OpenGL。我建议您打开Google打开,然后阅读,那里有很多值得阅读的内容。

您下载了Libs后,有很多示例项目需要查看,它们会让您入门。

此时有两种方法:有一种计算向量的数学方法,这些向量描述了一个非常数量的侧面的形状(即它看起来像一个圆圈)。或者有一种"作弊"方法,即只需用alpha通道绘制圆圈的纹理(即图片),以使其其余的纹理透明。(作弊方法更容易编码,更快地执行并产生更好的结果,尽管它的灵活性较低)。

如果您想数学上进行操作,那么这两个库都将允许您绘制线屏幕的线路,因此您需要从每行的起点和终点的视图开始,而不是单个像素。我,你想要矢量图形。

我现在不能做重量的数学,但是向量方法可能有点像这样(sudo代码):

in-param: num_of_sides, length_of_side;
float angle = 360 / num_of_sides;
float start_x = 0;
float start_y = 0;
x = startX;
y = startX;
for(int i(0); i < num_of_sides; ++i)
{
  float endX, endY;
  rotateOffsetByAngle(x, y, x + lenth_of_side, y, angle * i, endX, endY);
  drawline(x, y, endX, endY);
  x = endX;
  y = endY;
}

drawline(float startX, startY, endX, endY)
{
  //does code that draws line between the start and end coordinates;
}
rotateOffsetByAngle(float startX, startY, endX, endY, angle, &outX, &outY)
{
  //the in-parameters startX, startY and endX, endY describe a line
  //we treat this line as the offset from the starting point
  //do code that rotates this line around the point startX, startY, by the angle.
  //after this rotation is done endX and endY are now at the same
  //distance from startX and startY that they were, but rotated.
  outX = endX;
  outY = endY; //pass these new coordinates back out by reference;
}

在上面的代码中,我们绕着圆的外部移动,将每个单独的线绘制在外部1中。对于每条线,我们都有一个起点和一个偏移,然后我们按角度旋转偏移(当我们绕圆移动时,该角度会增加)。然后,我们从起点点到偏移点。在开始下一次迭代之前,我们将起点移至偏移点,因此下一行是从最后一个末端开始的。

我希望这是可以理解的。

这是绘制填充圆的一种方法。如您所见,它会慢慢地执行。

现代图形基于抽象较低级别的东西,以便可以优化。开发人员撰写drawcircle(x,y,r),图形性Libary 驱动程序可以将其一直传递到芯片,这可以填充适当的像素。

尽管您正在用C 编写,但是除非您使用图形驱动程序,否则您不会操纵最接近核心的数据。即使是您的setPixelColour级别方法和通过电线上传递的实际二进制值,也有subroutine调用层。在几乎每一层中都有检查以及其他计算和例程运行。因此,更快的图形的秘诀是减少您拨打的这些呼叫的数量。如果您可以将命令DrawCircle一直到图形芯片,请执行此操作。当它像平凡一样,不要浪费单个像素的电话。

在现代操作系统中,有很多图形处理处理像您这样的单个应用程序的请求,并将它们与窗口,合成和任何其他效果相结合。因此,您的"绘制到屏幕"的命令已经被几层介入。您要向CPU提供的是将计算卸载到图形子系统所需的最低信息。

我想说的是,如果您想学习在屏幕上绘制东西,请使用帆布和JS,因为开发周期很容易且相对毫无痛苦。如果您想学习C ,请尝试使用Project Euler,或使用现有图形库绘制内容。如果您想编写一个2D图形库,请学习DirectX和OpenGL等基础图形技术,因为它们是实际完成图形的方式。但是它们看起来很复杂,您说吗?然后,您需要先了解更多C 。它们是出于某些非常好的理由的方式,无论结果如何。进行认真的工作。但是,如果您只想以此为例,那么可以做这样的事情:首先定义用于在屏幕上绘制线段的函数:

void draw_line(int x1, int y1, int x2, int y2);

这应该相对简单地实现:只需找到最快变化的方向,并在使用整数逻辑时迭代该方向,以找出其他维度应该改变多少。即,如果x更换速度,则y = (x-x1)*(y2-y1)/(x2-x1)

然后使用此功能将圆实现为分段线元素:

void draw_circle(int x, int y, int r)
{
    double dtheta = 2*M_PI/8/r;
    int x1 = x+r, x2, y1 = y, y2;
    int n = 2*M_PI/dtheta;
    for(int i = 1; i < n; i++)
    {
        double theta = i*dtheta;
        x2 = int(x+r*cos(theta)); y2 = int(y+r*sin(theta));
        draw_line(x1, y1, x2, y2);
        x1 = x2; y1 = y2;
    }
}

这使用浮点逻辑和三角函数来确定哪些线元素最能近似圆。这是一个粗略的实施,但我认为任何想要高效的大圈子都必须做这样的事情。

如果仅允许使用整数逻辑,则可以先绘制一个低分辨率整数圆,然后将每个选定的像素细分为较小的像素,然后选择您想要的子像素,等等,等等。这将扩展为n log n,因此仍然比上面的方法慢。但是您将能够避免犯罪和cos。