2

JOGL でインターリーブされた頂点配列 (VBO ではない) をレンダリングする適切な方法に関する情報が見つかりません。具体的には、glVertexAttribPointer() を使用すると、インターリーブされたデータ (FloatBuffer) 内のオフセットを指定できないようです。C、C++、または Objective-C では、これを行う方法を正確に知っていますが、Java では勝利への明確な道はないようです。

私が試した唯一のことは、glVertexAttribPointer() を使用する前にバッファの位置を設定することでしたが、これは効果がありませんでした。

わかりやすくするために、レンダリング関数のコードのサンプルを次に示します。

gl.glEnableVertexAttribArray( POSITION_ATTRIB );
gl.glEnableVertexAttribArray( NORMAL_ATTRIB );
gl.glVertexAttribPointer( POSITION_ATTRIB, 4, GL.GL_FLOAT, false, 32, vertexBuffer );
// vertexBuffer.position( 4 );  if I try to specify an offset
gl.glVertexAttribPointer( NORMAL_ATTRIB, 4, GL.GL_FLOAT, false, 32, vertexBuffer );
gl.glDrawArrays( GL.GL_TRIANGLES, 0, nummy );
gl.glDisableVertexAttribArray( NORMAL_ATTRIB );
gl.glDisableVertexAttribArray( POSITION_ATTRIB );

持っている属性ごとに 4 つのフロートを使用しています。に基づいて 32 のストライドを選択しました

float あたり 4 バイト * アトリビュートあたり 4 float * 頂点あたり 2 アトリビュート。

4

2 に答える 2

2

FloatBuffer の位置を設定しても目的の動作が得られない理由は、参照によって FloatBuffer を渡すためだと思います。基本的に同じデータの別のビューである別の FloatBuffer を作成し (たとえば、float [] をラップ)、この別のFloatBuffer の位置を 4 に設定することもできます...

例えば:

// Somewhere in your class
private float [] verts;


// You can fill this with actual data yourself, I did the hard part :P
verts = new float [] { 0.0f, 0.0f, 0.0f, 1.0f,     0.0f, 0.0f, 0.0f, 1.0f,
                       0.0f, 0.0f, 0.0f, 1.0f,     0.0f, 0.0f, 0.0f, 1.0f,
                       0.0f, 0.0f, 0.0f, 1.0f,     0.0f, 0.0f, 0.0f, 1.0f,
                       0.0f, 0.0f, 0.0f, 1.0f,     0.0f, 0.0f, 0.0f, 1.0f };
                    // ^^^^^^^^^ POS ^^^^^^^^      ^^^^^^^ NORMAL ^^^^^^^

//
// When it comes time to supply the vertex pointers, use this:
//
FloatBuffer vtx_base  = FloatBuffer.wrap (verts);
FloatBuffer norm_base = FloatBuffer.wrap (verts, 4, verts.length () - 4);

gl.glVertexAttribPointer (POSITION_ATTRIB, 4, GL.GL_FLOAT, false, 32, vtx_base);
gl.glVertexAttribPointer (NORMAL_ATTRIB,   4, GL.GL_FLOAT, false, 32, norm_base);

免責事項:私は何年も Java を使用していないので、そのままでコンパイルできるとは思わないでください。ただし、基本的な理論は健全なはずです。


4D 頂点の位置と法線が本当に必要なのか疑問に思う必要がありますか? には非常に実用的な用途がありwますが、実際に必要ない場合は、ストレージや帯域幅を節約して 3D を使用してください。VBO の代わりにクライアント メモリを使用すると、より多くの CPU から GPU へのメモリ転送が行われ、サイズの縮小が少しでも役立つため、これを取り上げます。

于 2013-09-06T23:16:28.437 に答える
1

私は少し行き詰まっていたので、Nathan が述べたように、OpenGL で必要なダイレクト バッファを使用した別のソリューションを共有しました。また、この例では、フロートをバイト/整数でインターリーブしています (色は 4 バイトで表されます)。

// vertex position: 3 floats; vertex color: 4 bytes 
static final int COORDS_PER_VERTEX = 4;
static final int VERTS_PER_SPRITE = 4;
static final int MAX_NUM_SPRITES = 1000;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private FloatBuffer vertexBuffer;
private ByteBuffer colorBuffer;
public void init() {
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 4 bytes per float)
            COORDS_PER_VERTEX * VERTS_PER_SPRITE * 4 * MAX_NUM_SPRITES);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    bb.position(3 * 4);
    colorBuffer = bb.slice();
}

さて、頂点を描くときは、

public void draw() {
    GLES20.glUseProgram(myProgram);
    // Enable a handle to the sprite vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    GLES20.glEnableVertexAttribArray(mColorHandle);
    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, 3,
            GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
    GLES20.glVertexAttribPointer(mColorHandle, 4,
            GLES20.GL_UNSIGNED_BYTE, false, vertexStride, colorBuffer);
    // Draw the sprites GL_SHORT DOES NOT WORK!!!! Use UNSIGNED_SHORT
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6 * numSprites, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
}

バッファを更新する必要がある場合は、float バッファのみを用意してから、4 つのカラー バイトを float に変換します。

private void updateSpriteBuffer() {
    float[] vData = new float[COORDS_PER_VERTEX * VERTS_PER_SPRITE * MAX_NUM_SPRITES];
    for (int i = 0; i<numSprites; i++) {
        // ... x, y, z
        byte[] colorBytes = sprite.getColorBytes(); // {r, g, b, 1}
        float colorAsFloat = ByteBuffer.wrap(colorBytes).order(ByteOrder.nativeOrder()).getFloat();
        for (int k = 0; k < 4; k++) {
            int j = COORDS_PER_VERTEX * 4 * i + COORDS_PER_VERTEX * k;
            vData[j] = x[k];
            vData[j + 1] = y[k];
            vData[j + 2] = z[k];
            vData[j + 3] = colorAsFloat;
        }
    }
    vertexBuffer.put(vData);
    vertexBuffer.position(0);
}

これが同じことをしようとしている他の誰かに役立つことを願っています。

于 2016-12-27T11:50:11.513 に答える