使用GLKit绘图

8

我正在尝试使用OpenGL编写游戏,但是在iOS中使用新的GLKit类和默认模板时遇到了很多问题。

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if (!self.context) {
        NSLog(@"Failed to create ES context");
    }

    if(!renderer)
        renderer = [RenderManager sharedManager];
    tiles = [[TileSet alloc]init];

    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    [self setupGL];
}

- (void)setupGL
{
    int width = [[self view] bounds].size.width;
    int height = [[self view] bounds].size.height;

    [EAGLContext setCurrentContext:self.context];

    self.effect = [[GLKBaseEffect alloc] init];
    self.effect.light0.enabled = GL_TRUE;
    self.effect.light0.diffuseColor = GLKVector4Make(0.4f, 0.4f, 0.4f, 1.0f);

    //Configure Buffers
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    glGenRenderbuffers(2, &colourRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colourRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colourRenderBuffer);

    glGenRenderbuffers(3, &depthRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);

    //Confirm everything happened awesomely
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
    if(status != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }

    glEnable(GL_DEPTH_TEST);

    // Enable the OpenGL states we are going to be using when rendering
    glEnableClientState(GL_VERTEX_ARRAY);

}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.4f, 0.4f, 0.4f, 1.0f);


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);


    float iva[] = {
        0.0,0.0,0.0,
        0.0,1.0,0.0,
        1.0,1.0,0.0,
        1.0,0.0,0.0,
    };

    glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, iva);

    glDrawArrays(GL_POINTS, 0, 4);

}
@end

这样做会清除缓冲区(变为灰色),但顶点数组中的任何内容都不会渲染。我不知道该怎么做,由于技术的陈旧性,关于如何正确使用glkit的信息并不多。

5个回答

12

我在你的设置代码中没有看到任何加载着色器的内容-我想你会在代码的某个地方做这件事吧?

此外,在您的设置代码中,您正在创建帧缓冲区。 GLKView 会为您完成此操作-实际上,您正在告诉视图在viewDidLoad方法中使用24位深度缓冲区:

GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

在你上面的 glkView:drawInRect: 代码中所做的是说:“绑定我的手工帧缓冲区,并在其中绘制一些东西”。然后,GLKView 会自动显示它本身,但是什么也没有被绘制到它里面,你只是画在了自己制作的缓冲区中。除非你需要额外的帧缓冲对象来执行诸如渲染到纹理等任务,否则你根本不需要关心帧缓冲对象的创建 - 让GLKView 自动完成即可。

在你的 setupGL 方法中(或者任何你喜欢设置的地方),你应该创建记住执行绘制所需 OpenGL 状态的顶点数组对象。然后,在 glkView:drawInRect: 方法中,你应该:

  1. 使用 glClear() 进行清除。
  2. 启用你的程序。
  3. 绑定顶点数组对象(如果你没有使用 VAO,则启用适当的顶点属性指针)。
  4. 使用 glDrawArrays()glDrawElements() 绘制数据。

GLKView 在每个绘制周期之前会自动设置其上下文为当前上下文,并绑定其帧缓冲对象。

也许你可以尝试将 GLKView 看作一个常规的UIView。它大多数情况下为你处理了一般的 openGL 代码,只需要告诉它需要绘制什么即可。它有自己的 drawRect: 代码,就像一个常规的 UIView - 在 drawRect:中,你只需告诉它应该绘制什么,例如使用 Core Graphics 函数 - 你不需要告诉它去呈现自己。

然后最好将GLKViewController看作是在幕后处理渲染循环的机制。你不需要实现计时器,甚至不需要担心当你的应用程序进入后台时暂停动画。你只需要重写 update 或者 glkViewControllerUpdate: 方法(取决于你是子类化还是委托),以更新 OpenGL 对象或视图矩阵的状态。


1

0

我还没有使用过GLKit,但是看起来你在绘制完后没有呈现你的帧缓存。 在一个使用OpenGL ES 2的iOS应用程序中,但没有GLKit的情况下,我习惯在渲染循环的末尾调用以下代码。

if(context) {
  [EAGLContext setCurrentContext:context];
  glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
  [context presentRenderbuffer:GL_RENDERBUFFER];

}

就像我说的,我还没有使用过GLKit,所以我希望这可能会有用。


我之前见过并尝试过这个,但是Xcode拒绝编译,并显示以下信息:“EAGLContext”的实例消息没有声明选择器“presentRenderbuffer:”。 - botptr
导入QuartzCore解决了我的构建问题,但我仍然无法绘制任何东西。 - botptr
3
在GLKit中,GLKView会在每个渲染周期结束时自动呈现自己并丢弃不需要的渲染缓冲区。这与代码无关。有关详细信息,请参见我的答案。 - Stuart

0

我觉得你忘记调用了

[self.effect prepareToDraw];

就在之前

glDrawArrays(GL_POINTS, 0, 4);

0

由于GLKit模拟OpenGL ES 1.1渲染管道,因此您不需要包含定义着色器的例程。如果要使用类似OpenGL ES 1.1的基本管道,则GLKit实际上会为您执行此操作。


1
这是不正确的。如果使用OpenGL ES 2.0(用于默认的OpenGL ES模板)和GLKView,则仍需要提供着色器。一些默认效果是可用的,但您必须在GLKit中使用GLKBaseEffect等进行设置。以上代码中没有任何这些内容。 - Brad Larson
1
在某种意义上你是对的,我们会使用GLKit的GLKBaseEffect来设置这些参数。我的观点是,“如果您希望使用基本管线,则不必显式编写着色器”。 - Sagar Ranglani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接