Bogdan Daniel Bogdan Daniel - 24 days ago 9
Android Question

Dynamically change vertex buffer data opengl

I have a point class which uses a buffer to draw some points. I would like to be able to change the content of what's being drawn(update the scene with new points). Recreating an entirely new object doesn't really sound good, so I've been trying to change the content of the buffer. Recently I found out about

, but I don't know how to use it.

Here is my point class:

public class Point {
private int mProgram, mPositionHandle, mColorHandle, mMVPMatrixHandle;
private FloatBuffer vertexBuffer,colorBuffer;
private static final int COORDS_PER_VERTEX = 3;
private static final int COORDS_PER_COLOR = 3;
private int vertexCount,colorCount;


private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute mediump vec4 vColor;" +
"varying mediump vec4 vaColor;" +
"void main() {" +
" vaColor = vColor;" +
" gl_Position = uMVPMatrix * vPosition;" +
" gl_PointSize = 20.0;" +
"}";

private final String fragmentShaderCode =
"precision mediump float;" +
"varying mediump vec4 vaColor;" +
"void main() {" +
" gl_FragColor = vaColor;" +
"}";


private static int vertexStride = COORDS_PER_VERTEX * 4;
private final int colorStride = COORDS_PER_COLOR * 4;


public Point(float pointCoords[],float colorCoords[]){
this.vertexCount = pointCoords.length / COORDS_PER_VERTEX;
this.colorCount = colorCoords.length / COORDS_PER_COLOR;

ByteBuffer vbb = ByteBuffer.allocateDirect(pointCoords.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(pointCoords);
vertexBuffer.position(0);



ByteBuffer cbb = ByteBuffer.allocateDirect(colorCoords.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colorCoords);
colorBuffer.position(0);


int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);

// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();

// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();

// add the vertex shader to program
GLES20.glAttachShader(mProgram, vertexShader);

// add the fragment shader to program
GLES20.glAttachShader(mProgram, fragmentShader);

// creates OpenGL ES program executables
GLES20.glLinkProgram(mProgram);
}

public void draw(float[] mvpMatrix) {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);

// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);

// Prepare the point coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);


mColorHandle = GLES20.glGetAttribLocation(mProgram,"vColor");

GLES20.glEnableVertexAttribArray(mColorHandle);
// Set color for drawing the triangle
GLES20.glVertexAttribPointer(mColorHandle, COORDS_PER_COLOR, GLES20.GL_FLOAT, false,
colorStride, colorBuffer);

// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

//TRANSLATION
float[] transMatrix = new float[16];

Matrix.setIdentityM(transMatrix,0);
Matrix.translateM(transMatrix,0,0.5f,0,0);
Matrix.multiplyMM(transMatrix,0,mvpMatrix,0,transMatrix,0);


// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexCount);

// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}

/**
* Change content of buffer
*/
public void changeBufferData(float[] newBufferInfo) {
GLES20.glBufferSubData(?,0,newBufferInfo.length*4,vertexBuffer);
}

}

Answer

You're currently using client-side vertex arrays with data uploaded per draw using glVertexAttribPointer. Updating this dynamically isn't going to be any more expensive than what you are already doing, as you are already having to allocate and copy data into driver owned memory for every draw operation.

However, as you say, recreating buffers is expensive so avoiding client-side vertex upload is highly recommended ...

The part you are missing is the need to create a Vertex Buffer Object (glGenBuffers, etc), which you can then use instead of client-side attributes. glBufferData and glSubBufferData are used to patch the contents of one of these buffer objects.

Comments