如何使用openGL获得非常流畅的移动对象

时间:2010-08-03 15:40:02

标签: c++ opengl performance smooth motion

我正在开发一个应用程序,我绘制一个循环进度指示器,慢慢地“填充”,在这里你可以看到a couple of images。我正在使用中间模式,我只是通过在每次帧更新时绘制顶点来绘制这个圆形形状(参见下面的代码)。当圆圈填满白色和灰色之间的边界线时有点闪烁,我想知道如何让它变得更加流畅。

这是一个具体的例子,但总的来说,我想知道如何使用非常简单的线性空间插值来获得最平滑的运动?当我在iphone上翻页之间看动作时,它非常流畅,让我想知道如何在我的(快速)Mac上实现这一点?

感谢
Roxlu

PhotoBoothCountdown::PhotoBoothCountdown(float fMillisDuration)
    :duration(fMillisDuration)
    ,start_time(0)
{
    setActionCommand("take_picture");
}

void PhotoBoothCountdown::update() {
    if(start_time != 0) {
        float cur = ofGetElapsedTimeMillis();
        perc = (cur-start_time)/duration;

    }
}

void PhotoBoothCountdown::draw() {
    float resolution = 150;
    int parts_filled = resolution * perc;
    int parts_unfilled = (resolution - parts_filled);
    float part_angle = TWO_PI/resolution;
    //printf("filled: %i/%i/%i\n", parts_filled, parts_unfilled, (parts_filled+parts_unfilled));
    float radius = 300.0f;
    float width = 100;
    float radius_inner = radius-width;
    float center_x = ofGetWidth()/2;
    float center_y = ofGetHeight()/2;
    float angle = 0;

    glBegin(GL_TRIANGLE_STRIP);
        glColor4f(0.2f, 0.2f, 0.2f,0.9f);   
        for(int i = 0; i <= parts_filled; ++i) {
            float cosa = cos(angle);
            float sina = sin(angle);
            glVertex2f(center_x + cosa * radius,center_y + sina * radius);
            glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
            angle += part_angle;
        }
    glEnd();
    glBegin(GL_TRIANGLE_STRIP);
        glColor4f(1.0f, 1.0f, 1.0f,0.9f);
        angle -= part_angle;
        for(int i = 0; i <= parts_unfilled; ++i) {
            float cosa = cos(angle);
            float sina = sin(angle);
            glVertex2f(center_x + cosa * radius,center_y + sina * radius);
            glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
            angle += part_angle;
        }
    glEnd();

    if(perc >= 1) { 
        printf("should fire");
        fireEvent();
        reset();
    }
}



void PhotoBoothCountdown::start() {
    start_time = ofGetElapsedTimeMillis();
    end_time = start_time + duration;
}

void PhotoBoothCountdown::reset() {
    start_time = 0;
    end_time = 0;
    perc = 0;
}

3 个答案:

答案 0 :(得分:1)

答案 1 :(得分:0)

很难猜出你在问什么 - 一个闪烁,混叠,平滑的动作或绘图工件。查看代码后的自由思考

  • 您认为如果float part_angle = TWO_PI/resolution;,那么通过总结(angle += part_angleresolution次,您将得到TWO_PI。不幸的是,在浮点算术中这不是真的。此外,sin(TWO_PI)cos(TWO_PI)不会重复返回精确的0.01.0值。

  • 为了提高绘图精度,我会绘制完整的灰色圆圈,然后在必要时绘制一个白色圆圈。这将带来100%

  • 的完整灰色圆圈
  • 对浮点数的操作可能会给您一些错误,这些错误可能会影响转换后的积分值。可能你可能永远不会通过从像int parts_filled = resolution * perc;这样的表达式计算它们来获得所有填充的部分。您可以转换您的百分比倒计时,以便它将使用整数类型或至少通过打印百分比值进行测试,并检查它是否达到100%。
  • 另外你可以
    • 使用抗锯齿使边缘更平滑
    • 提高帧率(取决于您更新绘图的方式)
    • 启用垂直同步以删除页面撕裂

答案 2 :(得分:0)

我要做的第一件事就是简单地绘制一个圆圈,然后将其存储在一个显示列表中(你可以选择缓冲区对象,但这些建议的其余部分都不依赖于那个,你在立即模式,所以我们将坚持最简单的改进)。绘制分割的圆圈,在每个圆圈上绘制纹理坐标,对应于那里的完成百分比。应用一个大多数很无聊的着色器,但是为了完整性而具有均匀性;三角形的纹理坐标&lt; =完整性被点亮。其余的保持灰色。然后你的绘图包括设置制服,并调用显示列表。快得多。