0

我正在编写一个 iOS 应用程序,使用 OpenGL ES 2.0 将许多对象呈现到屏幕上。目前,这些对象是简单的形状(正方形、球体和圆柱体)。

当没有对象相互重叠时,程序以 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 设备太慢了,无法做到这一点。该程序仅渲染 5 个模型,每个模型大约有 180 个三角形。

有什么我没有看到的,或者有什么解决方法吗?任何建议或指示将不胜感激。

4

2 回答 2

3

您正在使用移动 GPU 的特性之一:这些东西(NVidia Tegra 除外)不会对隐藏表面移除进行深度测试。大多数移动 GPU,包括 iPad 中的 GPU,都是基于 tile 的光栅化器。这样做的原因是为了节省内存带宽,因为内存访问实际上是一个耗电的操作。在移动设备的功率受限环境中,减少所需的内存带宽可显着延长电池寿命。

基于图块的渲染器将视口拆分为多个图块。将几何图形发送到其中时,它会被拆分为图块,然后对于每个图块,它与图块中已经存在的几何图形相交。大多数情况下,图块仅被一个图元覆盖。如果传入的图元恰好在已经存在的几何体之前,它将替换它。如果存在切割交叉点,则会添加新边。只有当边缘数量达到某个阈值时,该单个图块才会切换到深度测试模式。

然后,仅在同步点对准备好的图块进行光栅化。

现在很明显为什么重叠对象会降低渲染性能:基元重叠越多,设置图块所需的预处理就越多。

于 2013-01-18T11:21:24.530 回答
1

参见“透明度排序”/“阿尔法排序”。

我怀疑您看到的缓慢主要是由于“过度绘制”,即帧缓冲区像素被多次绘制。当您从后到前绘制场景时,这是最糟糕的,因为深度测试总是通过。虽然 iPhone 4/4S/5 可能有一个强大的 GPU,但最后我检查了内存带宽非常糟糕(我不知道 GPU 缓存有多大)。

如果你从前到后渲染,问题是透明像素仍然写入深度缓冲区,导致它们遮挡它们后面的多边形。您可以使用 alpha 测试稍微减少(但只是稍微)。

简单的解决方案:大致从前到后渲染不透明多边形,然后从后到前渲染透明多边形。这可能意味着要通过您的场景两次,理想情况下,您希望对透明多边形进行排序,这并不容易做好。

我认为(原则上)也可以从前到后渲染所有内容并在目标 alpha 上执行 alpha 测试,但我认为 OpenGL 不支持这一点。

于 2013-01-18T04:03:05.157 回答