iOS中的OpenGL ES 2.0 - 多次调用glDrawElements导致EXC_BAD_ACCESS错误

4
几年前,我用Cocoa/Obj-C编写了一个小型的OpenGL ES 1.1和iPhone游戏框架。当时iOS 3.x很流行。我的OpenGL ES 1.1/iOS 3.x实现都可以正常工作。时间过去了,现在我们有了iOS 5.1、OpenGL ES 2.0、ARC、块等新技术。因此我决定将项目移植到更为现代化的标准上。
编辑:我已经自己解决了其中的一个问题——它在模拟器上崩溃的问题。某种程度上来说,我现在可以绘制较小的模型,但是较大的模型(例如测试警车)仍会导致EXC_BAD_ACCESS,即使这是唯一的glDrawElements调用。我还能够修复在模拟器上绘制多个网格的问题。然而,我不知道这是否可以在设备上运行,直到明天早上。 (我的5.0测试设备是我朋友的iPhone,所以...)。所以我想问的主要问题是,为什么在模拟器上会因为较大的模型导致EXC_BAD_ACCESS错误?
以下是原始帖子:
然而,在升级到iOS 5.0时,我遇到了一些OpenGL ES 2.0错误——具体来说是两个错误,尽管它们可能有关联。第一个错误很简单——如果我尝试在设备上渲染我的模型(iPhone 4S运行5.0.1),它可以正常显示,但如果我尝试在模拟器上显示它(iPhone模拟器运行5.0),它会在glDrawElements上抛出EXC_BAD_ACCESS。第二个错误也很简单,我不能绘制多个网格。当我将模型作为一个大组(一个顶点数组/索引数组组合)绘制时,它可以正常绘制,但是当我将模型作为多个部分(例如,多次调用drawElements)绘制时,它会失败并显示一个黑屏——黑色不是由正在绘制的模型造成的(我已经验证了这一点,在下面进行了概述)。
总之,在模拟器上尝试渲染我的模型会导致崩溃。
注意:对于小型网格,一切都正常。我没有问题重复地绘制我的小立方体,即使在模拟器上也是如此。当我说“模型”时,我指的是一个整体模型,可能由多个顶点和索引缓冲区组成。在代码中,这意味着“模型只是保存网格或模型组数组”的一个。网格或模型组是模型的子单元,例如模型的一个连续片段,具有一个顶点数组和一个索引数组,并存储两者的长度。在我使用的模型的情况下,汽车的主体是一个网格,窗户是另一个网格,灯是第三个网格。所有这些组合在一起,构成了整个模型。
我使用的模型是一辆警车,有数千个顶点和面,分为多个部分(车身、灯光、窗户等)-车身约有3000个面,窗户约有100个,灯光略少。
以下是需要注意的几点:
  1. My model is loading properly. I have verified this in two ways - printing out the model vertices and manually inspecting them, and displaying each model-group individually as outlined in 2). I'd post images, but 'reputation limit' and this being my first question, I can't. I have also re-built the model loader twice from scratch with no change, so I know the vertex and index buffers are in the correct order/format.

  2. When I load the model as a single model-group (ie, one vertex buffer/index buffer) it displays the whole model correctly. When I load the model as multiple model-groups, and display any given model-group individually, it displays correctly. When I try to draw multiple model-groups (multiple calls to glDrawElements) the big black screen happens.

  3. The black screen is not because of the model being drawn. I verified this by changing my fragment shader to draw every pixel red no matter what. I always clear the color buffer to a medium-gray (I clear the depth buffer as well, obviously), but attempting to draw multiple meshes/model-groups results in a black screen. We know it is not the model simply obscuring the view because it is colored black instead of red. This occurs on the device, I do not know what would happen on the simulator as I cannot get it to draw.

  4. My model will not draw in the simulator. It will not draw as either a single mesh/model-group, nor multiple mesh/model-groups. The application loads properly, but attempting to draw a mesh/model-group results in an EXC_BAD_ACCESS in the glDrawElements. The relevant parts of the backtrace are:

     thread #1: tid = 0x1f03, 0x10b002b5, stop reason = EXC_BAD_ACCESS (code=1, address=0x94fd020)
        frame #0: 0x10b002b5
        frame #1: 0x09744392 GLEngine`gleDrawArraysOrElements_ExecCore + 883
        frame #2: 0x09742a9b GLEngine`glDrawElements_ES2Exec + 505
        frame #3: 0x00f43c3c OpenGLES`glDrawElements + 64
        frame #4: 0x0001cb11 MochaARC`-[Mesh draw] + 177 at Mesh.m:81
    

    EDIT: It consistently is able to draw smaller dynamically-created models (~100 faces) but the 3000 of the whole model

  5. I was able to get it to render a much-smaller, less-complicated, but still dynamically loaded, model consisting of 192 faces / 576 vertices. I was able to display it both as a single vertex and index buffer, as well as split up into parts and rendered as multiple smaller vertex and index buffers. Attempting to draw the single-mesh model in the simulator resulted in the EXC_BAD_ACCESS still being thrown, but only on the first frame. If I force it to continue, it displays a very screwed up model, and then every frame after that, it displayed 100% fine exactly as it ought to have.

  6. My shaders are not in error. They compile and display correctly when I use a small, statically declared vertex buffer. However, for completeness I will post them at the bottom.


以下是我的代码:

渲染循环:

glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //muShader is a subclass of a shader-handler I've written that tracks the active shader
    //and handles attributes/uniforms
    //[muShader use] just does glUseProgram(muShader.program); then
    //disables the previous shader's attributes (if needed) and then
    //activates its own attributes - in this case:
    //it does:
    //    glEnableVertexAttribArray(self.position);
    //    glEnableVertexAttribArray(self.uv);
    //where position and uv are handles to the position and texture coordinate attributes
[self.muShader use];

GLKMatrix4 model = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(_rotation), 0, 1, 0);
GLKMatrix4 world = GLKMatrix4Identity;
GLKMatrix4 mvp = GLKMatrix4Multiply(_camera.projection, _camera.view);
mvp = GLKMatrix4Multiply(mvp,world);
mvp = GLKMatrix4Multiply(mvp, model);

    //muShader.modelViewProjection is a handle to the shader's model-view-projection matrix uniform
glUniformMatrix4fv(self.muShader.modelViewProjection,1,0,mvp.m);

glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, self.policeTextureID);
    //ditto on muShader.texture
glUniform1i(self.muShader.texture, 0);

for(int i=0; i < self.policeModel.count; i++)
{
        //I'll expand muShader readyForFormat after this
    [self.muShader readyForFormat:ModelVertexFormat];
        //I'll expand mesh draw after this
    [[self.policeModel meshAtIndex:i] draw];
}

muShader相关内容

muShader绑定属性和统一变量(uniforms)

我不会贴出整个muShader类的代码,这是不必要的,只需说明它正常工作即可,否则它将永远无法显示任何内容。

//here is where we bind the attribute locations when the shader is created
-(void)bindAttributeLocations
{
    _position = glGetAttribLocation(self.program, "position");
    _uv = glGetAttribLocation(self.program, "uv");
}
//ditto for uniforms
-(void)bindUniformLocations
{
    _modelViewProjection = glGetUniformLocation(self.program, "modelViewProjection");
    _texture = glGetUniformLocation(self.program, "texture");
}

muShader准备好格式化

-(void)readyForFormat:(VertexFormat)vertexFormat
{
    switch (vertexFormat)
    {
        //... extra vertex formats removed for brevity
        case ModelVertexFormat:

            //ModelVertex is a struct, with the following definition:
            //typedef struct{
            //    GLKVector4 position;
            //    GLKVector4 uv;
            //    GLKVector4 normal;
            //}ModelVertex;

            glVertexAttribPointer(_position, 3, GL_FLOAT, GL_FALSE, sizeof(ModelVertex), BUFFER_OFFSET(0));
            glVertexAttribPointer(_uv, 3, GL_FLOAT, GL_FALSE, sizeof(ModelVertex), BUFFER_OFFSET(16));
            break;
        //... extra vertex formats removed for brevity
    }
}

网格相关

设置顶点/索引缓冲区

//this is how I set/create the vertex buffer for a mesh/model-group
//vertices is a c-array of ModelVertex structs
//    created with malloc(count * sizeof(ModelVertex))
//    and freed using free(vertices) - after setVertices is called, of course
-(void)setVertices:(ModelVertex *)vertices count:(GLushort)count
{
    //frees previous data if necessary
    [self freeVertices];
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(ModelVertex) * count, vertices, GL_STATIC_DRAW);
    _vertexCount = count;

}
//this is how I set/create the index buffer for a mesh/model-group
//indices is a c-array of GLushort,
//    created with malloc(count * sizeof(GLushort);
//    and freed using free(vertices) - after setVertices is called, of course
-(void)setIndices:(GLushort *)indices count:(GLushort)count
{
    [self freeIndices];
    glGenBuffers(1, &_indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * count, indices, GL_STATIC_DRAW);
    _indexCount = count;
}

网格绘制
//vertexBuffer and indexBuffer are handles to a vertex/index buffer
//I have verified that they are loaded properly
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_SHORT, 0);

着色器相关

顶点着色器

attribute highp vec4 position;
attribute lowp vec3 uv;

varying lowp vec3 fragmentUV;

uniform highp mat4 modelViewProjection;
uniform lowp sampler2D texture;

void main()
{
    fragmentUV = uv;

    gl_Position = modelViewProjection * position;
}

片段着色器

varying lowp vec3 fragmentUV;

uniform highp mat4 modelViewProjection;
uniform lowp sampler2D texture;

void main()
{
    gl_FragColor = texture2D(texture,fragmentUV.xy);
    //used below instead to test the aforementioned black screen by setting
    //every pixel of the model being drawn to red
    //the screen stayed black, so the model wasn't covering the whole screen or anything
    //gl_FragColor = vec4(1,0,0,1);
}
1个回答

8

我自己找到了答案,当使用多个缓冲区对象时,必须在绑定顶点/索引缓冲区对象时为每个缓冲区对象调用glEnableVertexAttribArray函数,而不是在每帧(每个着色器)中仅调用一次。这是所有问题的根本原因,包括模拟器崩溃。

已关闭。


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