1

I'm working for the first time on a 3D project (actually, I'm programming a Bullet Physics integration in a Quartz Composer plug-in), and as I try to optimize my rendering method, I began to use glDrawElements instead of the direct access to vertices by glVertex3d...

I'm very surprised by the result. I didn't check if it is actually quicker, but I tried on this very simple scene below. And, from my point of view, the rendering is really better in immediate mode.

The "draw elements" method keep showing the edges of the triangles and a very ugly shadow on the cube.

I would really appreciate some information on this difference, and may be a way to keep quality with glDrawElements. I'm aware that it could really be a mistake of mines...

Immediate mode enter image description here

DrawElements enter image description here

The vertices, indices and normals are computed the same way in the two method. Here are the 2 codes.

Immediate mode

glBegin (GL_TRIANGLES);
    int si=36;
    for (int i=0;i<si;i+=3)
    {
        const btVector3& v1 = verticesArray[indicesArray[i]];;
        const btVector3& v2 = verticesArray[indicesArray[i+1]];
        const btVector3& v3 = verticesArray[indicesArray[i+2]];


        btVector3 normal = (v1-v3).cross(v1-v2);
        normal.normalize ();
        glNormal3f(-normal.getX(),-normal.getY(),-normal.getZ());
        glVertex3f (v1.x(), v1.y(), v1.z());
        glVertex3f (v2.x(), v2.y(), v2.z());
        glVertex3f (v3.x(), v3.y(), v3.z());

    }
    glEnd();

glDrawElements

glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, sizeof(btVector3), &(normalsArray[0].getX()));
    glVertexPointer(3, GL_FLOAT, sizeof(btVector3), &(verticesArray[0].getX()));
    glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_BYTE, indicesArray);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

Thank you.

EDIT

Here is the code for the vertices / indices / normals

GLubyte indicesArray[] = {
        0,1,2,
        3,2,1,
        4,0,6,
        6,0,2,
        5,1,4,
        4,1,0,
        7,3,1,
        7,1,5,
        5,4,7,
        7,4,6,
        7,2,3,
        7,6,2 };

    btVector3 verticesArray[] = {
        btVector3(halfExtent[0], halfExtent[1], halfExtent[2]),
        btVector3(-halfExtent[0], halfExtent[1], halfExtent[2]),
        btVector3(halfExtent[0], -halfExtent[1], halfExtent[2]),
        btVector3(-halfExtent[0], -halfExtent[1], halfExtent[2]),
        btVector3(halfExtent[0], halfExtent[1], -halfExtent[2]),
        btVector3(-halfExtent[0], halfExtent[1], -halfExtent[2]),
        btVector3(halfExtent[0], -halfExtent[1], -halfExtent[2]),
        btVector3(-halfExtent[0], -halfExtent[1], -halfExtent[2])
    };

    indicesCount = sizeof(indicesArray);
    verticesCount = sizeof(verticesArray);


    btVector3 normalsArray[verticesCount];

    int j = 0;
    for (int i = 0; i < verticesCount * 3; i += 3)
    {
        const btVector3& v1 = verticesArray[indicesArray[i]];;
        const btVector3& v2 = verticesArray[indicesArray[i+1]];
        const btVector3& v3 = verticesArray[indicesArray[i+2]];

        btVector3 normal = (v1-v3).cross(v1-v2);
        normal.normalize ();

        normalsArray[j] = btVector3(-normal.getX(), -normal.getY(), -normal.getZ());

        j++;
    }
4

2 回答 2

2

您可以(并且将)使用即时模式和基于顶点数组的渲染获得完全相同的结果。您的图像表明您的法线错误。由于您没有包含用于创建数组的代码,我只能猜测可能出了什么问题。我可以想象的一件事:每个三角形使用一个法线,因此在法线数组中,您必须为每个顶点重复该法线。

您应该知道,GL 中的顶点不仅仅是位置(您glVertex在立即模式下通过它指定),而是所有属性的集合,如位置、法线、texcoords 等。因此,如果您有一个端点是不同三角形的一部分的网格,那么如果所有属性都是共享的,那么这只是一个顶点,而不仅仅是位置。在您的情况下,法线是每个三角形的,因此每个三角形需要不同的顶点(与其他一些顶点共享位置,但使用不同的法线)。

于 2013-09-07T19:02:47.460 回答
2

我开始使用 glDrawElements

好的!

而不是 glVertex3d 直接访问顶点...

立即模式没有什么“直接”的。事实上,它离 GPU 尽可能远(在现代 GPU 架构上)。

我对结果感到非常惊讶。我没有检查它是否真的更快,但我尝试了下面这个非常简单的场景。而且,从我的角度来看,直接访问方法的渲染效果确实更好。

实际上它慢了几个数量级。每个 glVertex 调用都会导致上下文切换的开销。此外,GPU 需要更大量的数据才能高效工作,因此 glVertex 调用首先填充临时创建的缓冲区。

您的直接代码段必须实际理解如下

    glNormal3f(-normal.getX(),-normal.getY(),-normal.getZ());
    glVertex3f (v1.x(), v1.y(), v1.z());

    // implicit copy of the glNormal supplied above
    glVertex3f (v2.x(), v2.y(), v2.z());

    // implicit copy of the glNormal supplied above
    glVertex3f (v3.x(), v3.y(), v3.z());

这样做的原因是,顶点不仅仅是一个位置,而是它的属性的整体组合。并且在使用顶点数组时,您必须提供完整的属性向量以形成有效的顶点。

于 2013-09-07T19:54:29.793 回答