13

頂点配列を使用して適度に単純な形状を作成する作業を行っており、順調に進んでいますが、今は 2 つ (またはそれ以上) の三角形ファン オブジェクトを描画したいと考えています。1 回だけ電話をかける方法はありますか、gl.glDrawArrays(GL.GL_TRIANGLE_FAN,...それともファンごとに個別に電話をかける必要がありますか?

ウィキペディアのトライアングル ストリップの記事では、プリミティブ リスタートと呼ばれるものについて説明していますが、OpenGL のVertex Specificationを見ると、これは頂点配列では機能しないと思われます。

複数の三角扇子の正しい描き方は?これが私の現在の描画方法です:

public void draw(GL gl){
if(vertices.length == 0)
    return;

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL.GL_COLOR_ARRAY);
    gl.glEnableClientState(GL.GL_NORMAL_ARRAY);

    gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertBuff);
    gl.glColorPointer(3, GL.GL_FLOAT, 0, colorBuff);
    gl.glNormalPointer(GL.GL_FLOAT,0, normalBuff);

    // drawArrays count is num of points, not indices.
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, triangleCount);
    gl.glDrawArrays(GL.GL_QUADS, triangleCount, quadCount);
    gl.glDrawArrays(GL.GL_TRIANGLE_FAN, triangleCount+quadCount, fanCount);

    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL.GL_COLOR_ARRAY);
    gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
}

編集

draw の関連セクションを次のように更新しました。

    for(int i = 0; i < fanLength.length; i++){
        gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 
            triangleCount+quadCount+fanDist[i], fanLength[i]);
    }

ここで、fanDist はこのファンの始点の (ファンの始点からの) オフセットであり、fanLength はこのファンの長さです。

これはうまくいくようですが、それでもこれは正しい方法ですか? より良い方法はありますか?

4

1 に答える 1

19

プリミティブ リスタートは、頂点配列と頂点バッファーで機能します。機能しない場合は、あまり役に立ちません。

ただし、 と組み合わせて使用​​すると役に立たないのは事実ですglDrawArrays

2 つのテクニックを見てみましょう。

プリミティブ リスタート


紹介さglDrawElementsせてください:次のような呼び出し

glDrawArrays(mode, 0, 5);

に類似している

GLuint idxs[] = {0, 1, 2, 3, 4}; // C code, but idea's the same in Java
glDrawElements(mode, 5, GL_UNSIGNED_INT, idxs);

したがって、配列から描画する要素の範囲を指定する代わりに、それらの要素の正確なインデックスを指定します。

そして、そのような配列を使用してプリミティブ再起動を導入できます。

GLuint PRIMITIVE_RESTART = 12345; // magic value

glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(PRIMITIVE_RESTART);
GLuint idxs[] = {0, 1, 2, 3, PRIMITIVE_RESTART, 4, 5, 6, 7};
glDrawElements(mode, 9, GL_UNSIGNED_INT, idxs);

これにより、最初の 4 つの頂点からファンが描画され、プリミティブを再起動する「記号」に遭遇し、最後の 4 つの頂点から別のファンが描画されます。

DrawElements に渡されるインデックスは、連続した範囲である必要はありません! それらは任意の順序にすることができ、必要に応じて繰り返すことができます。これがこの関数の最も優れた部分です。実際、1 つのインデックスをできるだけ頻繁に再利用することをお勧めします。これは、結果がキャッシュされている場合、頂点シェーダーによって 1 回だけ処理されるためです。したがって、次のようなバッファを自由に作成できます。

GLuint idxs[] = {0, 6, 3, 4, 6, 2, PRIMITIVE_RESTART, 2, 6, 3, 3, 5, 2}; // etc.

MultiDrawElements


あなたの場合、代わりに使用したいかもしれませんglMultiDrawElements

たとえば、20 個の頂点があり、最初から 8 個の頂点からなる 1 つのファンと、10 番目から始まる 10 個の頂点からなる 1 つのファンを描きたい場合は、次のようにすることができます。

// assuming glVertexPointer is already set
GLuint startingElements[] = {0, 9};
GLuint counts[] = {8, 10};
glMultiDrawArrays(GL_TRIANGLE_FAN, startingElements, counts, 2); // 2 fans

したがって、行う作業が少し少なくなります。


より役立つと思われる手法を選択してください。Java/JOGL の書き直しはあなたに任せます。原則は同じですが、Bufferそれらすべてにクラスを使用する必要があると思います。

于 2010-12-08T12:19:33.877 に答える