我直接从opengl教科书中复制了这个椭圆代码:
void ellipseMidpoint (int xCenter, int yCenter, int Rx, int Ry)
{
int Rx2 = Rx * Rx;
int Ry2 = Ry * Ry;
int twoRx2 = 2 * Rx2;
int twoRy2 = 2 * Ry2;
int p;
int x = 0;
int y = Ry;
int px = 0;
int py = twoRx2 * y;
//initial points in both quadrants
ellipsePlotPoints (xCenter, yCenter, x, y);
//Region 1
p = round (Ry2 - (Rx2 * Ry) + (0.25 * Rx2));
while (px < py) {
x++;
px += twoRy2;
if (p < 0)
p += Ry2 + px;
else {
y--;
py -= twoRx2;
p += Ry2 + px - py;
}
ellipsePlotPoints (xCenter, yCenter, x, y);
}
//Region 2
p = round (Ry2 * (x+0.5) * (x+0.5) + Rx2 * (y-1) * (y-1) - Rx2 * Ry2);
while (y > 0) {
y--;
py -= twoRx2;
if (p > 0)
p += Rx2 - py;
else {
x++;
px += twoRy2;
p += Rx2 - py + px;
}
ellipsePlotPoints (xCenter, yCenter, x, y);
}
}
void ellipsePlotPoints (int xCenter, int yCenter, int x, int y)
{
setPixel (xCenter + x, yCenter + y);
setPixel (xCenter - x, yCenter + y);
setPixel (xCenter + x, yCenter - y);
setPixel (xCenter - x, yCenter - y);
}
void setPixel (GLint xPos, GLint yPos)
{
glBegin (GL_POINTS);
glVertex2i(xPos, yPos);
glEnd();
}
较小的椭圆似乎很好,但较大的椭圆是尖的,两端是扁平的。
任何想法为什么?
这是当前的截图:
答案 0 :(得分:0)
我认为你遇到了溢出。我玩了你的代码。虽然我从来没有看到完全相同的&#34;柠檬&#34;从你的图片中输入形状,大小的东西肯定会崩溃,这是由于代码中使用的int
变量的范围溢出造成的。
例如,查看第一个作业之一:
int py = twoRx2 * y;
如果替换,则变为:
int py = 2 * Rx * Rx * Ry;
如果Rx
和Ry
各使用1000,则为2,000,000,000。这非常接近32位int
范围的2 ^ 31 - 1顶部。
如果要将此算法用于较大的大小,可以使用64位整数变量。根据您的系统,类型可以是long
或long long
。或者更强大,int64_t
包括<stdint.h>
。
现在,如果你想要做的就是用OpenGL绘制省略号,那么有更好的方法。如果您需要逐个像素地绘制曲线,则代码中使用的Bresenham类型算法是理想的。但是OpenGL是一个更高级别的API,它知道如何渲染比像素更复杂的基元。对于曲线,您通常会使用一组连接的线段来近似曲线。然后,OpenGL会将这些线段转换为像素。
绘制省略号的最简单方法是直接应用参数化表示。如果phi
的角度介于0和PI之间,并且使用代码中的命名,则省略号上的点为:
x = xCenter + Rx * cos(phi)
y = yCenter + Ry * sin(phi)
您可以使用符合您的精度要求的phi
增量,代码将生成一个与DIV_COUNT
近似的省略号,这些内容将如下所示:
float angInc = 2.0f * m_PI / (float)DIV_COUNT;
float ang = 0.0f;
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
ang += angInc;
float x = xCenter + Rx * cos(ang);
float y = yCenter + Ry * sin(ang);
glVertex2f(x, y);
glEnd();
如果您关心效率,可以避免计算每个点的三角函数,并应用增量旋转来计算前一个点的每个点:
float angInc = 2.0f * M_PI / (float)DIV_COUNT;
float cosInc = cos(angInc);
float sinInc = sin(angInc);
float cosAng = 1.0f;
float sinAng = 0.0f
glBegin(GL_LINE_LOOP);
for (int iDiv = 0; iDiv < DIV_COUNT; ++iDiv) {
float newCosAng = cosInc * cosAng - sinInc * sinAng;
sinAng = sinInc * cosAng + cosInc * sinAng;
cosAng = newCosAng;
float x = xCenter + Rx * cosAng;
float y = yCenter + Ry * sinAng;
glVertex2f(x, y);
glEnd();
这段代码当然只是为了说明数学,并让你开始。实际上,您应该使用当前的OpenGL渲染方法,包括顶点缓冲区等。