Рисование с помощью GLKit

Я пытаюсь написать игру с помощью opengl, но у меня большие проблемы с новыми классами glkit и шаблоном по умолчанию из iOS.

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


person botptr    schedule 18.10.2011    source источник


Ответы (5)


Я не вижу ничего в вашем установочном коде, который загружает ваши шейдеры — я полагаю, вы делаете это где-то в своем коде?

Кроме того, в вашем коде установки вы создаете свой фреймбуфер. GLKView делает это за вас - на самом деле вы говорите представлению использовать 24-битный буфер глубины в вашем методе viewDidLoad:

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 - с обычным UIView в drawRect: вы просто говорите ему, что он должен рисовать, например, используя функции Core Graphics - вы не говорите ему, чтобы он представил себя.

Тогда GLKViewController лучше всего рассматривать как обработку механики цикла рендеринга за кулисами. Вам не нужно реализовывать таймеры или даже беспокоиться о приостановке анимации вашего приложения, переходящего в фоновый режим. Вам просто нужно переопределить метод update или glkViewControllerUpdate: (в зависимости от того, делаете ли вы подклассы или делегируете), чтобы обновить состояние объектов openGL или матрицы представления.

person Stuart    schedule 19.10.2011

Я сделал пост о том, как настроить базовый шаблон проекта с помощью GLKit. Вы можете найти это здесь:

Блог Стива Зиссоу о программировании

person Gabriel G. Roy    schedule 27.03.2012

Я еще не использовал GLKit, но кажется, что вы не представляете свой фреймбуфер после рисования в нем. В приложении, использующем OpenGL ES 2 под iOs, но без GLKit, я вызываю следующий код в конце цикла рендеринга.

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

}

Как я уже сказал, я еще не использовал GLKit, поэтому надеюсь, что это может быть полезно.

person JimN    schedule 18.10.2011
comment
Я видел и пробовал это раньше, но xcode отказывается компилироваться. с сообщением. 'EAGLContext' для экземпляра сообщения не объявляет метод с селектором 'presentRenderbuffer:' - person botptr; 18.10.2011
comment
Импорт QuartzCore устранил мою проблему со сборкой, но мне все еще не удается ничего нарисовать. - person botptr; 18.10.2011
comment
В GLKit GLKView автоматически представляет себя и отбрасывает ненужные буферы рендеринга в конце каждого цикла рендеринга. Это не проблема с кодом. Подробности смотрите в моем ответе. - person Stuart; 19.10.2011

Я думаю, ты забыл позвонить

[self.effect prepareToDraw];

как раз перед

glDrawArrays(GL_POINTS, 0, 4);
person Germano    schedule 28.10.2011

Поскольку GLKit имитирует конвейер рендеринга OpenGL ES 1.1, вам не нужно включать подпрограммы для определения шейдера. GLKit на самом деле делает это за вас, если вы хотите использовать базовый конвейер, такой как OpenGL ES1.1.

person Sagar Ranglani    schedule 05.12.2011
comment
Это неправильно. Вам по-прежнему необходимо предоставлять шейдеры при работе с OpenGL ES 2.0 (используется для шаблона OpenGL ES по умолчанию) и GLKView. Доступны некоторые эффекты по умолчанию, но вы должны настроить их в GLKit, используя GLKBaseEffect и тому подобное. Ничего этого нет в приведенном выше коде. - person Brad Larson; 13.12.2011
comment
Да, в некотором смысле вы правы, мы настроим эти параметры с помощью GLKBaseEffect GLKit. Я хочу сказать, что вам не нужно явно вовлекать себя в написание шейдеров, если вы хотите использовать базовый конвейер. - person Sagar Ranglani; 02.01.2012