glDrawArrays(...)中的OpenGL访问冲突

时间:2014-04-15 14:57:20

标签: c++ opengl shader mesh

我正在按照教程为现代OpenGL设置一些VBO。我设法让网格和着色器运行(着色器设置为使每个像素变红)。

接下来的教程我是设置着色器使用纹理映射,它似乎在调试器中正确加载,但是我不太确定,因为我得到一个错误,一旦我到达glDrawArrays(...) ;

我认为这些东西很难进入,所以我猜测我可能在某处做了一些可怕的错误。提前抱歉您可能会看到x)

错误输出:

First-chance exception at 0x52E4A415 (nvoglv32.dll) in Modern OpenGL.exe: 0xC0000005: Access violation reading location 0x00000000.

这是我的网格代码(或VBO代码):

Mesh::Mesh() {
    //Generate vertex array
    glGenVertexArrays(1, &arrayObject);

    for (int i = 0; i < VBO_COUNT; i++) {
        //Generate vertex buffer
        glGenBuffers(1, &buffers[i]);
    }
}

Mesh::Mesh(ObjectData *obj) {
    //Initialize first
    Mesh::Mesh();

    //Set object to parameter
    setObject(obj);
}

Mesh::~Mesh() {
    for (int i = 0; i < VBO_COUNT; i++) {
        //Delete buffer
        glDeleteBuffers(1, &buffers[i]);
    }

    //Delete array
    glDeleteVertexArrays(1, &arrayObject);
}

void Mesh::draw() {
    //Tell OpenGL which array to use
    glBindVertexArray(arrayObject);

    glDrawArrays(GL_TRIANGLES, 0, object->vertices.size());

    glBindVertexArray(NULL);
}

void Mesh::updateVBO() {
    //Tell OpenGL which vertex array to use from now
    glBindVertexArray(arrayObject);

    //Set buffer data
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_VERTEX]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(object->vertices[0]) * object->vertices.size(), &object->vertices.front(), GL_STATIC_DRAW);

    //Set shader attribute data
    glEnableVertexAttribArray(VBO_VERTEX);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    //Set buffer data
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_TEXCORD]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(object->texCoords[0]) * object->texCoords.size(), &object->texCoords.front(), GL_STATIC_DRAW);

    //Set shader attribute data
    glEnableVertexAttribArray(VBO_TEXCORD);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    //Unbind vertex array
    glBindVertexArray(NULL);
}

void Mesh::setObject(ObjectData *obj) {
    object = obj;
    updateVBO();
}

这是我的着色器代码:

Shader::Shader(string fileName) {
    m_program = glCreateProgram();
    m_shaders[SHA_VERTEX] = createShader(loadShader(fileName + ".vs"), GL_VERTEX_SHADER);
    m_shaders[SHA_FRAGMENT] = createShader(loadShader(fileName + ".fs"), GL_FRAGMENT_SHADER);

    for (int i = 0; i < SHA_COUNT; i++) {
        glAttachShader(m_program, m_shaders[i]);
    }

    glBindAttribLocation(m_program, VBO_VERTEX, "vertices");
    glBindAttribLocation(m_program, VBO_TEXCORD, "texCoords");

    glLinkProgram(m_program);
    checkShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");

    glValidateProgram(m_program);
    checkShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
}

Shader::~Shader() {
    for (int i = 0; i < SHA_COUNT; i++) {
        glDetachShader(m_program, m_shaders[i]);
        glDeleteShader(m_shaders[i]);
    }

    glDeleteProgram(m_program);
}

string Shader::loadShader(string filePath) {
    ifstream file;
    file.open((filePath).c_str());

    string output;
    string line;

    if(file.is_open()) {
        while(file.good()) {
            getline(file, line);
            output.append(line + "\n");
        }
    }
    else {
        printf("Unable to load shader: %s\n", filePath.c_str());
    }

    return output;
}

void Shader::checkShaderError(GLuint shader, GLuint flag, bool isProgram, string errorMessage) {
    GLint success = 0;
    GLchar error[1024] = {0};

    if (isProgram) {
        glGetProgramiv(shader, flag, &success);
    }
    else {
        glGetShaderiv(shader, flag, &success);
    }

    if (success == GL_FALSE) {
        if(isProgram) {
            glGetProgramInfoLog(shader, sizeof(error), NULL, error);
        }
        else {
            glGetShaderInfoLog(shader, sizeof(error), NULL, error);
        }

        printf("%s: '%s'\n", errorMessage.c_str(), error);
    }
}

GLuint Shader::createShader(string text, unsigned int type) {
    GLuint shader = glCreateShader(type);
    if (shader == 0) {
        printf("Error compiling shader type %i\n", type);
    }

    const GLchar *p[1];
    p[0] = text.c_str();
    GLint lengths[1];
    lengths[0] = text.length();

    glShaderSource(shader, 1, p, lengths);
    glCompileShader(shader);

    checkShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");

    return shader;
}

void Shader::bind() {
    glUseProgram(m_program);
}

编辑:这是我的顶点和texCoords:

//Create test objects
ObjectData *obj = new ObjectData();

obj->vertices.push_back(glm::vec3(-1, 0, 0));
obj->vertices.push_back(glm::vec3(0, 0.5, 0));
obj->vertices.push_back(glm::vec3(0, -0.5, 0));
obj->texCoords.push_back(glm::vec2(0.0, 0.5));
obj->texCoords.push_back(glm::vec2(0.5, 0.75));
obj->texCoords.push_back(glm::vec2(0.5, 0.25));

obj->vertices.push_back(glm::vec3(1, 0, 0));
obj->vertices.push_back(glm::vec3(0, 0.5, 0));
obj->vertices.push_back(glm::vec3(0, -0.5, 0));
obj->texCoords.push_back(glm::vec2(1.0, 0.5));
obj->texCoords.push_back(glm::vec2(0.5, 0.75));
obj->texCoords.push_back(glm::vec2(0.5, 0.25));

这是我的对象数据:

struct ObjectData {
    vector <glm::vec3> vertices, normals, colors;
    vector <glm::vec2> texCoords;
    vector <GLint> indices;

    ObjectData();
};

3 个答案:

答案 0 :(得分:3)

您正在使用位置和纹理坐标属性。我想在代码中:

//Set shader attribute data
glEnableVertexAttribArray(VBO_TEXCORD);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

您打算将VBO_TEXCORD的第一个参数传递给glVertexAttribPointer

答案 1 :(得分:0)

这部分:

Mesh::Mesh(ObjectData *obj) {
    //Initialize first
    Mesh::Mesh();

    //Set object to parameter
    setObject(obj);
}

并不像你想象的那样工作 - 不像在例如Java Mesh::Mesh()没有调用this的默认构造函数 (我很惊讶你的编译器没有抱怨。)

您可以将公共初始化移动到从两个构造函数调用的单独函数中,也可以使用默认参数值将它们粉碎在一起,如下所示:

Mesh::Mesh(Object* obj) {
    //Generate vertex array
    glGenVertexArrays(1, &arrayObject);

    for (int i = 0; i < VBO_COUNT; i++) {
        //Generate vertex buffer
        glGenBuffers(1, &buffers[i]);
    }

    if (obj)
      setObject(obj);
}

答案 2 :(得分:0)

因此,专门使用VBO_VERTEX的代码正在运行,并且在您同时使用VBO_VERTEXVBO_TEXCORD时会崩溃吗?

我的猜测是verticestexCoords数组的大小不同,例如:object->texCoords.size() < object->vertices.size()

然后当glDrawArrays尝试从相应的数组中获取数据时,vertices是可以的,因为有足够的元素,但texCoords没有足够的元素=&gt;访问违规。

作为旁注:由于您的所有数据似乎都是静态的,因此使用单个VBO而不是两个VBO可以获得更好的性能。引自https://www.opengl.org/wiki/Vertex_Specification_Best_Practices

  

问:你应该为每个人创建一个单独的VBO吗?你会失去性能吗? 答:如果你的对象是静态的,那么将它们全部合并   尽可能少的VBO以获得最佳性能。见上一节   有关布局注意事项的更多详细信息。