2015-01-08 4 views
0

Я играю с 2D-графикой в ​​OpenGL - фракталы и другие забавные вещи^_ ^. Моя основная настройка - создание пары треугольников для заполнения экрана и использования фрагментарного шейдера, чтобы нарисовать на них классные вещи. Я хотел бы немного сгладить ситуацию, поэтому начал изучать суперсэмплинг. Для меня это не очевидно, как это сделать. Вот что я пробовал до сих пор ...Сглаживание/сглаживание/суперсэмплинг 2d изображений с opengl

Во-первых, я посмотрел на Apple docs on anti-aliasing. Я обновил свою инициализацию формата пикселей:

NSOpenGLPixelFormatAttribute attrs[] = 
{ 
    NSOpenGLPFADoubleBuffer, 
    NSOpenGLPFADepthSize, 24, 
    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, 
    NSOpenGLPFASupersample, 
    NSOpenGLPFASampleBuffers, 1, 
    NSOpenGLPFASamples, 4, 
    0 
}; 

Я также добавил glEnable(GL_MULTISAMPLE); линии. GL_MULTISAMPLE_FILTER_HINT_NV, похоже, не определен (документы выглядят устаревшими), поэтому я не был уверен, что делать там.

Это заставило меня делать медленнее, но, похоже, не делает сглаживания, поэтому я попробовал подход «Render-to-FBO», описанный на OpenGL Wiki on Multisampling. Я пробовал множество вариаций с множеством результатов: успешный рендеринг (который не кажется сглаженным), рендеринг мусора на экране (забава!), Сбои (приложение испаряется, и я получаю системный диалог о проблемах с графикой) и отключение моего ноутбука от курсора (после жесткой перезагрузки получил системный диалог о проблемах с графикой).

Я проверяю статус своего фреймбуфера перед рисованием, поэтому я знаю, что это не проблема. И я уверен, что я предоставляю аппаратное обеспечение, а не программное обеспечение - видел это предложение на других постах.

Я потратил на это много времени и до сих пор не совсем понимаю, как подойти к этому. Одна вещь, которую мне бы очень понравилась, - это как запросить GL, чтобы проверить, включена ли суперсэмплинга правильно или как определить, сколько раз мой шейдер фрагментов вызывается, и т. Д. Я также немного смущен тем, что некоторые из вызовов go - большинство примеров. Я нахожу, что просто говорю, какие методы вызывать, но не указывайте, какие из них нужно использовать в обратном вызове draw. У кого-нибудь есть простой пример SSAA с OpenGL 3 или 4 и OSX ... или другие вещи, чтобы попробовать?

Edit: рисунок код - супер сломан (не судите меня), но для справки:

- (void)draw 
{ 
    glBindVertexArray(_vao); // todo: is this necessary? (also in init) 
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), points, GL_STATIC_DRAW); 

    glGenTextures(1, &_tex); 
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _tex); 
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, _width * 2, _height * 2, false); 

    glGenFramebuffers(1, &_fbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, _fbo); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, _tex, 0); 

    GLint status; 
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    if (status != GL_FRAMEBUFFER_COMPLETE) { 
     NSLog(@"incomplete buffer 0x%x", status); 
     return; 
    } 

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
    glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
    glDrawBuffer(GL_BACK); 
    glClear(GL_COLOR_BUFFER_BIT); 
    glDrawArrays(GL_TRIANGLES, 0, 6); 
    glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, GL_LINEAR); 

    glDeleteTextures(1, &_tex); 
    glDeleteFramebuffers(1, &_fbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
} 

Update: Я изменил код на предложение Рето ниже:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); 
glClear(GL_COLOR_BUFFER_BIT); 
glDrawArrays(GL_TRIANGLES, 0, 6); 
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, 
        GL_COLOR_BUFFER_BIT, GL_LINEAR); 

Это заставило программу отображать мусор на экран. Затем я избавился от множителя * 2, и он все еще рисовал мусор на экран. Затем я отключил опции NSOpenGLPFA, связанные с мульти/супер-выборкой, и он выглядел нормально, без сглаживания.

Я также пробовал использовать текстуру без мультисэмпла, но продолжал получать неполные ошибки вложений. Я не уверен, что это связано с проблемой NVidia, упомянутой в вики OpenGL (опубликует комментарий ina, поскольку у меня недостаточно рекламы, чтобы разместить более 2 ссылок) или что-то еще. Если кто-то может предложить способ узнать, почему вложение является неполным, это было бы очень, очень полезно.

Наконец, я попытался использовать renderbuffer вместо текстуры и обнаружил, что указание ширины и высоты, превышающей размер области просмотра в glRenderbufferStorage, похоже, не работает должным образом.

GLuint rb; 
glGenRenderbuffers(1, &rb); 
glBindRenderbuffer(GL_RENDERBUFFER, rb); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, _width * 2, _height * 2); 

// ... 

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); 
glClear(GL_COLOR_BUFFER_BIT); 
glDrawArrays(GL_TRIANGLES, 0, 6); 
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, 
        GL_COLOR_BUFFER_BIT, GL_LINEAR); 

... оказывает нижнюю левую руку 1/4 экрана. Кажется, он не выглядит более плавным, хотя ...

Обновление 2: удвоил размер видового экрана, он не стал более плавным. Поворот NSOpenGLPFASupersample по-прежнему заставляет его рисовать мусор на экране. >. <

Обновление 3: Я - идиот, это абсолютно гладко. Он просто не выглядит хорошим, потому что я использую уродливую цветовую схему. И мне нужно удвоить все мои координаты, потому что в окне просмотра 2x. Ну что ж. Я до сих пор люблю некоторую помощь, чтобы понять, почему NSOpenGLPFASupersample вызывает такое сумасшедшее поведение ...

+0

NVidia + неполная текстура вопрос: https://www.opengl.org/wiki/Common_Mistakes#Render_To_Texture –

+0

Не мог бы вы поделиться рабочим проектом Мандельброта пожалуйста? Я пытаюсь понять, как сделать 2d графики на OS X с прямой манипуляцией пикселями и действительно изо всех сил пытаться добраться где угодно :( –

+0

@ DanielLucraft Я постараюсь бросить его на Github, но в то же время я бы предложите проверить GLEssentials от Apple [пример кода] (https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html). Я нашел, что это очень полезно для начала работы. –

ответ

1

Ваша последовательность вызовов здесь выглядит он не будет делать то, что вы хотели:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
glDrawBuffer(GL_BACK); 
glClear(GL_COLOR_BUFFER_BIT); 
glDrawArrays(GL_TRIANGLES, 0, 6); 
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, GL_LINEAR); 

Когда вы звоните glClear() и glDrawArrays(), ваш текущий фрейм-буффер кадров, который определяется последним вызовом glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ...), является фреймбуфером по умолчанию. Таким образом, вы никогда не оказываете FBO. Позвольте мне аннотацию выше:

// Set draw framebuffer to default (0) framebuffer. This is where the rendering will go. 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
// Set read framebuffer to the FBO. 
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
// This is redundant, GL_BACK is the default draw buffer for the default framebuffer. 
glDrawBuffer(GL_BACK); 
// Clear the current draw framebuffer, which is the default framebuffer. 
glClear(GL_COLOR_BUFFER_BIT); 
// Draw to the current draw framebuffer, which is the default framebuffer. 
glDrawArrays(GL_TRIANGLES, 0, 6); 
// Copy from read framebuffer (which is the FBO) to the draw framebuffer (which is the 
// default framebuffer). Since no rendering was done to the FBO, this will copy garbage 
// into the default framebuffer, wiping out what was previously rendered. 
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, 
        GL_COLOR_BUFFER_BIT, GL_LINEAR); 

Чтобы получить эту работу, вам необходимо установить раздаточный видеобуфер к FBO во время рендеринга, а затем установить для чтения видеобуфера на FBO и раздаточный видеобуфер по умолчанию для копирования :

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); 
glClear(GL_COLOR_BUFFER_BIT); 
glDrawArrays(GL_TRIANGLES, 0, 6); 
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, 
        GL_COLOR_BUFFER_BIT, GL_LINEAR); 

Резюме: команды

  • Draw написать GL_DRAW_FRAMEBUFFER.
  • glBlitFramebuffer() экземпляры от GL_READ_FRAMEBUFFER до GL_DRAW_FRAMEBUFFER.

Еще пара замечаний по коде:

  • Поскольку вы создаете мультисэмпнула текстуру в два раза больше, вы используете как мультисамплинг и суперсамплинг одновременно:

    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _tex); 
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, 
             _width * 2, _height * 2, false); 
    

    Что является полностью законным. Но это ... много выборки. Если вы просто хотите суперсэмплинг, вы можете использовать обычную текстуру.

  • Вы можете использовать renderbuffer вместо текстуры для целевой цели FBO. Нет огромного преимущества, но это проще и потенциально более эффективно. Вам нужно использовать текстуры только как вложения, если вы захотите пробовать результат позже, что здесь не так.
+0

Большое спасибо за такой подробный ответ. К сожалению, пока это еще не совсем ... Я обновлю вопрос, что я пробовал, и результаты. –

+0

Еще раз спасибо. Вот как выглядит мой Мандельброт сейчас : https://dl.dropboxusercontent.com/u/24793835/thankyou.png.Это с 700 итерациями и масштабированием с 25600 пикселями на единицу. –