I am trying to render large VBO array objects, containing ~700000 values and I have ~1500000 values in my element_array buffer. But what I am getting is a blank screen. On the other hand if I just use only the VAO, my code works correctly. My code is as follows:
//Data buffers
FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(this.coordCount);
vertexBuffer.put(Vertices);
vertexBuffer.rewind();
IntBuffer indexBuffer = GLBuffers.newDirectIntBuffer(this.indexCount);
indexBuffer.put(index);
indexBuffer.rewind();
//setting up the VBO
int nVBO = 2;
int[] VBO = new int[nVBO];
gl.glGenBuffers(nVBO, VBO,0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBO[0]);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER,VBO[1]);
gl.glBufferData(GL.GL_ARRAY_BUFFER, this.coordCount*Float.SIZE, vertexBuffer, GL.GL_STATIC_DRAW);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, this.indexCount*Integer.SIZE, indexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBO[0]);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, VBO[1]);
gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
//gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
//gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
gl.glDrawElements(GL.GL_TRIANGLES, this.indexCount, GL.GL_UNSIGNED_INT, 0);
//gl.glDrawElements(GL.GL_TRIANGLES, this.indexCount, GL.GL_UNSIGNED_INT, indexBuffer);
gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
Any clues/suggestions on how I can fix this?
Is this code block called each time when the loop runs? If it is, you should divide your vbo phases into different blocks.This sample code may help you how to divide. (In the link that I post, you should just focus initVBO and renderVbo functions) I guess your initializing your vbo's sequentially, which it may make your program unresponsive.
Related
I am looking for help with understanding VBOs. I have done a ton of research and have found tutorials on the subject, but they are still vague to me. I have a few questions:
Where should a VBO be created, and how should I create one?
I am currently using the code right below to initialize my vertex and index buffers:
vertices = new float[]
{
p[0].x, p[0].y, 0.0f,
p[1].x, p[1].y, 0.0f,
p[2].x, p[2].y, 0.0f,
p[3].x, p[3].y, 0.0f,
};
// The order of vertex rendering for a quad
indices = new short[] {0, 1, 2, 0, 2, 3};
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(indices);
drawListBuffer.position(0);
If I am correct, this is not creating a VBO. So, if I wanted to make a VBO, would the code to create a VBO go right after the code listed above? If so, how would it be created?
Also, how is a VBO rendered and drawn to screen?
Is it rendered and drawn the same way as just using vertex and index arrays? If not, what is the process? Currently, I render and draw my objects as shown in the code below:
GLES20.glUseProgram(GraphicTools.sp_SolidColor);
mPositionHandle =
GLES20.glGetAttribLocation(GraphicTools.sp_SolidColor, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
mtrxHandle = GLES20.glGetUniformLocation(GraphicTools.sp_SolidColor,
"uMVPMatrix");
GLES20.glUniformMatrix4fv(mtrxHandle, 1, false, m, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
If you have any questions, let me know. Thanks in advance.
A Vertex Buffer Object is a buffer where vertex array data can be stored. The data are uploaded one time to the graphics memory (GPU) and can be used repeatedly to draw a mesh.
First you have to create 2 buffer objects, one for the vertices and one for the indices:
int buffers[] = new int[2];
GLES20.glGenBuffers(2, buffers, 0);
int vbo = buffers[0];
int ibo = buffers[1];
Then you have to bind the buffer and to transfer the data
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);
GLES20.glBufferData(
GLES20.GL_ARRAY_BUFFER,
vertexBuffer.capacity() * 4, // 4 = bytes per float
vertexBuffer,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo);
GLES20.glBufferData(
GLES20.GL_ELEMENT_ARRAY_BUFFER,
drawListBuffer.capacity() * 2, // 2 = bytes per short
drawListBuffer,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
If you want to draw the mesh, then you have to define the array of generic vertex attribute data and you have to bind the index buffer, but you don't have to transfer any data to the GPU:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);
GLES20.glVertexAttribPointer(
mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, 0); // <----- 0, because "vbo" is bound
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo);
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, 0); // <----- 0, because "ibo" is bound
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
See also An Introduction to Vertex Buffer Objects (VBOs)
I am trying to use VAOs to render and am having trouble with incorrect rendering.
I do have a little experience in the subject but not a huge amount.
This is my binding Code:
//RawModel is just a type to store vao id and number of indices.
public RawModel loadToVao(float[] positions, int[] indices){
//create VAO and bind it
int vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
//create index buffer
int indexVBO = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexVBO);
IntBuffer indexBuffer = BufferUtils.createIntBuffer(indices.length);
indexBuffer.put(indices);
indexBuffer.flip();
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer , GL15.GL_STATIC_DRAW);
//create vertex buffer
int positionVBO = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, positionVBO);
FloatBuffer vertBuffer = BufferUtils.createFloatBuffer(positions.length);
vertBuffer.put(positions);
vertBuffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertBuffer , GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
return new RawModel(vaoID, indices.length);
}
This is my render code:
GL30.glBindVertexArray(obj.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_POINTS, 0, sphere.getRawModel().getSize());
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, sphere.getRawModel().getSize());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
I render both points and Triangles just to see what is going wrong. eventually will only be triangles.
This code always seems to give me a point at the objects centre which should not be there. It also has incorrect grouping of elements so triangles render completely wrong.
If anyone could help it would be great.
Thanks
I have managed to get a cube rendered in OpenGL using a VBO. My next goal is actually creating a for loop to create multiple cubes. I'm stuck on this part though, do I put this code:
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vertexBufferID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
GL11.glDrawArrays(GL11.GL_QUADS, 0, 24);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
Into a for loop? Wouldn't I have to use some sort of glPopMatrix command along with a translate function? I barely understand how to create one cube in a VBO, so sorry if its obvious whats wrong.
You can use the following way:
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vertexBufferID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
for (int i = 0; i < cubeCount; i++) {
GL11.glPushMatrix();
// do translation/rotation for cube no i
GL11.glDrawArrays(GL11.GL_QUADS, 0, 24);
GL11.glPopMatrix();
}
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
Please note that the glPushMatrix/glPopMatrix way is deprecated in newer openGl versions. For you it should work because you are using GL11.
I've been following the tutorials http://www.learnopengles.com and learning more how to work with OpenGL ES but I'm having a hard time trying to get a sphere to show up.
I've went ahead and made a geodesic sphere in Blender and imported the vertices and the draw order but I whenever I call the sphere the app crashes.
I'll include a link to my full render file but I'll also point out what I think some of the key things where I think problems might be:
Here is where the buffers are created. I'm not sure if the app has issues with the way I'm buffering the sphere or the sphere's draw order points.
// Initialize the buffers.
mCubePositions = ByteBuffer.allocateDirect(cubePositionData.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubePositions.put(cubePositionData).position(0);
mSpherePositions = ByteBuffer.allocateDirect(spherePositionData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mSpherePositions.put(spherePositionData).position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(sphereDrawOrder.length * 2).order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(sphereDrawOrder);
drawListBuffer.position(0);
mCubeColors = ByteBuffer.allocateDirect(cubeColorData.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeColors.put(cubeColorData).position(0);
mCubeNormals = ByteBuffer.allocateDirect(cubeNormalData.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeNormals.put(cubeNormalData).position(0);
And here is the class that draws the sphere. I have no colors or normals for the sphere so I just removed those parts. Is that what's causing it to freak out?
private void drawSphere()
{
// Pass in the position information
mSpherePositions.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
0, mSpherePositions);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
// Pass in the normal information
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
// Draw the sphere.
GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphereDrawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
}
Whenever it crashes it tells me there's something wrong with the code after //Draw the sphere. It doesn't like the glDrawElements for some reason.
Here is the full render script for reference: http://pastebin.com/Y1WU27hz
If you have any insight to this I thank you.
EDIT: Solved it! I made stupid mistake, I had a textureId I'd forgotten about when it was textureID I should use.
Okay, I am fully aware that this is a recurring question, and that there is a lot of tutorials and open source code. But I've been trying as best as I can for quite a while here, and my screen is still blank (with whatever color I set using glClearColor()).
So, I would be grateful for some pointers to what I'm doing wrong, or even better, some working code that will render a resource image.
I'll show what I've got so far (by doing some crafty copy-pasting) in my onDrawFrame of the class that implements the Renderer. I've removed some of the jumping between methods, and will simply paste it in the order it is executed.
Feel free to disregard my current code, I'm more than happy to start over, if anyone can give me a working piece of code.
Setup:
bitmap = BitmapFactory.decodeResource(panel.getResources(),
R.drawable.test);
addGameComponent(new MeleeAttackComponent());
// Mapping coordinates for the vertices
float textureCoordinates[] = { 0.0f, 2.0f, //
2.0f, 2.0f, //
0.0f, 0.0f, //
2.0f, 0.0f, //
};
short[] indices = new short[] { 0, 1, 2, 1, 3, 2 };
float[] vertices = new float[] { -0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f };
setIndices(indices);
setVertices(vertices);
setTextureCoordinates(textureCoordinates);
protected void setVertices(float[] vertices) {
// a float is 4 bytes, therefore we multiply the number if
// vertices with 4.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
mVerticesBuffer = vbb.asFloatBuffer();
mVerticesBuffer.put(vertices);
mVerticesBuffer.position(0);
}
protected void setIndices(short[] indices) {
// short is 2 bytes, therefore we multiply the number if
// vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
mIndicesBuffer = ibb.asShortBuffer();
mIndicesBuffer.put(indices);
mIndicesBuffer.position(0);
mNumOfIndices = indices.length;
}
protected void setTextureCoordinates(float[] textureCoords) {
// float is 4 bytes, therefore we multiply the number of
// vertices with 4.
ByteBuffer byteBuf = ByteBuffer
.allocateDirect(textureCoords.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
mTextureBuffer = byteBuf.asFloatBuffer();
mTextureBuffer.put(textureCoords);
mTextureBuffer.position(0);
}
//The onDrawFrame(GL10 gl)
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -4);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);
if(shoudlLoadTexture){
loadGLTextures(gl);
shoudlLoadTexture = false;
}
if (mTextureId != -1 && mTextureBuffer != null) {
gl.glEnable(GL10.GL_TEXTURE_2D);
// Enable the texture state
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Point to our buffers
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
}
gl.glTranslatef(posX, posY, 0);
// Point out the where the color buffer is.
gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndicesBuffer);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
if (mTextureId != -1 && mTextureBuffer != null) {
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
private void loadGLTextures(GL10 gl) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
mTextureID = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
}
It doesn't crash, no exceptions, simply a blank screen with color. I've printed stuff in there, so I'm pretty sure it is all executed.
I know it's not optimal to just paste code, but at the moment, I just want to be able to do what I was able to do with canvas :)
Thanks a lot
If you're getting the background colour, that means your window is properly set up. OpenGL is connected to that area of the screen.
However, OpenGL clips to the near and far clip planes, ensuring that objects don't cross or intersect the camera (which, both mathematically and logically, doesn't make sense) and that objects too far away don't appear. So if you've not set up modelview and projection correctly, it's probable that all your geometry is being clipped.
Modelview is used to map from world to eye space. Projection maps from eye space to screen space. So a typical applications uses the former to position objects within the scene, and position the scene relative to the camera, then the latter deals with whether the camera sees with perspective or not, how many world units make how many screen units, etc.
If you look at examples like this one, particularly onSurfaceChanged, you'll see an example of a perspective projection with a camera fixed at the origin.
Because the camera is at (0, 0, 0), leaving your geometry on z = 0 as your code does will cause it to be clipped. In that example code they've set the near clip plane to be at z = 0.1, so in your existing code you could change:
gl.glTranslatef(posX, posY, 0);
To:
gl.glTranslatef(posX, posY, -1.0);
To push your geometry back sufficiently far to appear on screen.