当前位置: 首页 > 知识库问答 >
问题:

如何优化画圆?

皇甫聪
2023-03-14

我想知道如何优化我的画圆方法。在将顶点发送到opengl之前,我寻求如何尽快生成顶点。

void DrawCircle(float x, float y, float radius, Color color, float thickness)
{
    int numOfPoints = 100;
    for (float i = 0; i < numOfPoints; ++i) {
        float pi2 = 6.28318530718;
        float angle = i / numOfPoints * pi2;

        FillRect(
        cos(angle) * radius + x,
        sin(angle) * radius + y, 
        thickness, 
        thickness, 
        color);
    }
}

FillRect函数只绘制一个四边形,因此DrawCircle函数绘制100个四边形,这些四边形按cos、sin和半径移动。

FillRect(float x, float y, float w, float h, Color color)

我怎么能以不同的方式画圆呢?

共有2个答案

荆钱明
2023-03-14

在您的评论中,您提到您正在使用OpenGL进行渲染(假设旧的API),所以使用单独的GL_QUADS是您的问题。当你做OpenGL调用你的圆的每个单独的“像素”。这通常比渲染本身慢得多。有什么选择来解决这个问题?

>

  • VBO

    这是您的最佳选择,只需创建VBO,其中包含cos(a)、sin(a)单位圆点,并渲染为单个glDrawArray调用(应用变换矩阵将单位圆变换到所需的位置和半径)。这应该几乎和单个GL_QUADS调用一样快。。。(除非每个圆有太多的点)但会丢失厚度(除非组合2个圆和模具…)。在这里:

    • 完成GL GLSL VAO/VBO C示例

    您可以找到如何在OpenGL中使用VAO/VBO。另请参见如何制作孔(厚度):

    • 我有一个OpenGL Tessellated球体,我想在上面切一个圆柱形的洞

    GL\u-LINE\u-LOOP

    您可以使用粗线条而不是矩形,这样可以将glVertex调用从每“像素”4个减少到1个。它看起来像这样:

    void DrawCircle(float x, float y, float radius, Color color, float thickness)
        {
        const int numOfPoints = 100;
        const float pi2=6.28318530718; // = 2.0*M_PI
        const float da=pi2/numOfPoints;
        float a;
        glColor3f(color.r,color.g,color.b);
        glLineWidth(thickness/2.0);
        glBegin(GL_LINE_LOOP);
        for (a=0;a<pi2;a+=da) glVertex2f(cos(a)*radius + x, sin(a) * radius + y); 
        glEnd();
        glLineWidth(1.0);
        }
    

    因为我不知道如何组织颜色,所以颜色设置可能会更改。此外,glLineWidth不保证适用于任意厚度。。。

    如果你仍然想使用GL_QUADS,那么至少把它转到GL_QUAD_STRIP,这将需要一半的glVertex调用...

    void DrawCircle(float x, float y, float radius, Color color, float thickness)
        {
        const int numOfPoints = 100;
        const float pi2=6.28318530718; // = 2.0*M_PI
        const float da=pi2/numOfPoints;
        float a,r0=radius-0.5*thickness,r1=radius+0.5*thickness,c,s;
        int e;
        glColor3f(color.r,color.g,color.b);
        glBegin(GL_QUAD_STRIP);
        for (e=1,a=0.0;e;a+=da) 
          {
          if (a>=pi2) { e=0; a=pi2; }
          c=cos(a); s=sin(a);
          glVertex2f(c*r0 + x, s * r0 + y); 
          glVertex2f(c*r1 + x, s * r1 + y); 
          }
        glEnd();
        }
    

    着色器

    您甚至可以创建着色器,将圆的中心、厚度和半径作为输入(作为统一体),并通过围绕圆渲染单个四边形bbox来使用它。然后,内部碎片着色器丢弃圆周长以外的所有碎片。大概是这样的:

    • 如何在glsl上创建渐变球体

    实现#2是最简单的。使用#1需要一些工作,但如果你知道如何使用VBO,就不会太多。#3也不太复杂,但如果你没有任何着色器的经验,可能会造成问题...

  • 诸葛煜
    2023-03-14

    由于您明确要求优化生成顶点坐标的方法,我将为此提出一个解决方案。然而,看看一些基准测量(见下面的演示链接),我不相信这真的是任何性能问题的原因...

    您可以使用旋转矩阵递归地计算以(0,0)为中心的圆上的顶点:

    // Init
    X(0) = radius;
    Y(0) = 0;
    // Loop body
    X(n+1) = cos(a) * X(n) - sin(a) * Y(n);
    Y(n+1) = sin(a) * X(n) + cos(a) * Y(n);
    

    这将替换循环中的cossin计算,而只使用少量浮点乘法、加法

    void DrawCircle(float x, float y, float radius, Color color, float thickness) {
        int numOfPoints = 100;
        float pi2 = 6.28318530718;
        float fSize = numOfPoints;
        float alpha = 1 / fSize * pi2;
        // matrix coefficients
        const float cosA = cos(alpha);
        const float sinA = sin(alpha);
        // initial values
        float curX = radius;
        float curY = 0;
        for (size_t i = 0; i < numOfPoints; ++i) {
            FillRect(curX + x, curY + y, thickness, thickness, color);
            // recurrence formula
            float ncurX = cosA * curX - sinA * curY;
            curY =        sinA * curX + cosA * curY;
            curX = ncurX;
        }
    }
    

    现场演示

    使用独占递归的缺点是,每次迭代都会累积微小的计算错误。如演示所示,在100次迭代中,错误是微不足道的。

     类似资料:
    • 问题内容: 我一直在使用一个简单的动画上。但是,当观看动画时,我会遇到难以置信的震荡。我应该采取什么步骤来优化此代码? 不知道这是否重要,但是我正在使用OpenJDK 1.8.0_121版本。 任何帮助表示赞赏。 问题答案: 在与Yago进行了精彩的讨论之后,我发现问题围绕多个领域展开,很大程度上归因于Java将更新与操作系统和硬件同步的能力,有些是您可以控制的,有些是无法控制的。 受到Yago的

    • 如何清理linux不需要的软件包

    • 有时候你会遇到循环,或者递归函数,它们会花费很长的执行时间,可能是你的产品的瓶颈。在你尝试使循环变得快一点之前,花几分钟考虑是否有可能把它整个移除掉,有没有一个不同的算法?你可以在计算时做一些其他的事情吗?如果你不能找到一个方法去绕开它,你可以优化这个循环了。这是很简单的,move stuff out。最后,这不仅需要智慧而且需要理解每一种语句和表达式的开销。这里是一些建议: 删除浮点运算操作。

    • 这样一堆 if 合理吗?后面还会加判断,会更多。 再拆分的话感觉不太好,有更好的方法吗?

    • 本文向大家介绍js如何性能优化?相关面试题,主要包含被问及js如何性能优化?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 减少HTTP请求 使用内容发布网络(CDN) 添加本地缓存 压缩资源文件 将CSS样式表放在顶部,把javascript放在底部(浏览器的运行机制决定) 避免使用CSS表达式 减少DNS查询 使用外部javascript和CSS 避免重定向 图片lazyLoad  

    • 本文向大家介绍MySQL如何优化索引,包括了MySQL如何优化索引的使用技巧和注意事项,需要的朋友参考一下 1.  MySQL如何使用索引 索引用于快速查找具有特定列值的行。如果没有索引,MySQL必须从第一行开始,然后遍历整个表以找到相关的行。表越大,花费越多。如果表中有相关列的索引,MySQL可以快速确定要在数据文件中间查找的位置,而不必查看所有数据。这比顺序读取每一行要快得多。 大多数MyS