GLES20 为什么纹理数据不与顶点索引链接?

GLES20 Why texture data is not linked with vertices indexes?

我试图渲染一个立方体并在所有面上应用单一纹理。 以及通过传递面部顶点的索引来使用尽可能少的顶点。示例:

顶点:

static final float FACE_VERTEX[] = {
        // front
        0.0f,  1.0f, 1.0f,     //0
        0.0f, 0.0f, 1.0f,     //1
        1.0f, 0.0f, 1.0f,      //2
        1.0f,  1.0f, 1.0f,      //3

        //back
        1.0f,  1.0f, 0.0f,      //4 - 3
        1.0f, 0.0f, 0.0f,      //5 - 2
        0.0f, 0.0f, 0.0f,     //6 - 1
        0.0f,  1.0f, 0.0f,     //7 - 0
}; 

索引:

static final int FACE_INDEX[] = {
        //front
        0,1,2, 0,2,3,
        //back
        4,5,6, 4,6,7,

        //left
        7,6,1, 7,1,0,

        //right
        3,2,5, 3,5,4,

        //top
        4,7,0, 4,0,3,

        //bottom
        1,6,5, 1,5,2

};

纹理映射数据:

final int textureCoordinateData[] =
        {
                // Front face
                0,0, 0,1, 1,1, 1,0,
                //back
                0,0, 0,1, 1,1, 1,0,
                //left
                0,0, 0,1, 1,1, 1,0,
                //right
                0,0, 0,1, 1,1, 1,0,
                //top
                0,0, 0,1, 1,1, 1,0,
                //bottom
                0,0, 0,1, 1,1, 1,0,
                //top
                0,0, 0,1, 1,1, 1,0,
                //bottom
                0,0, 0,1, 1,1, 1,0,


        };

纹理在立方体的所有面渲染,顶部和底部除外。只有正面的第一行像素沿着整个顶面和底面渲染(见截图):

我正在使用 VBO 将 vertex/index/texture 数据存储在 GPU 中,并使用

进行渲染
glDrawElements(GL_TRIANGLES, indexLength, GL_UNSIGNED_INT, 0);

但是这个问题是因为纹理数据应该映射到传递的顶点数据(这对于立方体模型来说有点烦人)并且不是通过索引计算的。

我的问题是: - 有什么方法可以使顶点数据尽可能少并将纹理映射到索引数据吗? - 如果我创建 36 个顶点(有些重复)来解决纹理映射问题,但我创建了正确的索引来渲染立方体,它仍然比使用 glDrawArrays 更快吗?还是我应该使用 glDrawArrays 并丢弃索引数据?

相关问题(没有回答我的问题):

OpenGL ES - texture map all faces of an 8 vertex cube?

如果您阅读了对答案的第一条评论:

What do you mean you have to use 24 vertexes? If you have to duplicate the vertexes what is the point of using an index buffer then if you are still sending repeat data to the GPU?

确实没有合理的方法来绘制纹理坐标小于24个顶点的立方体。那是因为...它有 24 个顶点,当使用 OpenGL 中形成顶点的定义时,这是顶点属性(位置、纹理坐标、法线等)的每个唯一组合。

您可以仅使用位置和纹理坐标来稍微减少数量,因为在您的情况下纹理坐标只是 0 和 1 值的组合。如果您不关心每个面上纹理的方向,例如,您可以有 1 个顶点使用 (0, 0) 作为所有 3 个相邻面的纹理坐标。当然你不能对所有的顶点都这样做,但是你可以 trim 稍微减少顶点的数量。

那么使用索引值得吗?正如您现在已经发现的那样,在使用索引时您可以轻松地坚持使用 24 个顶点,但需要 36 个顶点最直接地使用 glDrawArrays(),其中您使用单个绘制调用 GL_TRIANGLES 作为基元类型。所以它确实减少了顶点的数量。

您也可以使用 glDrawArrays() 将其减少到 24 个顶点,如果您为每个面调用单独的绘制调用,并使用每个具有 4 个顶点的 GL_TRIANGLE_STRIP 基元类型绘制面。但是,这将导致 6 个绘制调用,并且也不希望有许多小的绘制调用。

即使在多维数据集的情况下看起来有问题,索引缓冲区通常也非常有用。立方体是如此小而简单的形状,您发送顶点的方式无论如何都不会有太大的不同。

在大多数用例中,您将拥有更复杂的形状,以及更多通常定义光滑表面的顶点。在这种情况下,相同的顶点(具有相同的法线和纹理坐标)主要由多个三角形共享。绘制常规网格的一部分:

_____________
|  /|  /|  /|
| / | / | / |
|/__|/__|/__|
|  /|  /|  /|
| / | / | / |
|/__|/__|/__|

你可以看到内部顶点由 6 个三角形共享。因此,对于相对较大的平滑表面,您通常可以通过共享顶点将顶点数量减少大约 6 倍,这正是使用索引数组可以做到的。如果您的几何体足够大,将内存使用量减少近 6 倍可能是一个可观的收益。