使用GLKit进行按需OpenGL ES渲染

时间:2022-09-07 09:24:46

I am looking into converting my OpenGL rendering code to take advantage of a few features of GLKit (namely the asynchronous texture loading and the automation provided by GLKView/Controller). However, it appears that the classes are designed mainly to accommodate people rendering using an animation loop, whereas I'm working with on-demand rendering. Additionally, some of the rendering is to a texture rather than the GLKView's framebuffer, so should I be looking to just subclass the GLKView and add additional FBOs?

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

Is there a recommended approach for this type of setup? I would expect something along the lines of:

这种类型的设置是否有推荐的方法?我希望有以下几点:

  • Set the view controller's preferredFramesPerSecond to 0, or just pause the frame updates?
  • 将视图控制器的preferredFramesPerSecond设置为0,或者只是暂停帧更新?
  • Ignore the glkViewControllerUpdate or glkView:drawInRect: methods and just draw what I need, when I need it.
  • 忽略glkViewControllerUpdate或glkView:drawInRect:方法,只需在需要时绘制我需要的东西。
  • Use the view's setNeedsDisplay as with a normal UIView in order to display the frame (do I need to call bindDrawable given that I will be rendering to a texture as well?).
  • 使用视图的setNeedsDisplay和普通的UIView一样,以显示帧(我是否需要调用bindDrawable,因为我也将渲染到纹理?)。

Perhaps it's not worth the effort if this is not what the new API is designed for? I wish the documentation was a little more thorough than it is. Perhaps more samples will be provided when the API has 'matured' a little...

如果这不是新API的设计目标,那么也许不值得努力?我希望文档比它更彻底。当API稍微“成熟”时,可能会提供更多样本......

Thanks

谢谢

3 个解决方案

#1


23  

The approach I ended up using was to not bother with the GLKViewController, but just use GLKView directly under a UIViewController subclass.

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

Clearly, the GLKViewController is intended for use by people who need a consistent rendering loop for apps such as games. Without it, drawing to the GLKView is as simple as calling [glkView setNeedsDisplay]. Be sure to set enableSetNeedsDisplay to YES in order to enable this behaviour.

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

If you did still want to make use of a GLKViewController, you can disable the animation rendering loop in viewWillAppear like so:

如果您仍想使用GLKViewController,则可以在viewWillAppear中禁用动画渲染循环,如下所示:

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

    [self setPaused:YES];
}

Also, set resumeOnDidBecomeActive to NO to prevent the view controller from resuming again automatically.

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

Using a plain UIViewController with a GLKView is perfectly acceptable however, and I have seen it recommended by an Apple engineer as an appropriate way to perform on-demand drawing.

然而,使用带有GLKView的普通UIViewController是完全可以接受的,我已经看到苹果工程师推荐它作为执行按需绘图的适当方式。

#2


3  

I've just converted my code from using an EAGLContext manager I rolled myself to using the GLKit classes.

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

You suggest you might "..ignore the.. glkView:drawInRect: methods and just draw what [you] need, when I need it". This seems like a sensible option performance-wise; I assume (though haven't tried) if you simply don't specify a GLKViewDelegate or provide a subclassed GLKView with its drawInRect: defined then no animation loop rendering will occur. Have you attempted this?

你建议你可以“..忽略.. glkView:drawInRect:方法,只需绘制你需要的东西,当我需要它时”。这似乎是表现明智的明智选择;我假设(虽然没有尝试过)如果你只是没有指定GLKViewDelegate或者提供带有drawInRect的子类化GLKView:定义那么就不会发生动画循环渲染。你试过这个吗?

The alternative would be to simply create some @property (assign, nonatomic) BOOL shouldUpdate; in your MyController : GLKViewController <GLKViewDelegate> class which will only update if there is something to do:

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

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

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

I'm sure you get the idea, it's hardly complicated.

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

One thing worth mentioning: the official API docs state that viewDidLoad should be used in your GLKViewController for initial GL setup. I had issues with this; for some reason my glCreateShader calls always returned zero. This may have been due to my setting the EAGLContext post-initialisation; I couldn't pass it as an init parameter since I created the controller in Storyboard. However, there was nothing logically wrong with the code, so I offer this friendly warning in case you encounter similar issues. My solution is simply to have the following in my drawInRect:

值得一提的是:官方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.
}

Obviously it's not ideal to have an IF in there unnecessarily, but it was an easy solution.

显然,不必要地在那里安装IF并不理想,但这是一个简单的解决方案。

Let me know how it goes if you try updating to use GLKit.

如果您尝试更新以使用GLKit,请告诉我它是怎么回事。

#3


1  

After you have created GLKView, add this line:

创建GLKView后,添加以下行:

glkView.enableSetNeedsDisplay = TRUE;

glkView.enableSetNeedsDisplay = TRUE;

(Because of this, no one will redraw the view automatically)

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

When you want redraw, insert this line:

如果要重绘,请插入以下行:

[glkView setNeedsDisplay];

... then drawInRect routine will be called only once.

...然后drawInRect例程将只调用一次。

Hope it helps.

希望能帮助到你。

#1


23  

The approach I ended up using was to not bother with the GLKViewController, but just use GLKView directly under a UIViewController subclass.

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

Clearly, the GLKViewController is intended for use by people who need a consistent rendering loop for apps such as games. Without it, drawing to the GLKView is as simple as calling [glkView setNeedsDisplay]. Be sure to set enableSetNeedsDisplay to YES in order to enable this behaviour.

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

If you did still want to make use of a GLKViewController, you can disable the animation rendering loop in viewWillAppear like so:

如果您仍想使用GLKViewController,则可以在viewWillAppear中禁用动画渲染循环,如下所示:

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

    [self setPaused:YES];
}

Also, set resumeOnDidBecomeActive to NO to prevent the view controller from resuming again automatically.

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

Using a plain UIViewController with a GLKView is perfectly acceptable however, and I have seen it recommended by an Apple engineer as an appropriate way to perform on-demand drawing.

然而,使用带有GLKView的普通UIViewController是完全可以接受的,我已经看到苹果工程师推荐它作为执行按需绘图的适当方式。

#2


3  

I've just converted my code from using an EAGLContext manager I rolled myself to using the GLKit classes.

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

You suggest you might "..ignore the.. glkView:drawInRect: methods and just draw what [you] need, when I need it". This seems like a sensible option performance-wise; I assume (though haven't tried) if you simply don't specify a GLKViewDelegate or provide a subclassed GLKView with its drawInRect: defined then no animation loop rendering will occur. Have you attempted this?

你建议你可以“..忽略.. glkView:drawInRect:方法,只需绘制你需要的东西,当我需要它时”。这似乎是表现明智的明智选择;我假设(虽然没有尝试过)如果你只是没有指定GLKViewDelegate或者提供带有drawInRect的子类化GLKView:定义那么就不会发生动画循环渲染。你试过这个吗?

The alternative would be to simply create some @property (assign, nonatomic) BOOL shouldUpdate; in your MyController : GLKViewController <GLKViewDelegate> class which will only update if there is something to do:

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

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

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

I'm sure you get the idea, it's hardly complicated.

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

One thing worth mentioning: the official API docs state that viewDidLoad should be used in your GLKViewController for initial GL setup. I had issues with this; for some reason my glCreateShader calls always returned zero. This may have been due to my setting the EAGLContext post-initialisation; I couldn't pass it as an init parameter since I created the controller in Storyboard. However, there was nothing logically wrong with the code, so I offer this friendly warning in case you encounter similar issues. My solution is simply to have the following in my drawInRect:

值得一提的是:官方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.
}

Obviously it's not ideal to have an IF in there unnecessarily, but it was an easy solution.

显然,不必要地在那里安装IF并不理想,但这是一个简单的解决方案。

Let me know how it goes if you try updating to use GLKit.

如果您尝试更新以使用GLKit,请告诉我它是怎么回事。

#3


1  

After you have created GLKView, add this line:

创建GLKView后,添加以下行:

glkView.enableSetNeedsDisplay = TRUE;

glkView.enableSetNeedsDisplay = TRUE;

(Because of this, no one will redraw the view automatically)

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

When you want redraw, insert this line:

如果要重绘,请插入以下行:

[glkView setNeedsDisplay];

... then drawInRect routine will be called only once.

...然后drawInRect例程将只调用一次。

Hope it helps.

希望能帮助到你。