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

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 に答える
2

イミディエイト モードと頂点配列ベースのレンダリングを使用して、まったく同じ結果を得ることができます。あなたの画像は、法線が間違っていることを示唆しています。配列を作成するコードが含まれていないため、何が問題なのかを推測することしかできません。私が想像できることの1つは、三角形ごとに1つの法線を使用しているため、法線配列では、頂点ごとにその法線を繰り返す必要があることです。

GL の頂点は、位置 (glVertexイミディエイト モードで指定する) だけでなく、位置、法線、texcoords などのすべての属性のセットであることに注意してください。したがって、終点が異なる三角形の一部であるメッシュがある場合、位置だけでなくすべての属性が共有されている場合、これは 1 つの頂点にすぎません。あなたの場合、法線は三角形ごとであるため、三角形ごとに異なる頂点 (他のいくつかの頂点と位置を共有しますが、異なる法線を使用する) が必要になります。

于 2013-09-07T19:02:47.460 に答える