Opengles 2.0 multiple vertex buffers vs one buffer.

Started by
6 comments, last by dgi 8 years, 5 months ago

Hi guys I wanted to get your opinion on this.

I currently thought of making multiple classes each one will have a prepare and draw method. To prepare and render staff to screen.
The draw method has multiple glDraw() calls as it binds a texture and draws a part of the object binds next texture draw another part etc.. (I am aware this is quiet expensive but I maximum have 3 textures)
the draw method will be used by some base class which will call the corresponding draw method on every object.
(The code should make more sense than this sentence :) )

Now the problem is that when I start creating multiple objects should If I just concatenate them into one big buffer
which should increase performance I will end up with restricted number of vertices because of
"glDrawElements(GL_TRIANGLES, Index, GL_UNSIGNED_SHORT, 0);" GL_UNSIGNED_SHORT -> only 65,535 vertices for all objects.... If however I keep the multiple draw calls I can have max 65,535 per object or am I being optimistic and the phone will just crash ??

RenderShip.cpp(some object with methods Draw and PrepareGraphics)



void RenderShip::PrepareGraphics(std::string textureFilename, std::string modelFilename)
{
	GLuint textureHandle;

	std::vector<GLfloat> rawData;

	objMtlLoader meshLoader;
	data = meshLoader.LoadFromFile(modelFilename);

     GLfloat * RawGraphicsData = data->GetRawArrayofValues(true, false);

	 IndexPerTexture = data->IndxsPrTxtHndl(programId);

	std::vector<unsigned short> Indexes; // cannot be more than 15 textures any way

	std::vector<glm::vec3> * Vertices = data->GetVertices();

	CenterMatrix = ModelPositioning::CenterModel(*Vertices);

	indexes = data->getIndexes();

	indexSize = data->GetIndexSize();


	GLint FragmentShaderTextureId;
	GLint VertexId;
	VertexId = glGetAttribLocation(programId, "position");

	FragmentShaderTextureId = glGetAttribLocation(programId, "vertexUV");
	glEnable(GL_DEPTH_TEST);

	GLuint myBuffId = 0;

	glGenBuffers(1, &myBuffId);

	glEnableVertexAttribArray(VertexId);

	glBindBuffer(GL_ARRAY_BUFFER, myBuffId);

	glBufferData(GL_ARRAY_BUFFER, indexSize * 5 * sizeof(float), RawGraphicsData, GL_STATIC_DRAW);

	glVertexAttribPointer(VertexId, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);

	GLuint IndexBuffId = 0;
	glGenBuffers(1, &IndexBuffId);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffId);

	glEnableVertexAttribArray(FragmentShaderTextureId);

	glVertexAttribPointer(FragmentShaderTextureId, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (char *)(sizeof(float) * 3));  // stride of 5 floats describing my colors starting at position 2

}


void RenderShip::DrawShip()
{
	glm::mat4 ModelViewProject(1.0f);
	glm::mat4 View(1.0f);
	glm::mat4 Model(1.0f);


	glm::mat4 Projection = glm::perspective(45.0f, 1024.0f / 768.0f, 0.1f, 15.0f);

	Model = CenterMatrix;

	ModelViewProject = Projection * camera->getWorldToViewMatrix() *  Model;

	GLint transform = glGetUniformLocation(programId, "ModelViewProject");

	glUniformMatrix4fv(transform, 1, false, glm::value_ptr(ModelViewProject));;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

	GLuint IndexBuffId = 0;
	glGenBuffers(1, &IndexBuffId);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffId);

	GLuint textureHandle;

	for (std::map<GLuint, size_t>::iterator it = IndexPerTexture.begin(); it != IndexPerTexture.end(); it++)
	{
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, it->second * sizeof(GLfloat), indexes, GL_DYNAMIC_DRAW);
		glBindTexture(GL_TEXTURE_2D, it->first); // Bind that texture temporarily
		glActiveTexture(it->first);

		glDrawElements(GL_TRIANGLES, it->second, GL_UNSIGNED_SHORT, 0);
	}


}


Renderer.cpp (Base class which will call draw on all objects)


#include "Renderer.h"
#include "RenderShip.h"
#pragma once

GLuint programId;

int program;


RenderShip * ship;


void Renderer::Prepare()
{
	 programId = InstallShaders();

	SendDataToOpenGL();
}

void Renderer::Render()
{
	ship->DrawShip();
}

void Renderer::SetCamera(Camera& cam)
{
	camera = &cam;
}


void Renderer::SendDataToOpenGL()
{
	ship = new RenderShip(programId, (*camera));

	ship->PrepareGraphics("textureWood.bmp", "untitled.obj");

}

int Renderer::InstallShaders()
{
	return  ShaderHandler::InstallShaders();
}

Advertisement
I can't speak from experience, but I wouldn't expect much of a performance gain by combining multiple objects into a single vertex buffer. Plus, I would only start looking for ways to optimize code once you know you have a performance problem and have identified the bottleneck.
My current game project Platform RPG

Having less draw calls is faster , but this approach is very inflexable , hard to manage and scale.

I can't speak from experience, but I wouldn't expect much of a performance gain by combining multiple objects into a single vertex buffer. Plus, I would only start looking for ways to optimize code once you know you have a performance problem and have identified the bottleneck.

I agree yet that means restructuring all the classes and the design of the engine which will take a considerate amount of time.

Having less draw calls is faster , but this approach is very inflexable , hard to manage and scale.

Do you know how much faster, and is it worth it? If it`s 5% faster than yeh I probably would not bother but if it`s a good 20%-30% performance increase than something should be done.

Having less draw calls is faster , but this approach is very inflexable , hard to manage and scale.

Do you know how much faster, and is it worth it? If it`s 5% faster than yeh I probably would not bother but if it`s a good 20%-30% performance increase than something should be done.

It's all about trades , if you can live with messy code do it like that.


Having less draw calls is faster , but this approach is very inflexable , hard to manage and scale.



Having 1 vertex buffer vs multi-buffer does not imply 1 drawcall. The only thing derivation from that is 1 buffer binding. Since, if the op is not using a single render state ( texture, material, GL state or whatnot ), then multiple draw call will still be required.

II would profile to see how much if any gains would be achieved from doing so like others have already mentioned.


Having less draw calls is faster , but this approach is very inflexable , hard to manage and scale.


Having 1 vertex buffer vs multi-buffer does not imply 1 drawcall. The only thing derivation from that is 1 buffer binding. Since, if the op is not using a single render state ( texture, material, GL state or whatnot ), then multiple draw call will still be required.

II would profile to see how much if any gains would be achieved from doing so like others have already mentioned.

I said less not one :)

This topic is closed to new replies.

Advertisement