如何在主循环之外渲染OpenGL ES对象?

时间:2014-04-05 19:43:05

标签: ios opengl-es nsthread glkit

在我使用GLKit创建的应用程序中,我有一个滑块拼图,用户点击与空拼贴相邻的拼贴,并且拼贴滑动到新位置。为了减少我必须执行单个任务的方法数量,我决定尝试在一个循环中处理整个滑动动画。

- (void)slideSelectedTile
{
    while (!self.selectedTile.hasFinishedMoving)
    {
        [self.selectedTile moveByVector:self.tileDisplacement];
        [self render];
        [NSThread sleepForTimeInterval:.1];
    }
}

问题是渲染调用在此循环内部不起作用。只有在整个循环结束并且游戏到达下一个glkViewDrawInRect调用时才会呈现图块,其中我也调用render,其当然包含用于呈现每个图块的代码。

我已经检查过当前线程是我在循环中的主线程,并且我可以手动调用render而不需要它在任何类型的循环中并且它可以工作。我在这里做错了什么?

1 个答案:

答案 0 :(得分:1)

你在这里做错了是你错过了整个概念。您的while循环将阻止您在屏幕上绘制和显示的线程。虽然缓冲区重新绘制了N次,但您的视图却没有。

一些快速修复可能是在render方法上调用主线程上的执行选择器(并等待它完成)。这样你甚至可能会失去睡眠因素。另一种方法是创建另一个动画师线程,在该线程上将调用slideSelectedTile,但同样必须在主线程上调用render

在任何情况下,如果没有做出漂亮的代码设计,您将在以后遇到一些问题。您应该做的是让对象存储源位置,目标位置和当前位置。它应该实现一些move方法,用插值计算当前位置:线性插值将是source + (target-source)*(currentTime/animationTime)。在大多数情况下,currentTimeanimationTime实际上可能是帧数,因为我希望动画在6帧中完成animationTime为6而currentTime迭代[ 0,6]并在currentTime==animationTime时完成动画。因此,最后您可以调用类似animateTo:(CGPoint)location in:(NSInteger)frameCount的内容,将currentTime设置为零,将animationTime设置为frameCount,将source设置为当前位置,target } location

此时的问题是调用move方法以及当前位置的内容:当前位置必须在render方法的主线程上使用。可以在一些新线程上调用move方法,您可以控制它调用它的频率,但也可以在render方法之前(或内部)的每一帧上调用它。

所以我的建议是在动画一些openGL驱动的代码时需要对render方法进行一些重复调用,例如使用显示链接。使用此调用执行所有渲染,同时将所有移动分离到某些外部方法,该方法与渲染或openGL完全无关。这样,您就可以在单独的线程或同一个线程中控制移动。

关于使运动动画方法和插值复杂化:如果按照我描述的方式实现它,你将能够在动画中停止并将其动画到其他位置而不会出现任何问题。