Frage

I'm drawing some objects with OpenGL ES 2.0, and each vertex has several attributes which, as recommended for best performance, I'm storing interleaved in a single buffer. Some of these (like position) are represented with floats (GLES20.GL_FLOAT), but I'm passing in a color, and it's wasteful of memory to pass the color attribute as four float components so I'd like to use GLES20.GL_UNSIGNED_BYTE. Four of these will pack into one 32 bit field. However I can't figure out an easy way of storing these in ByteBuffers. E.g. using GL_FLOAT for the colours I'd do the following:

    void addVertex(float xpos, float ypos, int color) {
        floatBuffer.put(xpos);
        floatBuffer.put(ypos);
        floatBuffer.put(Color.red(color) / 255f);
        floatBuffer.put(Color.green(color) / 255f);
        floatBuffer.put(Color.blue(color) / 255f);
        floatBuffer.put(Color.alpha(color) / 255f);
    }

This works, but I'm using 128 bits to represent a colour that could be represented in 32, which will also cause a performance hit. So what I'd like to do is create a ByteBuffer and use asFloatBuffer() to create an alias to it and use whichever is appropriate for the type being stored. Like so:

    void addVertices() {
        byteBuffer = ByteBuffer.allocateDirect(vertexCount * VERTEX_STRIDE).order(ByteOrder.nativeOrder());
        floatBuffer = byteBuffer.asFloatBuffer();

        for(Vertex v : vertices)
            addVertex(v.x, v.y, v.color);
    }

    void addVertex(float xpos, float ypos, int color) {
        floatBuffer.put(xpos);
        floatBuffer.put(ypos);
        byteBuffer.put(Color.red(color));
        byteBuffer.put(Color.green(color));
        byteBuffer.put(Color.blue(color));
        byteBuffer.put(Color.alpha(color));        }

However this won't work because asFloatBuffer() creates a FloatBuffer that shares the underlying storage of the ByteBuffer, but maintains its own position index. I'd have to manually track the position and update each one before storing anything, which is ugly.

I could also split the attributes into separate buffers, but the performance penalty for that would probably outweigh the gain.

Any ideas on how to do this in an elegant, efficient manner?

War es hilfreich?

Lösung

ByteBuffer has additional methods that can be used to put other data types besides byte into the buffer, in a machine-independent way. So instead of wrapping the ByteBuffer in a FloatBuffer, use the ByteBuffer directly, and use putFloat() to append the float values:

void addVertex(float xpos, float ypos, int color) {
    byteBuffer.putFloat(xpos);
    byteBuffer.putFloat(ypos);
    byteBuffer.put((byte)Color.red(color));
    byteBuffer.put((byte)Color.green(color));
    byteBuffer.put((byte)Color.blue(color));
    byteBuffer.put((byte)Color.alpha(color));     
}

Andere Tipps

You could either pack the color into one float and put that into the float buffer, or split the position into bytes and put them into the byte buffer.

As an example, here's how to do the former:

Assuming 0-255 ints, first pack them into one int:

int colorBits = a << 24 | b << 16 | g << 8 | r;

then make that into a float:

float floatColor = Float.intBitsToFloat(colorBits);
floatBuffer.put(floatColor);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top