简体   繁体   English

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

[英]OpenGL access violation at glDrawArrays(…)

I'm following a tutorial to set up some VBOs for the modern OpenGL. 我正在按照一个教程为现代OpenGL设置一些VBO。 I managed to get a mesh and shader running (shader set to make each pixel red). 我设法使网格和着色器运行(将着色器设置为使每个像素变为红色)。

Next tutorial I was to set up the shader to use texture mapping, which seems to load correctly in the debugger, but I'm not so sure since I get an error once I get to glDrawArrays(...); 在下一个教程中,我将设置着色器以使用纹理映射,该纹理映射似乎已正确加载到调试器中,但是我不确定,因为一旦进入glDrawArrays(...),就会出现错误。

I think this stuff is kind of hard to get into, so I'm guessing I'm probably doing something horribly wrong somewhere. 我认为这些东西很难理解,所以我猜我可能在某处做着可怕的错误。 Sorry in advance for what you might see x) 抱歉,您可能会看到x)

Error output: 错误输出:

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

This is my mesh code (or VBO code): 这是我的网状代码(或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();
}

Here is my shader code: 这是我的着色器代码:

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);
}

EDIT: Here is my vertices and texCoords: 编辑:这是我的顶点和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));

Here is my object data: 这是我的对象数据:

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

    ObjectData();
};

You are using the location for the position and texture coordinate attributes. 您正在使用位置作为位置和纹理坐标属性。 I think in the code: 我认为在代码中:

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

You meant to pass VBO_TEXCORD for the first argument to glVertexAttribPointer . 您打算将VBO_TEXCORD作为第一个参数传递给glVertexAttribPointer

This part: 这部分:

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

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

doesn't work the way you think - unlike in eg Java, Mesh::Mesh() doesn't call the default contructor of this . 不能按照您的想法工作-与Java不同, Mesh::Mesh()不会调用this的默认构造函数。
(I'm surprised your compiler doesn't complain.) (我很惊讶您的编译器没有抱怨。)

You can either move the common initialization to a separate function that you call from both constructors or smash them together using a default parameter value like 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);
}

So the code that uses exclusively VBO_VERTEX is working and it crashes when you use VBO_VERTEX and VBO_TEXCORD at the same time? 因此,仅使用VBO_VERTEX的代码可以正常工作,并且同时使用VBO_VERTEXVBO_TEXCORD时,它会崩溃吗?

My guess would be that the vertices and texCoords arrays don't have the same size, eg: object->texCoords.size() < object->vertices.size() 我的猜测是verticestexCoords数组的大小不同,例如: object->texCoords.size() < object->vertices.size()

And then when glDrawArrays tries to fetch data from the respective arrays, vertices are okay because there are enough elements but texCoords doesn't have enough elements => access violation. 然后,当glDrawArrays尝试从各个数组中获取数据时, vertices就可以了,因为有足够的元素,但是texCoords没有足够的元素=>访问冲突。

As a side note: since all your data seems to be static, you would get better performance by using a single VBO instead of two. 附带说明:由于所有数据似乎都是静态的,因此使用单个VBO而不是两个VBO可以获得更好的性能。 Quoted from https://www.opengl.org/wiki/Vertex_Specification_Best_Practices : 引用自https://www.opengl.org/wiki/Vertex_Specification_Best_Practices

Q: Should you create a separate VBO for each? 问:您是否应该为每个单独创建一个VBO? Would you lose performance? 您会失去表现吗? A: If your objects are static, then merge them all into as few VBOs as possible for best performance. 答:如果您的对象是静态的,则将它们全部合并到尽可能少的VBO中,以获得最佳性能。 See above section for more details on layout considerations. 有关布局注意事项的更多详细信息,请参见以上部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM