使用 GLKit 进行按需 OpenGL ES 渲染

发布于 2024-12-09 23:47:05 字数 643 浏览 1 评论 0原文

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

对于这种类型的设置有推荐的方法吗?我期望的内容如下:

  • 将视图控制器的 preferredFramesPerSecond 设置为 0,或者只是 暂停帧更新?
  • 忽略 glkViewControllerUpdateglkView:drawInRect: 方法 当我需要的时候,就画出我需要的东西。
  • 按顺序使用视图的 setNeedsDisplay 与普通 UIView 一样 显示框架(鉴于我,我是否需要调用 bindDrawable 也会渲染到纹理吗?)。

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

谢谢

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?

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?
  • Ignore the glkViewControllerUpdate or glkView:drawInRect: methods
    and just draw what I need, when I need it.
  • 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?).

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...

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

久伴你 2024-12-16 23:47:06

创建 GLKView 后,添加这一行:

glkView.enableSetNeedsDisplay = TRUE;

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

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

[glkView setNeedsDisplay];

... then < code>drawInRect 例程将仅被调用一次。

希望有帮助。

After you have created GLKView, add this line:

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.

Hope it helps.

り繁华旳梦境 2024-12-16 23:47:05

我最终使用的方法是不使用 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 工程师推荐它作为执行按需绘图的适当方法。

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

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.

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

- (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.

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.

唱一曲作罢 2024-12-16 23:47:05

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

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

另一种方法是简单地在您的 MyController : GLKViewController 类中创建一些 @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 文档指出,应在 GLKViewController 中使用 viewDidLoad 进行初始 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,请告诉我情况如何。

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

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?

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:

[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:

-(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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文