OpenGL ES 2.0绘制多个纹理

6
我的问题可能很简单,我正在使用OpenGL ES 2.0绘制简单的2D场景。
我有一个背景纹理,它覆盖整个屏幕,还有另一个在特定位置绘制的花朵纹理(或者我应该说是精灵?)。

所以,我想到的最简单方法是两次调用glDrawArrays,一次用于背景纹理的顶点,另一次用于花朵纹理的顶点。

这是正确的方法吗?如果是,那么对于10朵花,我需要调用glDrawArrays 10次吗?

关于混合怎么办?如果我想要将花与背景混合,我需要同时获得背景和花的像素颜色,这可能会带来问题,对吧?

还是说可以在一个绘制中完成?如果可以,那么我应该如何创建一个着色器,知道当前处理的是背景纹理顶点还是花纹理顶点?

或者说可以在一个绘制中完成吗?

一个绘制的问题在于着色器需要知道当前顶点是背景顶点(然后使用背景纹理颜色)还是花纹理顶点(然后使用花纹理颜色),我不知道该如何做到。

下面是如何使用一次绘制调用来绘制覆盖整个屏幕的背景图像和半大小、居中的花朵。

- (void)renderOnce {
    //... set program, clear color..

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, backgroundTexture);
    glUniform1i(backgroundTextureUniform, 2);

    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, flowerTexture);
    glUniform1i(flowerTextureUniform, 3);

    static const GLfloat allVertices[] = {
        -1.0f, -1.0f, // background texture coordinates
        1.0f, -1.0f,  // to draw in whole screen
        -1.0f,  1.0f, //
        1.0f,  1.0f,

        -0.5f, -0.5f, // flower texture coordinates
        0.5f, -0.5f,  // to draw half screen size
        -0.5f,  0.5f, // and centered
        0.5f,  0.5f,  //
    };

    // both background and flower texture coords use the whole texture
    static const GLfloat backgroundTextureCoordinates[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
    };

    static const GLfloat flowerTextureCoordinates[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
    };

    glVertexAttribPointer(positionAttribute, 2, GL_FLOAT, 0, 0, allVertices);
    glVertexAttribPointer(backgroundTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, backgroundTextureCoordinates);
    glVertexAttribPointer(flowerTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, flowerTextureCoordinates);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
1个回答

5
你有两个选择:
  1. 为每个你想要绘制的纹理调用 glDrawArrays,如果你有超过10-20个纹理,这将会很慢。但是,你可以使用硬件vbo来加速它。
  2. 将所有你想要绘制的精灵的顶点(顶点、纹理坐标、颜色)批处理到一个数组中,然后使用一个贴图集(一张图片包含了你想要绘制的所有图片),通过一个 glDrawArrays 绘制出来。
第二种方法显然更好,也是正确的。要了解如何执行它,请查看我的答案这里

谢谢你的回复,我已经更新了我的答案,并附上了一个使用一次绘制调用的示例。我的问题是如何构建一个能够读取正确背景/花朵顶点颜色的着色器。你能帮忙看一下吗? - Eyal
我有点困惑,那么我应该怎样去做你建议的事情(选项2)? - Eyal
如果你真的想在单个绘制调用中完成它,你可以在你的VBO中存储要使用的纹理的ID(为每个顶点复制相同的ID)。这是完全可能的,但不是很实际。假设你有一个动画精灵,你可以通过绑定10个纹理并选择要在着色器内采样的纹理来实现它。更好的方法是将帧打包到一个纹理中。同样,正如SteveL所说,你可以创建一个包含背景和花朵的纹理集。然后使用纹理坐标来决定纹理,而不是使用ID。 - jozxyqk
1
@Eyal,如果您想使用不同的着色器,则唯一的选择是为每个不同的着色器调用glDrawArrays。因此,正确的方法是:1)绘制背景(使用背景着色器而不进行批处理,如果您只有一个背景)2)批处理并绘制所有花朵(使用花朵着色器)。 - SteveL
@Eyal,另一种处理背景顶点和花朵顶点的不同方法是类似于jozxyqk建议的做法,在VBO中存储你正在绘制的内容(背景或花朵)的ID,并在你的着色器中使用类似这样的if语句:if(id==0)backgroundShader();else if(id==1)flowerShader()。但这是一个我永远不会使用的解决方案,为每个不同的着色器调用glDrawArrays一次比使用复杂的着色器要快得多。希望我的评论没有让你更加困惑。 - SteveL
显示剩余3条评论

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