2016-03-31 2 views
1

При попытке перейти в использовании «современный» OpenGL (в основном 3.2+), я столкнулся с некоторыми проблемами работает базовый код (производный от обоих here и here) с помощью GLFW, GLEW и OpenGL ,OpenGL + GLFW glGenVertexArrays возвращает GL_INVALID_OPERATION

Моя первая проблема заключается в том, что на код ниже:

#define GLEW_STATIC 
#include <GL/glew.h> 
#include <GLFW/glfw3.h> 
#include <stdlib.h> 
#include <stdio.h> 

const GLchar* vertexSource = 
    "#version 150 core\n" 
    "in vec2 position;" 
    "void main()" 
    "{" 
    " gl_Position = vec4(position, 0.0, 1.0);" 
    "}"; 
const GLchar* fragmentSource = 
    "#version 150 core\n" 
    "out vec4 outColor;" 
    "void main()" 
    "{" 
    " outColor = vec4(1.0, 1.0, 1.0, 1.0);" 
    "}"; 

void checkErr(const char* msg) { 
    GLenum err = glGetError(); 

    if (err != 0) { 
     printf("@ \"%s\": %d\n", msg, err); 
     exit(EXIT_FAILURE); 
    } else { 
     printf("@ \"%s\": successful\n", msg); 
    } 
} 

int main(int argc, char* argv[]) { 
    GLFWwindow* window; 

    // Initialize GLFW 
    if (!glfwInit()) 
     return -1; 

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

    // Create a windowed mode window and its OpenGL context 
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); 
    if (!window) 
    { 
     glfwTerminate(); 
     return -1; 
    } 

    // Make the window's context current 
    glfwMakeContextCurrent(window); 

    // Initialize GLEW 
    glewExperimental = GL_TRUE; 
    glewInit(); 

    // get version info 
    const GLubyte* renderer = glGetString(GL_RENDERER); 
    const GLubyte* version = glGetString(GL_VERSION); 
    const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION); 
    printf ("Renderer:  %s\n", renderer); 
    printf ("OpenGL version: %s\n", version); 
    printf ("GLSL version: %s\n", glslVersion); 

    // Create Vertex Array Object 
    GLuint vao; 
    glGenVertexArrays(1, &vao); 
    checkErr("Gen VAO"); 
    glBindVertexArray(vao); 
    checkErr("Bind VAO"); 

    // Create a Vertex Buffer Object and copy the vertex data to it 
    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    checkErr("Gen VBO"); 

    GLfloat vertices[] = { 
     0.0f, 0.5f, 
     0.5f, -0.5f, 
     -0.5f, -0.5f 
    }; 

    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    checkErr("Bind VBO"); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
    checkErr("VBO data"); 

    // Create and compile the vertex shader 
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexSource, NULL); 
    glCompileShader(vertexShader); 
    checkErr("Compile vert shader"); 

    // Create and compile the fragment shader 
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL); 
    glCompileShader(fragmentShader); 
    checkErr("Compile frag shader"); 

    // Link the vertex and fragment shader into a shader program 
    GLuint shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glBindFragDataLocation(shaderProgram, 0, "outColor"); 
    glLinkProgram(shaderProgram); 
    checkErr("Link program"); 
    glUseProgram(shaderProgram); 
    checkErr("Use program"); 

    // Specify the layout of the vertex data 
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); 
    glEnableVertexAttribArray(posAttrib); 
    checkErr("Enable vertex attrib"); 
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); 
    checkErr("Describe vert data"); 

    // Loop until the user closes the window 
    while (!glfwWindowShouldClose(window)) 
    { 
     /* Render here */ 
     glClearColor(0.0, 0.0, 0.0, 1.0); 
     glClear(GL_COLOR_BUFFER_BIT); 
     glDrawArrays(GL_TRIANGLES, 0, 3); 

     /* Swap front and back buffers */ 
     glfwSwapBuffers(window); 

     /* Poll for and process events */ 
     glfwPollEvents(); 
    } 

    glfwTerminate(); 
    exit(EXIT_SUCCESS); 
} 

я сразу бегу в GL_INVALID_OPERATION ошибок на самом первом этапе создания объекта массива вершин.

Я провел довольно немного исследований относительно ненадежной поддержки OpenGL OS X, но до сих пор большинство вещей, которые я изменил в этом коде, ничего не делали, но производят полностью черный экран (т. Е. Когда я удалили сбойную функцию checkError вспомогательной функции).

Для справки, я бегу на начале 2015 MacBook Pro ж/Retina, OS X v10.11.3, и выход информации версии из моих выше списка программ следующим образом:

Renderer:  Intel(R) Iris(TM) Graphics 6100 
OpenGL version: 4.1 INTEL-10.12.13 
GLSL version: 4.10 

Любой помощь очень ценится!

ответ

3

Вы только предположили что ваша ошибка возникла от glGenVertexArrays. Но это не тот случай. Он генерируется glewInit. И это потому, что GLEW просто разбит на основной профиль opengl: он использует glGetString(GL_EXTENSIONS) для запроса строки расширения, которая недоступна в основных версиях и генерирует ошибку GL_INVALID_ENUM (1280).

Обычно glewInit отменяет код возврата GL_FALSE. Тем не менее, «обходной путь» установки glewExperimental=GL_TRUE заставит его работать, игнорируя ошибку и в любом случае запрашивая все указатели на расширение. Это сейчас нарушено, по крайней мере, в 3 разных отношениях:

  1. Все переменные GLEW для запроса доступности специальных расширений возвращают false, даже если расширение доступно.
  2. Он будет извлекать указатели функций для функций расширения, доступность которых не была объявлена ​​реализацией. Не гарантируется, что эти указатели будут NULL, но называть их было бы неопределенным поведением. Вместе с 1 это означает, что у вас нет возможности проверить доступность какого-либо расширения, за исключением того, что вручную делаете glow на самом деле там для вас.
  3. Он оставит контекст GL в состоянии ошибки.

Как быстро & грязного хака, вы можете просто добавить glGetError() сразу после glewInit, чтобы прочитать сообщение об ошибке прочь. После того, как я это сделал, ваш код создал ожидаемый белый треугольник в моей реализации (NVIDIA/Linux).

Лучшим решением, вероятно, является переход на другой загрузчик GL, который правильно работает с профилями сердечника, например glad. Переключение не будет действительно трудным, так как только эта функция init должна быть заменена. Обратите внимание, что рад не является библиотекой загрузчика, а скриптом python, который создает файл-загрузчик источник для ваших нужд, поэтому вам не нужно связывать другую библиотеку, а просто добавить дополнительный исходный файл в ваш проект.

+0

Спасибо за помощь @derhass, я на самом деле не использую GLEW в другом месте, поэтому просто удаляю GLEW, полностью работающую для создания треугольника! Я определенно впадал в рад раньше, но не мог точно понять, какую дополнительную ценность он добавил по сравнению с GLFW, GLEW и т. Д. Но я обязательно посмотрю сейчас. – jerluc

+1

Поскольку вы находитесь на OSX, gl-загрузчик не требуется строго для доступа к основным функциям OpenGL. Однако, если вы намерены написать защищенный код, вы не можете этого сделать. Взгляните на [this] (https://www.opengl.org/wiki/Load_OpenGL_Functions) и [this] (https://www.opengl.org/wiki/OpenGL_Loading_Library). Вики-статья OpenGL, чтобы узнать, какие GL-загрузчики около. – derhass

Смежные вопросы