OpenGL -- glGenVertexArrays意为生成顶点数组对象,"thread 1: exc_bad_access (code =1, address=0x0)"是一个错误提示信息,表示访问了无效的内存地址。

4
我将翻译以下内容:

我正在编写一个使用C++的OpenGL程序,它可以在地面上绘制两个三维对象。我使用的编程工具是Xcode版本8.0(8A218a)(OSX 10.11.6)。

我的代码(main.cpp):

   #include <GL/glew.h>
    #include <GL/freeglut.h>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <iostream>
    #include <fstream>
    using namespace std;

    using glm::vec3;
    using glm::mat4;

    GLint programID;
    //initialize all OpenGL objects
    GLuint groundVAO, groundVBO, groundEBO; //ground


    bool checkStatus( //OK
        GLuint objectID,
        PFNGLGETSHADERIVPROC objectPropertyGetterFunc,
        PFNGLGETSHADERINFOLOGPROC getInfoLogFunc,
        GLenum statusType)
        {
        GLint status;
        objectPropertyGetterFunc(objectID, statusType, &status);
        if (status != GL_TRUE)
        {
            GLint infoLogLength;
            objectPropertyGetterFunc(objectID, GL_INFO_LOG_LENGTH, &infoLogLength);
            GLchar* buffer = new GLchar[infoLogLength];

            GLsizei bufferSize;
            getInfoLogFunc(objectID, infoLogLength, &bufferSize, buffer);
            cout << buffer << endl;

            delete[] buffer;
            return false;
        }
        return true;
    }

     bool checkShaderStatus(GLuint shaderID) //OK
    {
        return checkStatus(shaderID, glGetShaderiv, glGetShaderInfoLog, GL_COMPILE_STATUS);
    }

     bool checkProgramStatus(GLuint programID) //OK
    {
        return checkStatus(programID, glGetProgramiv, glGetProgramInfoLog, GL_LINK_STATUS);
    }

    string readShaderCode(const char* fileName) //OK
    {
        ifstream meInput(fileName);
        if (!meInput.good())
        {
            cout << "File failed to load..." << fileName;
            exit(1);
        }
        return std::string(
            std::istreambuf_iterator<char>(meInput),
            std::istreambuf_iterator<char>()
        );
    }

    void installShaders() //OK
    {
        GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
        GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

        const GLchar* adapter[1];
        //adapter[0] = vertexShaderCode;
        string temp = readShaderCode("VertexShaderCode.glsl");
        adapter[0] = temp.c_str();
        glShaderSource(vertexShaderID, 1, adapter, 0);
        //adapter[0] = fragmentShaderCode;
        temp = readShaderCode("FragmentShaderCode.glsl");
        adapter[0] = temp.c_str();
        glShaderSource(fragmentShaderID, 1, adapter, 0);

        glCompileShader(vertexShaderID);
        glCompileShader(fragmentShaderID);

        if (!checkShaderStatus(vertexShaderID) || 
    !checkShaderStatus(fragmentShaderID))
            return;

        programID = glCreateProgram();
        glAttachShader(programID, vertexShaderID);
        glAttachShader(programID, fragmentShaderID);
        glLinkProgram(programID);

        if (!checkProgramStatus(programID))
            return;

        glDeleteShader(vertexShaderID);
        glDeleteShader(fragmentShaderID);

        glUseProgram(programID);
     }

     void keyboard(unsigned char key, int x, int y)
     {
         //TODO:
     }

     void sendDataToOpenGL()
     {
         //TODO:
        //create solid objects here and bind to VAO & VBO

        //Ground, vertices info
        const GLfloat Ground[]
        {
             -5.0f, +0.0f, -5.0f, //0
             +0.498f, +0.898, +0.0f, //grass color
             +5.0f, +0.0f, -5.0f, //1
             +0.498f, +0.898, +0.0f,
             +5.0f, +0.0f, +5.0f, //2
             +0.498f, +0.898, +0.0f,
             -5.0f, +0.0f, +5.0f
        };
        GLushort groundIndex[] = {1,2,3, 1,0,3};

        //Pass ground to vertexShader
        //VAO
        glGenVertexArrays(1, &groundVAO);
        glBindVertexArray(groundVAO);

        //VBO
        glGenBuffers(1, &groundVBO);
        glBindBuffer(GL_ARRAY_BUFFER, groundVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Ground), Ground, GL_STATIC_DRAW);

        //EBO
        glGenBuffers(1, &groundEBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, groundEBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(groundIndex), groundIndex, GL_STATIC_DRAW);

        //connectToVertexShader
        glEnableVertexAttribArray(0); //position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
        glEnableVertexAttribArray(1); //color
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (char*)(sizeof(float)*3));
     }

    void paintGL(void)
    {
        //TODO:
        //render your objects and control the transformation here
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //translate model
        glm::mat4 modelTransformMatrix = glm::translate(glm::mat4(), vec3(+0.0f, +0.0f, -3.0f));
        //perspective view
        glm::mat4 projectionMatrix = glm::perspective(+40.0f, +1.0f, +1.0f, +60.0f);
        //ultimate matrix
        glm::mat4 ultimateMatrix;

        //register location on the graphics cards
        GLint ultimateMatrixUniformLocation = glGetUniformLocation(programID, "ultimateMatrix");
        /*GLint modelTransformMatrixUniformLocation = glGetUniformLocation(programID, "modelTransformMatrix");
        GLint projectionMatrixUniformLocation = glGetUniformLocation(programID, "projectionMatrix");*/

        //drawing the ground

        /*glUniformMatrix4fv(modelTransformMatrixUniformLocation, 1, GL_FALSE, &modelTransformMatrix[0][0]);
        glUniformMatrix4fv(projectionMatrixUniformLocation, 1, GL_FALSE, &projectionMatrix[0][0]);*/
        glBindVertexArray(groundVAO);
        ultimateMatrix = projectionMatrix * modelTransformMatrix;
        glUniformMatrix4fv(ultimateMatrixUniformLocation, 1, GL_FALSE, &ultimateMatrix[0][0]);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);

        glFlush();
        glutPostRedisplay();
    }

    void initializedGL(void) //run only once
    {
        glewInit();
        glEnable(GL_DEPTH_TEST);
        sendDataToOpenGL();
        installShaders();
    }

    int main(int argc, char *argv[])
    {
        /*Initialization*/
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
        glutCreateWindow("Try");
        glutInitWindowSize(700, 700);

        //const GLubyte* glversion = glGetString(GL_VERSION);

        /*Register different CALLBACK function for GLUT to response
        with different events, e.g. window sizing, mouse click or
        keyboard stroke */
        initializedGL();

        //glewExperimental = GL_TRUE;

        glutDisplayFunc(paintGL);
        glutKeyboardFunc(keyboard);

        /*Enter the GLUT event processing loop which never returns.
        it will call different registered CALLBACK according
        to different events. */
        //printf("OpenGL ver: %s\n", glversion);
        glutMainLoop();

        return 0;
    }

VertexShaderCode.glsl:

#version 430  // GLSL version your computer supports

in layout(location=0) vec3 position;
in layout(location=1) vec3 vertexColor;

uniform mat4 ultimateMatrix;

out vec3 theColor;

void main()
{
    vec4 v = vec4(position, 1.0);
    gl_Position = ultimateMatrix * v;
    theColor = vertexColor;
} 

FragmentShaderCode.glsl:

#version 430 //GLSL version your computer supports

out vec4 theColor2;
in vec3 theColor;

void main()
{
    theColor2 = vec4(theColor, 1.0);
}

函数: checkStatus, checkShaderStatus, checkProgramStatus, readShaderCode, installShaders 应该都没问题。

void keyboard() 可以忽略,因为我还没有实现它(只是用于键盘控制)。

我在 sendDataToOpenGL() 中实现了对象 "Ground"。但当我编译并运行程序时,在VAO的那一行出现了"thread 1: exc_bad_access (code =1, address=0x0)"的错误:
enter image description here

而弹出窗口只是一个白屏而不是绿色的草地(3D)。
enter image description here

我尝试了其他 stackoverflow 帖子中提供的一个方法:使用 glewExperimental = GL_TRUE;。我没有看到任何错误,但是弹出窗口出现后立即消失了。似乎它不能解决问题。

有人能帮帮我吗?谢谢!


我不确定我是否表达清楚了我的问题。您可以向我要求更多细节。在没有解释的情况下进行负评是一种可怕的行为。 - Gareth Lam
@Rabbid76 谢谢你的帮助,现在看起来清晰多了。 :) - Gareth Lam
顺便提一下,glutInitWindowSize 应该在 glutCreateWindow 之前调用。好的,我把它们换了顺序。然后,我在 "glutCreateWindow(“Try”);" 下面添加了这些代码(在 int main() 中):if(glewGetExtension("GL_ARB_vertex_array_object") != GL_TRUE) { fprintf(stderr, "It is not supported!\n"); }输出了"It is not supported!"。那么,这是不是意味着 glGenvertexarray 不能被支持呢? - Gareth Lam
我得到了: 1: 在执行glGenVertexArrays(1, &groundVAO)时,错误从“thread 1: exc_bad_access (code =1, address=0x0)”变成了“Thread 1:breakpoint1.1”。 2. fprintf语句中打印了“不支持!”的信息。 - Gareth Lam
1个回答

3

glGenVertexArrays自OpenGL 3.0版本开始提供。可以通过glewGetExtension("GL_ARB_vertex_array_object")检查是否支持顶点数组对象。

Glew可以通过glewExperimental = GL_TRUE;启用其他扩展。参见GLEW文档,其中写道:

GLEW从图形驱动程序获取有关支持的扩展信息。但是,实验性或预发布驱动程序可能不会通过标准机制报告每个可用的扩展,在这种情况下,GLEW将报告其不受支持。为了避免这种情况,可以在调用glewInit()之前将全局开关glewExperimental设置为GL_TRUE,以确保所有具有有效入口点的扩展都将被公开。

将此添加到您的代码中:

glewExperimental = GL_TRUE;
glewInit();

我添加了你建议的代码。“thread 1: exc_bad_access (code =1, address=0x0)” 的问题已经解决了!谢谢!但是现在我面临另一个问题:文件加载失败...VertexShaderCode.glslProgram以退出代码1结束。无法加载顶点着色器。但是,我已经在installShaders()函数中实现了读取所有着色器代码的代码。此外,我已经将vertexshadercode.glsl、fragmentshadercode.glsl和main.cpp都放在同一个文件中。我不明白为什么glsl文件无法加载..... - Gareth Lam
当您从文件中读取时,着色器文件必须包含在应用程序的工作目录中。出于调试原因,您可以将绝对文件路径应用于readShaderCode(...)的调用。 - Rabbid76
1
你的建议一直很好。我改成了绝对文件路径,现在着色器可以被读取了。但是接下来我遇到了一个问题,我认为它与我的OpenGL和GLSL版本有关。但是我会在一个新的帖子中提出这个问题,以使它更清晰。再次感谢你,Rabbid!!! - Gareth Lam

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