奇数访问冲突读取错误/glDrawArrays 使用

Posted

技术标签:

【中文标题】奇数访问冲突读取错误/glDrawArrays 使用【英文标题】:Odd access violation reading error / glDrawArrays usage 【发布时间】:2011-11-23 12:47:08 【问题描述】:

我不确定这是属于这里还是属于图形编程.....我遇到了一个非常烦人的访问冲突读取错误,我不知道为什么。我想要做的是重构一个关键帧函数(计算两个顶点位置之间的中间位置)。该函数编译正常

glBegin(GL_TRIANGLES);
    for(int i = 0; i < numTriangles; i++) 
        MD2Triangle* triangle = triangles + i;
        for(int j = 0; j < 3; j++) 
            MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
            MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
            Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
            Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
            if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) 
                normal = Vec3f(0, 0, 1);
            
            glNormal3f(normal[0], normal[1], normal[2]);

            MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
            glTexCoord2f(texCoord->texCoordX, texCoord->texCoordY);
            glVertex3f(pos[0], pos[1], pos[2]);
        
    
glEnd();

这里的函数计算位置并绘制它们。我想做的是事先计算所有位置,将它们存储在顶点数组中,然后绘制它们。 如果我尝试删除它并在程序的完全相同的部分中用以下内容替换这个块

int vCount = 0;
    for(int i = 0; i < numTriangles; i++) 
        MD2Triangle* triangle = triangles + i;
        for(int j = 0; j < 3; j++) 
            MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
            MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
            Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
            Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
            if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) 
                normal = Vec3f(0, 0, 1);
            

            indices[vCount] = normal[0];
            vCount++;
            indices[vCount] = normal[1];
            vCount++;
            indices[vCount] = normal[2];
            vCount++;

            MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
            indices[vCount] = texCoord->texCoordX;
            vCount++;
            indices[vCount] = texCoord->texCoordY;
            vCount++;

            indices[vCount] = pos[0];
            vCount++;
            indices[vCount] = pos[1];
            vCount++;
            indices[vCount] = pos[2];
            vCount++;
        

    

我收到访问冲突错误“Graphics_template_1.exe 中 0x01455626 处的未处理异常:0xC0000005:访问冲突读取位置 0xed5243c0”指向第 7 行

Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;

这两个 V 似乎在调试器中没有任何价值.... 到目前为止,该函数的行为方式与上面的完全相同,我不明白为什么会发生这种情况?

编辑 ---------------------------------- --------------------------------------------------

感谢 Werner 发现问题在于数组初始化!根据您的建议,我使用 std:vector 容器重构了该函数,并使绘图使用 glDrawArrays 而不是立即模式....但是帧速率并没有提高性能,而是比以前低了很多!我是否正确/有效地使用了这个功能?这是重构后的绘制函数:

    for(int i = 0; i < numTriangles; i++) 
        MD2Triangle* triangle = triangles + i;
        for(int j = 0; j < 3; j++) 
            MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
            MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
            Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
            Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
            if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) 
                normal = Vec3f(0, 0, 1);
            


            normals.push_back(normal[0]);
            normals.push_back(normal[1]);
            normals.push_back(normal[2]);

            MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
            textCoords.push_back(texCoord->texCoordX);
            textCoords.push_back(texCoord->texCoordY);

            vertices.push_back(pos[0]);
            vertices.push_back(pos[1]);
            vertices.push_back(pos[2]);
        

    


    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glNormalPointer(GL_FLOAT, 0, &normals[0]);
    glTexCoordPointer(2, GL_FLOAT, 0, &textCoords[0]); 
    glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);



    glDrawArrays(GL_TRIANGLES, 0, vertices.size()/3);


    glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);

    vertices.clear();
    textCoords.clear();
    normals.clear();

我在这里有什么额外的事情吗?因为这真的意味着比 glBegin()/End() 更有效率,对吧?

感谢您的宝贵时间和帮助!

【问题讨论】:

glBegin() 和 glEnd() 怎么样?我不擅长 OpenGL,但也许这会初始化一些存储顶点的内存? 由于我们看不到任何独立的示例,我们只能猜测,这导致我们可能(或 v2)MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j]; 导致错误的指针。由于我们看不到这一行中使用的值是如何存在的,所以我们无法猜测,只是可能有些东西未初始化。 我确实尝试过但无济于事...从我理解的缓冲区中绘制时不应该需要glBegin / End...但是感谢您的输入! 您是否尝试在启用所有警告和调试信息的情况下编译您的代码(在 Linux 上,这意味着 g++ -Wall -g)并调试您的程序(在 linux 上,使用 gdb 调试器,以及也许是ddd 的前端)? 不写入索引时会崩溃吗?您是否检查过您没有写超出索引的末尾(覆盖您的其他数据结构)? 【参考方案1】:

好的,让我们把它作为一个答案。猜测是:

当您不写入索引时它会崩溃吗?你检查过你 没有写超出索引的末尾(覆盖您的其他数据 结构)?

您的回复是,您创建了一个数组 GLfloat indices[],因为您事先不知道数组大小。

最好的(执行)解决方案是提前计算数组大小并适当地创建数组。

GLfloat *indices = new GLfloat[calculated_number_of_elements];
...use array...;
delete [] indices;

更好的是你可以创建一个 std::vector:

std::vector<GLfloat> indices(calculated_number_of_elements);

矢量还具有可以动态调整大小的优点。

【讨论】:

以上是关于奇数访问冲突读取错误/glDrawArrays 使用的主要内容,如果未能解决你的问题,请参考以下文章

访问冲突读取位置和错误读取字符串的字符

读取 gzip 的 zlib 错误时访问冲突

异常错误:访问冲突读取位置 0xDDDDDDDD

使用统一内存时 CUDA 中出现意外的读取访问冲突错误

访问冲突读取位置0x00000002 [关闭]

读取访问冲突 _First 为 nullPtr