Lwjgl 3 - difficulties trying to use VBO's

Intro, so I’ve spent a couple days trying to figure out the lwjgl 3 way of doing things with vbo’s. This being the first time I’m hearing a lot of the terminology isn’t making the resources/tutorials easy to understand. Nor do I want to begin at the very beginning, since I have a solid understanding of 3d rendering (though not of opengl or gpu’s). Also, though I would like to take the time to learn opengl thoroughly eventually, at the moment, I just want to get my little experiment working.

Previously, I had been using Java graphics2D to draw polygons; e.g., brush.drawPolygon(xy[0], xy[1], xy[0].length);

However, I was not happy with the 15fps it was dipping too when polygon count would reach 15-20k. So I decided to try out lwjgl. Here’s some code snippet I copied from a previous project before lwjgl 3 had come about, and was very happy with performance,
glColor3fv(color);
GL11.glBegin(GL11.GL_POLYGON);
for (byte i = 0; i < vertices.length; i += 2)
GL11.glVertex2d(vertices[i], vertices[i + 1]);
GL11.glEnd();

But for learning’s sake, I wanted to get a little familiar with the newer way of drawing in opengl. So I tried figuring out from tutorials and the online reference and eventually arrived at this working snippet (not included in the snippet is a glclear and glfwSwapBuffers that each happens once per frame):
glColor3fv(color);
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
int vboID = glGenBuffers();
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glDrawArrays(GL_QUADS, 0, vertices.length);

Unfortunately, this last snippet, was dropping painfully slow even at 1000 polygon count, which was disappointing, but also indicated that must not be the correct way of doing things.
I’m not sure if I can group up all my draw’s into 1 giant array and only call glDrawArrays once, since I think only the last glColor would then be applied to all the quads. Nor do I want to include the color per vertex, since doing so seems to require writing a shader or something, and that seems like overkill for my requirement.
Additionally, if it matters, vertexes are in 2D coordinates. I do the 3d -> 2d transformation and lighting -> color calculations with java+math rather than opengl. Hence my reluctance to write shaders or anything too complicated.

Thanks,

forget glColor3fv, it’s deprecated

this should be executed only once:

FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
int vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_DYNAMIC_DRAW);

and then in the loop

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glDrawArrays(GL_QUADS, 0, vertices.length);

If you need to change the vertices all together with the same transformation, you need to use matrices, otherwise bind again vboID and call glbufferSubData

It’s showing its age somewhat, but should be enough to get you started :point:

Thank you both. I’ll look at that intro and see what happens.

@Elect, just to clarify, you mean something like the following?

float[] accumulatedVerticies; // reset empty at beginning of each frame

void oncePerPolygon(float[] verticies) {
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glDrawArrays(GL_QUADS, 0, vertices.length);
// accumulatedVerticies = accumulatedVerticies . append . verticies;
}

void oncePerFrame() {
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(accumulatedVerticies.length);
verticesBuffer.put(vertices).flip();
int vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_DYNAMIC_DRAW);
}

If that’s what you mean (though I have a feeling I misunderstood you), I could just move all but the last line of the oncePerPolygon into the oncePerFrame, and just have the oncePerPolygon create append to the accumulatedVerticies, right?

Well, I just tried that, having the following execute once per frame:

		x = new LinkedList<>();
		
		// here i loop over polygons and add vertices to x.

		float[] y = new float[x.size()];
		for (int i = 0; i < y.length; i++)
			y[i] = x.get(i);
		
		FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(y.length);
		verticesBuffer.put(y).flip();
		int vboID = glGenBuffers();
		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, vboID);
		glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_DYNAMIC_DRAW);
		glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
		glDrawArrays(GL_QUADS, 0, y.length);
		
		glfwSwapBuffers(window);

And the result was the same 1-3 fps at just a 1000 polygon count.
Yes vertices change every frame, since these are not 3d world coordinates, but the 2d screen-projected coordinates.

You are creating a brand new vbo every frame, create the vbo once and update that vbo only if the data changes. By creating a new vbo every frame you are creating new memory blocks on the GPU every frame.

You are also creating a new FloatBuffer every frame. Don’t. Create it once and reuse it.

Remember a vbo is just a pointer to memory on the gpu that holds vertex data and the FloatBuffer is the memory the CPU uses to hold the data locally and update the GPU when necessary.

@abcdef, per your suggestion, I’ve moved the floatBuffer creation to once per execution instead of once per frame, and just do .clear each frame. Likewise moved the int vboID = glGenBuffers(); line to once per execution instead of per frame.

    // once per execution
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(1000 * 100 * 10);
int vboID = -1;

public void oncePerFrame() {
		x = new LinkedList<>();
		
		glClear(GL_COLOR_BUFFER_BIT);

     		// here i loop over polygons and add vertices to x.
		
		float[] y = new float[x.size()];
		for (int i = 0; i < y.length; i++)
			y[i] = x.get(i);
		
		if (vboID == -1) {  // once per execution
			vboID = glGenBuffers();
			glBindBuffer(GL_ARRAY_BUFFER, vboID);
		}

		verticesBuffer.clear();
		verticesBuffer.put(y).flip();
		glEnableVertexAttribArray(0);
		glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_DYNAMIC_DRAW);
		glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
		glDrawArrays(GL_QUADS, 0, y.length);
		
		glfwSwapBuffers(window);
	}

And did not see any improvements.

I feel bad for posting prior to having a chance to reading Riven your link, but just wanted to try and provide update on the suggestions. I’ll be reading that as my next step.

Can you define what you mean by once per execution and once per frame?

By once per execution, I mean it will execute on initialization or first frame, but no more.
By once per frame, I mean it will be executed on each iteration of the game/draw loop

Why are you updating every single vertex each frame?

Because I’m projecting the 3d world coordinates to 2d screen coordinates myself. Hence, since the camera moves every frame, the vertices will be modified as well.
Is this indicative that I’m approaching this the wrong way? I.e., if I’m modifying all vertices every frame, should I not be using vbo’s?

Aside: Never use Java’s LinkedList! And in any language, you’d never willingly use LinkedList::get(index), as the whole point of LinkedLists is that they are not random access.

Another aside: why project the 3D coordinates yourself when OpenGL can do this for you? Then you simply update the camera’s frustum matrix every frame instead, and the coordinates of your vertices never actually change.

Cas :slight_smile:

Thank you everyone for helping! :slight_smile:

@Riven, I followed the examples in that link, and got it to work. Thanks for the link :slight_smile:
@Elect Thanks for pointing that out, I’m now using colors the way those examples do rather than glColor3fv.
@Princec, those examples were just to show the results of attempting the suggestions, I converted the linked lists to arrays once I followed the link’s example and got the code to work. I will keep that 2nd aside in mind for future projects I do, but for this one, the majority of the project is to do the projection manually and only feed lwjgl the 2d screen coordinates.

Here’s the code that I put together closely following the link example,

			bufferLen = 0;
			colorLen = 0;
			glClear(GL_COLOR_BUFFER_BIT);
			painterQueue.paint(this); // this fills out vertexArray and colorArray, and increments bufferLen and colorLen
			painterQueue.drawReady = false; // to indicate to engine thread to we're ready to draw another frame
			
			vertexBuffer.clear();
			vertexBuffer.put(vertexArray).flip();
			colorBuffer.clear();
			colorBuffer.put(colorArray).flip();
			
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);
			
			glColorPointer(3, GL_FLOAT, 0, colorBuffer);
			glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
			glDrawArrays(GL_QUADS, 0, bufferLen / 2);
			
			glDisableClientState(GL_VERTEX_ARRAY);
			glDisableClientState(GL_COLOR_ARRAY);

			glfwSwapBuffers(window);