0

OpenGL ES 2.0 を使用して多数のオブジェクトを画面にレンダリングする iOS アプリを作成しています。現在、これらのオブジェクトは単純な形状 (正方形、球、円柱) です。

どのオブジェクトも互いに重なっていない場合、プログラムは 30 fps でスムーズに実行されます。

モデルの残りの部分の背後に表示されるオブジェクト (背景の四角形など) を追加すると、問題が発生します。背景の四角形を描画しようとすると、その前に画面の半分以下を占めるオブジェクトしか描画できません。それより大きいと、フレーム レートは 15 ~ 20 fps に低下します。

現状では、背景を含むすべてのモデルは次のコードで描画されます。

- (void)drawSingleModel:(Model *)model
{
    //Create a model transform matrix.
    CC3GLMatrix *modelView = [CC3GLMatrix matrix];

    //Transform model view
    // ...
    //Pass matrix to shader.
    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

    //Bind the correct buffers to openGL.
    glBindBuffer(GL_ARRAY_BUFFER, [model vertexBuffer]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [model indexBuffer]);
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);

    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));

    //Load vertex texture coordinate attributes into the texture buffer.
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, [model textureIndex]);
    glUniform1i(_textureUniform, 0);

    glDrawElements([model drawMode], [model numIndices], GL_UNSIGNED_SHORT, 0);
}

このコードは、次のように定義されている draw メソッドから呼び出されます。

- (void)draw
{
    glUseProgram(_programHandle);
    //Perform OpenGL rendering here.
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    _camera = [CC3GLMatrix matrix];

    //Camera orientation code.
    //...

    //Pass the camera matrix to the shader program.
    glUniformMatrix4fv(_projectionUniform, 1, 0, _camera.glMatrix);

    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    //Render the background.
    [self drawSingleModel:_background];

    //Render the objects.
    for(int x = 0; x < [_models count]; ++x)
    {
        [self drawSingleModel:[_models objectAtIndex:x]];
    }

    //Send the contents of the render buffer to the UI View.
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

レンダリング順序を次のように変更することで、次のことがわかりました。

    for(int x = 0; x < [_models count]; ++x)
    {
        [self drawSingleModel:[_models objectAtIndex:x]];
    } 
    [self drawSingleModel:_background];

背景の上にレンダリングするときの私のフレーム レートは 30 fps です。

もちろん、_models 内のオブジェクトを互いに前にレンダリングする必要がある場合、速度低下は依然として発生します。さらに、この順序でレンダリングすると、半透明オブジェクトと透明オブジェクトが黒く描画されます。

私はまだ OpenGL に慣れていないので、どこに問題があるのか​​よくわかりません。私の推測では、深度テストの実行速度が低下しているということです。また、モバイル デバイスで作業していることにも気付きました。しかし、iOS デバイスがこれを行うには遅すぎるとは信じられません。プログラムは、それぞれ約 180 個の三角形を持つ 5 つのモデルのみをレンダリングしています。

私が見ていないもの、またはこれに対する何らかの回避策はありますか? 提案や指針をいただければ幸いです。

4

2 に答える 2

3

モバイル GPU の特性の 1 つで実行しています。これらのもの (NVidia Tegra を除く) は、隠面消去の深度テストを行いません。iPad のものを含むほとんどのモバイル GPU は、タイル ベースのラスタライザーです。これは、メモリ アクセスが実際には電力を大量に消費する操作であるため、メモリ帯域幅を節約するためです。モバイル デバイスの電力が制限された環境では、必要なメモリ帯域幅を削減することで、バッテリ寿命が大幅に向上します。

タイル ベースのレンダラーは、ビューポートを多数のタイルに分割します。ジオメトリを送信すると、タイルに分割され、タイルごとに、タイル内に既にあるジオメトリと交差します。ほとんどの場合、タイルは 1 つのプリミティブだけで覆われています。入ってくるプリミティブがたまたま既存のジオメトリの前にある場合、それを置き換えます。切断交差がある場合、新しいエッジが追加されます。エッジ数が特定のしきい値に達した場合にのみ、その 1 つのタイルが深度テスト モードに切り替わります。

同期ポイントでのみ、準備されたタイルがラスタライズされます。

オブジェクトのオーバーラップがレンダリング パフォーマンスを低下させる理由は明らかです。プリミティブがオーバーラップするほど、タイルをセットアップするためにより多くの前処理を行う必要があります。

于 2013-01-18T11:21:24.530 に答える
1

透明度の並べ替え」/「アルファの並べ替え」を参照してください。

あなたが見ている遅さは主に「オーバードロー」、つまりフレームバッファのピクセルが複数回描画されていることが原因だと思います。深度テストは常にパスするため、シーンを前後に描画すると最悪です。iPhone 4/4S/5 には強力な GPU が搭載されている可能性がありますが、最後に確認したところ、メモリ帯域幅はかなりひどいものでした (GPU キャッシュの大きさはわかりません)。

前面から背面へレンダリングする場合、問題は、透明なピクセルがまだ深度バッファーに書き込まれ、その背後にあるポリゴンが遮られることです。アルファ テストを使用すると、これをわずかに (ただしわずかに) 減らすことができます。

簡単な解決策: 不透明なポリゴンをほぼ前から後ろにレンダリングし、次に透明なポリゴンを後ろから前にレンダリングします。これは、シーンに 2 つのパスを作成することを意味する場合があり、理想的には、透明なポリゴンを並べ替える必要がありますが、これは簡単ではありません。

すべてを前後にレンダリングし、宛先アルファでアルファ テストを実行することも (原則として) 可能だと思いますが、OpenGL がこれをサポートしているとは思いません。

于 2013-01-18T04:03:05.157 に答える