如何使用 openGL 获得真正平滑的移动物体
我正在开发一个应用程序,在其中绘制一个慢慢“填充”的圆形进度指示器,在这里您可以看到 几张图片。我正在使用中间模式,并且仅通过在每个帧更新时绘制顶点来绘制此圆形形状(请参见下面的代码)。当圆圈填满白色和灰色之间的边界线时,它有点闪烁,我想知道如何使它更平滑。
这是一个具体的例子,但总的来说,我想知道即使使用非常简单的线性插值,如何获得最平滑的运动?当我看到在 iPhone 上翻页时的动作时,它是如此的极其流畅,这让我想知道如何在我的(快速)Mac 上实现这一点?
谢谢
罗克斯鲁
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;
}
I'm working on an application where I draw a circular progress indicator which slowly gets "filled", here you can see a couple of images. I'm using intermediate mode and I'm only drawing this circular shape by drawing the vertices at each frame update (see code below). When the circle fills up the border line between the white and gray is a bit flickery and I'm wondering how I can make it more smooth.
This is a concrete example, but in general I'm wondering how to get the smoothest motion even when using very simple lineair interpolation? When I look at the motion when I flip between pages on my iphone it's just so extremelly smooth which makes me wonder how I would achieve this on my (fast) mac?
Thanks
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
看看双缓冲
Take a look at Double buffering
很难猜出你在问什么——闪烁、锯齿、平滑运动或绘图伪影。查看代码后的自由想法
您假设如果
floatpart_angle = TWO_PI/resolution;
然后通过求和(angle +=part_angle
)resolution< /code> 次您将获得
TWO_PI
。不幸的是,这在浮点运算中并非如此。此外,sin(TWO_PI) cos(TWO_PI) 不一定会返回精确的0.0
和1.0
值。为了提高绘图精度,我会绘制完整的灰色圆圈,然后根据需要在其上绘制白色圆圈。这将使完整的灰色圆圈达到 100%
int parts_filled = resolution * perc;
。您可以转换百分比倒计时,以便它将使用整数类型,或者至少通过打印百分比值来测试它并检查它是否达到 100%。It's hard to guess what you are asking about - a flickery, aliasing, smooth motion or drawing artifacts. Free thoughts after looking at your code
You assume that if
float part_angle = TWO_PI/resolution;
then by summing up (angle += part_angle
)resolution
times you'll getTWO_PI
. Unfortunatelly this isn't true in floating point arithmetics. Also sin(TWO_PI) cos(TWO_PI) will not neccessarily return precise0.0
and1.0
values.To improve drawing precission I would draw full grey circle and then a white one over it as neccessary. This would bring full grey circle at 100%
int parts_filled = resolution * perc;
. You can convert your percentage countdown so that it will use integral types or at least test it by printing out percent value and check out if it ever reaches 100%.我要做的第一件事就是简单地绘制一个圆圈,并将其存储在显示列表中(您可以选择缓冲区对象,但本建议的其余部分都不依赖于此,并且您处于即时模式,所以我们将坚持最简单的改进)。画出分割的圆,在每个圆上放置与完成百分比相对应的纹理坐标。应用一个着色器,虽然很无聊,但为了完整性有一个统一的着色器;纹理坐标 <= 的三角形的完整性会被点亮。其余的保持灰色。然后,您的绘图包括设置制服和调用显示列表。快得多。
The first thing I would do would be to simply draw a single circle, and store it in a display list (you could go for buffer objects, but none of the rest of this advice depends on that, and you're in immediate mode, so we'll stick with the simplest improvement). Draw your divided up circle, putting texture coordinates on each one that corresponds to the percent completion there. Apply a shader which is mostly boring, but has a uniform for the completeness; triangles with their texture coordinates <= that completeness get lit up. The rest stay grey. Then your drawing consists of setting the uniform, and calling the display list. Much faster.