PDA

View Full Version : Efficient Drawing with Open GL ES 2.0 (Android)



Ainigma
07-27-2017, 08:24 AM
Hi folks,

I'm new to the OpenGL paradigm. I want to draw building/room data with OpenGL. The data will be read out of a database (in the future), but for now it's hard coded like that:

elements.add(new EleWall(2f,0,2f,0,0,2f));
elements.add(new EleRoom (1f,1f,2f,2f));

Explanation:
elements -> ArrayList<Ele>
Ele -> Ele is an abstract Class that represents an Object with Data (like FloatBuffer and ShortBuffer for vertices and faces)
EleWall -> extends Ele, generates a 3D-Object (see below the functions "populateVertices()" and "populateFaces()", start and end is a own written class named CustomVector (x,y,z as floats))
World -> a class that holds all Ele objects in an ArrayList<Ele> called elements

World's draw-method:

public void draw(){
rot.set(VectorManager.rot.x,VectorManager.rot.y,Ve ctorManager.rot.z);
GLES20.glLineWidth(20f);
GLES20.glEnableVertexAttribArray(position);
GLES20.glUseProgram(program);
position = GLES20.glGetAttribLocation(program, "position");
setMatrix();
for (Ele e : elements){
e.program = program;
e.draw();
}

GLES20.glUseProgram(blackProgram);
position = GLES20.glGetAttribLocation(blackProgram, "position");
setMatrix();
arrow.program = blackProgram;
arrow.drawFull();

GLES20.glDisableVertexAttribArray(position);
}

EleWall's draw-method:

public void draw(){
try {
GLES20.glEnableVertexAttribArray(position);
GLES20.glVertexAttribPointer(position,3, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 12 * 3 , GLES20.GL_UNSIGNED_SHORT, facesBuffer);
Log.d("Eerey",String.valueOf(getAmountFaces()));
GLES20.glDisableVertexAttribArray(position);
}catch (Exception e){
Log.d("Eerey",e.toString() + " [Wall Problem]");

}
}


Now when I do this:

for (int i = 0;i<1500;i++){
addRandomRoom();
}
before rendering (a room consists of 4 walls) it becomes insanely slow, ~1FPS i guess.

What am I doing wrong?
Is it the right way to store new Objects as an Object and call it individually to draw it?
Or is it ineffective to call those 1500x4 Objects's buffers? Should I store it in just one buffer?
Wouldn't it be quite unmanagable after i did that?
What if I want to rotate an object in my elements-ArrayList?
Do i have to walk through the clumped verticesBuffer and fiddle the right coordinates out of it?
This seems crazy, - but what is right?
What is efficient?

I'd love to hear your experience or your critique.


EleWall generation code:

public void populateVertices(){
verticesBuffer.put((float)start.x- Constants.wallThickness/2);
verticesBuffer.put((float)start.y);
verticesBuffer.put((float)start.z- Constants.wallThickness/2);

verticesBuffer.put((float)end.x- Constants.wallThickness/2);
verticesBuffer.put((float)end.y);
verticesBuffer.put((float)end.z- Constants.wallThickness/2);

verticesBuffer.put((float)end.x+ Constants.wallThickness/2);
verticesBuffer.put((float)end.y);
verticesBuffer.put((float)end.z+ Constants.wallThickness/2);

verticesBuffer.put((float)start.x+ Constants.wallThickness/2);
verticesBuffer.put((float)start.y);
verticesBuffer.put((float)start.z+ Constants.wallThickness/2);

//top
verticesBuffer.put((float)start.x+ Constants.wallThickness/2);
verticesBuffer.put((float)start.y+ Constants.wallHeight);
verticesBuffer.put((float)start.z+ Constants.wallThickness/2);

verticesBuffer.put((float)end.x+ Constants.wallThickness/2);
verticesBuffer.put((float)end.y+ Constants.wallHeight);
verticesBuffer.put((float)end.z+ Constants.wallThickness/2);

verticesBuffer.put((float)end.x- Constants.wallThickness/2);
verticesBuffer.put((float)end.y+ Constants.wallHeight);
verticesBuffer.put((float)end.z- Constants.wallThickness/2);

verticesBuffer.put((float)start.x- Constants.wallThickness/2);
verticesBuffer.put((float)start.y+ Constants.wallHeight);
verticesBuffer.put((float)start.z- Constants.wallThickness/2);

verticesBuffer.position(0);
// verticesBuffer.rewind();
}
public void populateFaces(){
//Bottom
facesBuffer.put((short)0);
facesBuffer.put((short)1);
facesBuffer.put((short)2);

facesBuffer.put((short)0);
facesBuffer.put((short)2);
facesBuffer.put((short)3);

//Top
facesBuffer.put((short)4);
facesBuffer.put((short)5);
facesBuffer.put((short)6);

facesBuffer.put((short)4);
facesBuffer.put((short)6);
facesBuffer.put((short)7);

//LSide
facesBuffer.put((short)0);
facesBuffer.put((short)7);
facesBuffer.put((short)6);

facesBuffer.put((short)0);
facesBuffer.put((short)1);
facesBuffer.put((short)6);

//RSide
facesBuffer.put((short)2);
facesBuffer.put((short)3);
facesBuffer.put((short)5);

facesBuffer.put((short)2);
facesBuffer.put((short)3);
facesBuffer.put((short)4);

//Front
facesBuffer.put((short)0);
facesBuffer.put((short)3);
facesBuffer.put((short)7);

facesBuffer.put((short)3);
facesBuffer.put((short)4);
facesBuffer.put((short)7);

//Back
facesBuffer.put((short)1);
facesBuffer.put((short)2);
facesBuffer.put((short)6);

facesBuffer.put((short)2);
facesBuffer.put((short)6);
facesBuffer.put((short)5);
facesBuffer.position(0);

}

Dark Photon
07-27-2017, 08:52 PM
Now when I do this:

for (int i = 0;i<1500;i++){
addRandomRoom();
}
before rendering (a room consists of 4 walls) it becomes insanely slow, ~1FPS i guess.

What am I doing wrong?

You didn't actually show us addRandomRoom(). Let's start with that. That may point to the smoking gun.


Pending that, here are some thoughts...

What happens if you pre-create all of the rooms on startup, and then at draw time just draw them?

How many bytes of vertex data and index data are you providing to GL to draw those 1500 rooms?

You're currently using client arrays for your draw calls (i.e. "not" using GL buffer objects), so you're re-feeding the room data to GL again and again every frame. Try uploading it all to GL buffer object(s) on startup and then launch your draw calls using these buffer objects. That should greatly cut down on the amount of data your app needs to push through the GL driver to the GPU.

How many draw calls are you using to draw the rooms? If more than 1, try drawing them all with 1 draw call (that is, put all the vertex data for the rooms in one block, and all the index data for the rooms in another block; then, launch a single draw call to draw them all).

mhagain
07-28-2017, 01:04 AM
What happens if you remove your logging? Hitting the disk for each object drawn is never going to be fast; that's the first thing I'd consider.