如何优化圆画?
How to optimize circle draw?
我想知道如何优化我的圆画方法。我寻求如何在将它们发送到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函数只是画一个四边形,所以画圆函数画100个四边形,这些四边形按cos,sin和半径移动。
FillRect(float x, float y, float w, float h, Color color)
我怎样才能用不同的方式画圆?
由于您明确要求优化生成顶点坐标的方法,因此我将为此提出一个解决方案。但是,查看一些基准测试测量(请参阅下面的演示链接(,我不相信这真的是任何性能问题的原因......
您可以使用旋转矩阵递归计算以 (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);
这取代了循环内的cos
和sin
计算,只有几个浮点数乘法,加法和减法,通常更快。
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 次迭代,误差微不足道。
在您的评论中,您提到您正在使用OpenGL进行渲染(假设旧API(,因此使用单个GL_QUADS
是您的问题。当你在做OpenGL时,调用你的圈子的每个单独的"像素"。这通常比渲染本身慢得多。有什么选择可以解决这个问题?
-
驻维也纳国际
这是最好的选择,只需创建包含
cos(a),sin(a)
单位圆点的VBO并呈现为单个glDrawArray
调用(应用变换矩阵将单位圆转换为所需的位置和半径(。这应该几乎和单个GL_QUADS
呼叫一样快......(除非你每个圆圈得到太多点(,但你会失去厚度(除非组合 2 个圆圈和模板......这里:- 完整的GL+GLSL+VAO/VBO C++示例
您可以找到如何在OpenGL中使用VAO/VBO。另请参阅有关如何打孔(厚度(的信息:
- 我有一个OpenGL镶嵌球体,我想在上面切一个圆柱形孔
-
GL_LINE_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); }
粗略的,因为我不知道
color
是如何组织的,颜色设置可能会改变。此外,glLineWidth
也不能保证适用于任意厚度...如果您仍然想使用
GL_QUADS
那么至少将其转换为需要一半glVertex
调用的GL_QUAD_STRIP
...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(); }
-
着色
您甚至可以创建着色器,将圆的输入中心,厚度和半径(作为制服(作为输入中心,并通过在圆周围渲染单个QUAD框来使用它。 然后在片段着色器内部丢弃圆周之外的所有片段。像这样:
- 如何在 glsl 上制作梯度球体?
实现#2是最简单的。 使用#1需要一些工作,但如果您知道如何使用VBO,则不会太多。#3也不太复杂,但如果您没有任何着色器经验,可能会造成问题......
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 线性优化目标函数中的绝对值
- GCC 会优化内联访问器吗?
- gcc 如何优化此循环?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 为什么我的程序在 O0 和 O2 的优化级别返回不同的结果
- 如何使用android ndk(速度优化)优化本地代码
- 优化器:优化内联汇编