【问题标题】:On-demand OpenGL ES rendering using GLKit使用 GLKit 的按需 OpenGL ES 渲染
【发布时间】:2011-12-06 13:24:52
【问题描述】:

我正在考虑转换我的 OpenGL 渲染代码以利用 GLKit 的一些功能(即异步纹理加载和 GLKView/Controller 提供的自动化)。然而,这些类似乎主要是为了适应人们使用动画循环进行渲染而设计的,而我正在使用按需渲染。此外,一些渲染是针对纹理而不是 GLKView 的帧缓冲区,所以我是否应该只寻找 GLKView 的子类并添加额外的 FBO?

对于这种类型的设置是否有推荐的方法?我会期待以下内容:

  • 将视图控制器的preferredFramesPerSecond 设置为0,或者只是 暂停帧更新?
  • 忽略glkViewControllerUpdateglkView:drawInRect: 方法 并在我需要的时候画出我需要的东西。
  • 按顺序使用视图的setNeedsDisplay 和普通的UIView 显示框架(我需要打电话给bindDrawable,因为我 也会渲染到纹理?)。

如果这不是新 API 的设计目的,也许不值得付出努力?我希望文档比它更彻底。当 API 稍微“成熟”一点时,也许会提供更多示例......

谢谢

【问题讨论】:

标签: ios opengl-es glkit


【解决方案1】:

我刚刚将我的代码从使用 EAGLContext 管理器转换为使用 GLKit 类。

您建议您可以“..忽略..glkView:drawInRect: 方法,并在我需要时绘制[您]需要的东西”。从性能上看,这似乎是一个明智的选择;我假设(尽管没有尝试过)如果您只是不指定 GLKViewDelegate 或提供具有 drawInRect: 定义的子类 GLKView,则不会发生动画循环渲染。你尝试过吗?

另一种方法是在您的 MyController : GLKViewController <GLKViewDelegate> 类中简单地创建一些 @property (assign, nonatomic) BOOL shouldUpdate;,只有在有事情要做时才会更新:

[self setDelegate:self]; // in init or awakeFromNib or other..

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    if ([self shouldUpdate]) { ...

我相信你明白了,这并不复杂。

有一点值得一提:官方 API 文档声明 viewDidLoad 应该在您的 GLKViewController 中用于初始 GL 设置。我对此有疑问;出于某种原因,我的glCreateShader 调用总是返回零。这可能是由于我设置了EAGLContext 后初始化;因为我在 Storyboard 中创建了控制器,所以我无法将它作为 init 参数传递。但是,代码在逻辑上没有任何错误,因此我提供此友好警告,以防您遇到类似问题。我的解决方案只是在我的 drawInRect 中包含以下内容:

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    if ([self initialGLSetupDone] == NO) {
        [self beforeFirstRender];
        [self setInitialGLSetupDone:YES];
    }
    // .. rest of render code goes here.
}

显然,不必要地在其中放置一个 IF 并不理想,但这是一个简单的解决方案。

如果您尝试更新以使用 GLKit,请告诉我结果如何。

【讨论】:

  • 关于viewDidLoad 问题,您的EAGLContext 必须在创建着色器之前设置,正如您自己注意到的那样。在您设置其余 GL 代码之前,在 viewDidLoad 中执行此操作也没有什么害处。查看 Xcode 中的“OpenGL 游戏”模板项目,了解如何执行此设置的一个很好的示例。
  • 感谢闩锁提示。比尝试手动绘制 CAEAGLLayer 或其他解决方法要容易得多。
【解决方案2】:

创建 GLKView 后,添加以下行:

glkView.enableSetNeedsDisplay = TRUE;

(正因为如此,没有人会自动重绘视图)

当你想重绘时,插入这一行:

[glkView setNeedsDisplay];

...那么drawInRect 例程将只被调用一次。

希望对你有帮助。

【讨论】:

  • -1。这是不正确的 - 将 enableSetNeedsDisplay 设置为 NO 禁用 GLKViewsetNeedsDisplay 方法。使用GLKViewController 时,此属性会自动设置为NO,因此实际上必须在以setNeedsDisplay“模式”绘图时手动将其设置为YES
【解决方案3】:

我最终使用的方法是不打扰GLKViewController,而是直接在UIViewController 子类下使用GLKView

显然,GLKViewController 旨在供需要为游戏等应用程序提供一致渲染循环的人使用。没有它,绘制到GLKView 就像调用[glkView setNeedsDisplay] 一样简单。请务必将 enableSetNeedsDisplay 设置为 YES 以启用此行为。

如果您仍然想使用GLKViewController,您可以像这样禁用viewWillAppear 中的动画渲染循环:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];    // setPaused automatically set to NO in super's implementation

    [self setPaused:YES];
}

另外,将resumeOnDidBecomeActive 设置为NO 以防止视图控制器再次自动恢复。

不过,使用普通的 UIViewControllerGLKView 是完全可以接受的,而且我已经看到 Apple 工程师推荐它作为执行按需绘图的合适方式。

【讨论】:

  • 如果您能阐明需要在哪些方法中设置 enableSetNeedsDisplay 和 resumeOnDidBecomeActive 会有所帮助,因为您没有将它们放入 viewWillAppear(BOOL) 动画中。谢谢。
  • 在创建视图/视图控制器时设置这些属性。例如,如果您在代码中创建GLKViewController,则可能将其设置在alloc/init 之后的行上。如果您在界面生成器中创建它,那么在您的视图控制器中实现-awakeFromNib 方法可能是一个好地方。一般来说,像这样的属性应该在对象创建之后/使用时设置。
  • 您是否有可用的开源代码来展示此示例?谢谢
猜你喜欢
  • 2011-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
相关资源
最近更新 更多