我想知道如何优化我的圆形绘制方法
it('can change email', () => {
const user = {
name: 'jane',
email: 'jane@jane.com',
password: '12345'
}
// register and login w/o UI
cy.register(user)
cy.login(user)
cy.visit('/settings')
cy.get('input[name="email"]').type('UpdatedEmail@jane.com')
cy.get('input[type="submit"]').click()
cy.getUser(user.name)
.then((dbUser) => expect(dbUser.email).to.eql('UpdatedEmail@jane.com'))
})
FillRect函数仅绘制一个四边形,因此DrawCircle函数绘制100个由cos,sin和半径移动的四边形。
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);
}
}
如何绘制不同的圆圈?
答案 0 :(得分:2)
由于您明确要求优化生成顶点坐标的方法的方法,因此我将为此提供解决方案。但是,看看一些基准测试(请参阅下面的演示链接),我不认为这确实是导致任何性能问题的原因...
您可以使用rotation matrices递归计算以(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;
}
}
Live demo & simplistic comparison benchmark
仅使用递归的缺点是您在每次迭代中都会累积微小的计算错误。如该演示所示,该错误对于100次迭代而言微不足道。
答案 1 :(得分:1)
您在评论中提到您正在使用 OpenGL 进行渲染(假设使用旧的API),因此使用单个GL_QUADS
是您的问题。在执行 OpenGL 时,需要调用圆的每个单独的“像素”。这通常比渲染本身要慢得多。有什么解决方案?
VBO
这是您最好的选择,只需创建{strong> VBO 并按住cos(a),sin(a)
单位圆点并呈现为单个glDrawArray
调用(应用变换矩阵将单位圆变换到所需位置并半径)。这应该几乎与单个GL_QUADS
调用一样快...(除非您每个圆有太多的点),但是您将失去厚度(除非将2个圆和模板组合在一起...)。在这里:
您可以找到 OpenGL 中如何使用 VAO / VBO 。另请参阅有关如何打孔(针对厚度)的信息:
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
,则至少将其转到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();
}
着色器
您甚至可以创建以圆的厚度,半径和半径(均匀)为输入中心的着色器,并通过在圆周围渲染单个QUAD bbox来使用它。然后在片段着色器内部丢弃圆圆周以外的所有片段。像这样:
实施#2 是最容易的。使用#1 进行一些工作,但如果您知道如何使用 VBO ,则不需要太多工作。 #3 也不是太复杂,但是如果您没有任何可能会带来问题的着色器经验……