用OpenGL绘制椭圆或圆时,应使用多少个顶点? [英] When drawing an ellipse or circle with OpenGL, how many vertices should we use?

查看:224
本文介绍了用OpenGL绘制椭圆或圆时,应使用多少个顶点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们是否应该盲目使用360个顶点? 720似乎工作得更好,但是我们在哪里停下来?

解决方案

这取决于您可以容忍的误差(即视觉质量)和圆的大小(椭圆).更大的圈子将需要更多积分才能达到相同的质量.只需一点数学,就可以准确计算出给定错误所需的点数.

如果考虑由一系列线段表示的圆,则这些线段的端点正好位于该圆上(忽略像素网格).实圆与线段表示之间的最大偏差出现在每个线段的中心,并且所有线段的误差相同.

从x轴的逆时针方向看第一段,它的两个端点是:

A = (r, 0)
B = (r . cos(th), r . sin(th))

其中,r是圆的半径,th是每个线段覆盖的角度(例如,如果我们有720个点,则每个线段覆盖0.5度,因此th将为0.5度). /p>

此线段的中点位于

M = A + (B - A) / 2
  = (r, 0) + (r (cos(th) - 1) / 2, r . sin(th) / 2)
  = (r / 2) . (1 + cos(th), sin(th))

并且从原点到点的距离是

l = (r / 2) . sqrt((1 + cos(th))^2 + (sin(th))^2)
  = (r / 2) . sqrt(2) . sqrt(1 + cos(th))

如果我们的线段表示形式是完美的,则该长度应等于半径(线段的中点应落在圆上).通常会出现一些错误,并且该点会比半径稍小.错误是

e = r - l
  = r . (1 - sqrt(2) . sqrt(1 + cos(th)) / 2)

进行重新排列,因此我们在er

的基础上得到了th

2 . e / r = 2 - sqrt(2) . sqrt(1 + cos(th))
sqrt(2) . sqrt(1 + cos(th)) = 2 . (1 - e / r)
1 + cos(th) = 2 . (1 - e / r)^2

th = arccos(2 . (1 - e / r)^2 - 1)

这使我们能够计算出每个点之间为达到特定误差而可以拥有的最大角度.例如,假设我们要绘制一个半径为100像素的圆,并且我们希望最大误差为0.5像素.我们可以计算

th = arccos(2 . (1 - 0.5 / 100)^2 - 1))
   = 11.46 degrees

这对应于ceil(360 / 11.46) = 32点.因此,如果我们使用32个点绘制半径为100的圆,则最坏的像素将偏离不到一半,这意味着我们绘制的每个像素都将位于正确的位置(忽略锯齿).

也可以对椭圆进行这种分析,但本着所有好的数学精神,留给读者练习;)(唯一的区别是确定最大误差发生在哪里).

Should we just blindly use 360 vertices? 720 seems to work better, but where do we stop?

解决方案

It depends on how much error you can tolerate (i.e. the visual quality) and the size of the circle (ellipse). A bigger circle will need more points to achieve the same quality. You can work out exactly how many points you need for a given error with a bit of maths.

If you consider the circle represented by a series of line segments, the end points of the line segments lie exactly on the circle (ignoring the pixel grid). The biggest deviation between the real circle and our line segment representation occurs in the center of each line segment, and this error is the same for all of the line segments.

Looking at the first segment from the x-axis going anti-clockwise, its two endpoints are:

A = (r, 0)
B = (r . cos(th), r . sin(th))

where r is the radius of the circle and th is the angle covered by each line segment (e.g. if we have 720 points then each line segment covers 0.5 degree so th would be 0.5 degrees).

The midpoint of this line segment is at

M = A + (B - A) / 2
  = (r, 0) + (r (cos(th) - 1) / 2, r . sin(th) / 2)
  = (r / 2) . (1 + cos(th), sin(th))

and the distance from the origin to the point is

l = (r / 2) . sqrt((1 + cos(th))^2 + (sin(th))^2)
  = (r / 2) . sqrt(2) . sqrt(1 + cos(th))

If our line segment representation were perfect then this length should be equal to the radius (the midpoint of the line segment should fall on the circle). Normally there'll be some error and this point will be slightly less than the radius. The error is

e = r - l
  = r . (1 - sqrt(2) . sqrt(1 + cos(th)) / 2)

Rearranging so we have th in terms of e and r

2 . e / r = 2 - sqrt(2) . sqrt(1 + cos(th))
sqrt(2) . sqrt(1 + cos(th)) = 2 . (1 - e / r)
1 + cos(th) = 2 . (1 - e / r)^2

th = arccos(2 . (1 - e / r)^2 - 1)

This lets us calculate the maximum angle we can have between each point to achieve a certain error. For example, say we're drawing a circle with a radius of 100 pixels and we want a maximum error of 0.5 pixels. We can calculate

th = arccos(2 . (1 - 0.5 / 100)^2 - 1))
   = 11.46 degrees

This corresponds to ceil(360 / 11.46) = 32 points. So if we draw a circle of radius 100 using 32 points our worst pixel will be off by less than a half which should mean every pixel we draw will be in the correct place (ignoring aliasing).

This kind of analysis can be performed for ellipses too, but in the spirit of all good maths that is left as an exercise for the reader ;) (the only difference is determining where the maximum error occurs).

这篇关于用OpenGL绘制椭圆或圆时,应使用多少个顶点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆