4

数年前、私はOpenGLES1.1とiPhone用の小さなCocoa/Obj-Cゲームフレームワークを作成しました。これは、iOS3.xが普及したときに戻ってきました。これの私のOpenGLES1.1 /iOS3.x実装はすべて正常に機能しました。時が経ち、iOS 5.1、OpenGL ES 2.0、ARC、ブロックなどが登場しました。私は、プロジェクトをより多くの...最新の標準に移植する時期が来たと判断しました。

編集:私自身で問題の1つを解決しました-それがシミュレーターでクラッシュした理由の問題です。ある種-私は今では小さなモデルを描くことができますが、大きなモデル(テストパトカーのような)はまだEXC_BAD_ACCESSを引き起こします-それがglDrawElementsへの唯一の単一の呼び出しであるとしても。シミュレーターで複数のメッシュを描画することも修正できましたが、これがデバイス上で機能するかどうかは明日の朝までわかりません。(私の5.0テストデバイスは私の友人のiPhoneですが、そうではありません)。だから私は主な質問は、なぜ大きなモデルがシミュレーターでEXC_BAD_ACCESSを引き起こすのかということだと思います。

以下の元の投稿

ただし、5.0に移行する際に、いくつかのOpenGL ES 2.0エラーが発生しました。具体的には2つですが、関連している可能性があります。最初のものは単純です-デバイス(5.0.1を実行しているiPhone 4S)でモデルをレンダリングしようとすると表示されますが、シミュレーター(5.0を実行しているiPhone Simulator)で表示しようとすると、EXC_BAD_ACCESSがスローされますglDrawElementsで。第二に、これも簡単です。複数のメッシュを描画できません。モデルを1つの大きなグループ(1つの頂点配列/インデックス配列の組み合わせ)として描画すると、うまく描画されますが、モデルを複数のパーツ(たとえば、drawElementsへの複数の呼び出し)として描画すると、失敗し、大きな黒い画面が表示されます-黒さは、描画されているモデルによるものではありません(これを確認しました。以下に概説します)。

非常に詳細な部分の前に要約すると、シミュレータでモデルをレンダリングしようとするとクラッシュします

警告:小さなメッシュではすべて正常に機能します。シミュレーター上でも、静的に宣言された小さな立方体を何度も何度も描画することに問題はありません。静的に宣言されたとは、頂点バッファーにバインドされてロードされる構造体のハードコードされたconst配列と、インデックス配列にバインドされてロードされるGLushortsのconst配列を意味します。

注:「モデル」とは、モデル全体を意味し、複数の頂点バッファーとインデックスバッファーで構成されている可能性があります。コードでは、これはモデルがメッシュまたはモデルグループの配列を単に保持することを意味します。メッシュまたはモデルグループは、モデルのサブユニットです。たとえば、モデルの1つの連続した部分は、1つの頂点配列と1つのインデックス配列を持ち、両方の長さも格納します。私が使用しているモデルの場合、車のボディは1つのメッシュ、窓は別のメッシュ、ライトは3分の1です。一緒に、それらはモデルを構成します。

私が使用しているモデルはパトカーで、数千の頂点と面があり、複数の部分(ボディ、ライト、ウィンドウなど)に分割されています-ボディは約3000面、ウィンドウは約100、ライトは少し少ないです。

知っておくべきことがいくつかあります。

  1. モデルが正しく読み込まれています。これを2つの方法で検証しました。モデルの頂点を印刷して手動で検査する方法と、2)で概説したように各モデルグループを個別に表示する方法です。画像を投稿したいのですが、「評判の限界」とこれが私の最初の質問なので、できません。また、モデルローダーを最初から2回変更せずに再構築したので、頂点バッファーとインデックスバッファーが正しい順序/形式になっていることがわかります。

  2. モデルを単一のモデルグループ(つまり、1つの頂点バッファー/インデックスバッファー)としてロードすると、モデル全体が正しく表示されます。モデルを複数のモデルグループとしてロードし、特定のモデルグループを個別に表示すると、正しく表示されます。複数のモデルグループ(glDrawElementsへの複数の呼び出し)を描画しようとすると、大きな黒い画面が表示されます。

  3. 黒い画面は、モデルが描画されているためではありません。フラグメントシェーダーを変更して、 何があってもすべてのピクセルを赤く描画することで、これを確認しました。私は常にカラーバッファをミディアムグレーにクリアします(もちろん、デプスバッファもクリアします)が、複数のメッシュ/モデルグループを描画しようとすると黒い画面になります。赤ではなく黒に着色されているため、単にビューを覆い隠しているモデルではないことがわかります。これはデバイスで発生します。シミュレータを描画できないため、シミュレータで何が発生するかわかりません。

  4. 私のモデルはシミュレーターで描画しません。単一のメッシュ/モデルグループとしても、複数のメッシュ/モデルグループとしても描画されません。アプリケーションは正しくロードされますが、メッシュ/モデルグループを描画しようとすると、glDrawElementsにEXC_BAD_ACCESSが発生します。バックトレースの関連部分は次のとおりです。

     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
    

    編集:それは一貫してより小さな動的に作成されたモデル(〜100面)を描くことができますが、モデル全体の3000

  5. 192の面/576の頂点で構成される、はるかに小さく、複雑ではないが、動的にロードされるモデルをレンダリングすることができました。単一の頂点とインデックスバッファの両方として表示することも、パーツに分割して複数の小さな頂点とインデックスバッファとしてレンダリングすることもできました。シミュレータでシングルメッシュモデルを描画しようとすると、EXC_BAD_ACCESSが引き続きスローされますが、最初のフレームでのみスローされます。強制的に続行すると、非常にめちゃくちゃなモデルが表示され、その後のすべてのフレームで、本来あるべき状態とまったく同じように100%きれいに表示されます。

  6. 私のシェーダーはエラーではありません。静的に宣言された小さな頂点バッファを使用すると、正しくコンパイルおよび表示されます。ただし、完全を期すために、下部に投稿します。


私のコードは次のとおりです。

レンダリングループ:

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バインディング属性とユニフォーム

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

muShaderreadyForFormat

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

1 に答える 1

8

自分で答えると、複数のバッファオブジェクトを使用する場合、フレームごと(シェーダーごと)に1回だけではなく、頂点/インデックスバッファオブジェクトをバインドするたびにglEnableVertexAttribArrayを呼び出す必要があります。これが、シミュレーターのクラッシュを含むすべての問題の原因でした。

閉まっている。

于 2012-05-11T16:18:05.660 に答える