Hi,
Last week I jumped back in OpenGL and I wanted to worked on a project I have never finished. The project is about displaying a terrain generated with perlin noise and display some objects over it.
When I was working on this project I created a c++ API that will go through all my objects (by using the vertex array) and then considering their position from the camera I display them or not. What I did is that I used GL_DYNAMIC_DRAW in order to bind my buffers before drawing with only the object I wanted to draw (I also use this mechanism to move my objetcs).
But I figured out that testing the distance from the camera of each object of my vertex array is very slow and causes a big impact in the runtime (CPU side).
But as I have a lot of objects to be rendered if I do not do that it has a big impact GPU side.
So I was wondering if it exists a way to only display objects that are near the camera.
The other limitation is that the terrain should be rendered even far from the camera.
Camera :
glm::mat4 view = glm::lookAt(glm::vec3(x, y, z), glm::vec3(x + directionx, y + directiony, z + directionz), glm::vec3(0, 1, 0));
glm::mat4 proj = glm::perspective(yfov, xfov, znear,zfar);
glUniformMatrix4fv(get_uni_loc(programId, "projection"), 1, false, glm::value_ptr(proj));
glUniformMatrix4fv(get_uni_loc(programId, "modelview"), 1, false, glm::value_ptr(view));
Vertex shader :
#version 330 core
layout (location = 0) in vec3 positions;
layout (location = 1) in vec3 normals;
//Varying
out vec3 coord3d;
out vec3 realCoord3d;
flat out vec3 normal;
out vec3 light;
out vec2 tex_coord;
//Uniform
uniform mat4 modelview;
uniform mat4 projection;
uniform vec4 translation;
uniform vec3 rotation;
vec3 light_pos = vec3(100.0f,200.0f,100.0f);
mat4 rotationx = mat4(1,0,0,0,
0,cos(rotation.x),-sin(rotation.x),0,
0,sin(rotation.x),cos(rotation.x),0,
0,0,0,1);
mat4 rotationy =mat4(
cos(rotation.y),0,sin(rotation.y),0,
0,1,0,0,
-sin(rotation.y),0,cos(rotation.y),0,
0,0,0,1);;
mat4 rotationz = mat4(cos(rotation.z),-sin(rotation.z),0,0,
sin(rotation.z),cos(rotation.z),0,0,
0,0,1,0,
0,0,0,1);;
void main(){
coord3d = positions;
mat4 view = modelview;
vec4 p = view * (vec4(positions,1.0f)*rotationx*rotationy*rotationz + translation);
realCoord3d = positions;
p = projection * p;
normal = normals;
light = light_pos;
gl_Position = p;
The way I render :
void Renderer::initBillboard(Billboard& object) {
//Vertex array buffer generation
glGenBuffers(1, &object.vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, object.vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, (object.nbBillboards)* 36 * sizeof(float), nullptr, GL_STATIC_DRAW);
//Index array buffer generation
glGenBuffers(1, &object.indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object.nbBillboards * 6 * sizeof(int), nullptr, GL_STATIC_DRAW);
}
void Renderer::renderBillboard(Billboard& object, GLuint programId, GLuint texture) {
glDisable(GL_POLYGON_OFFSET_FILL);
PRINT_OPENGL_ERROR();
glUseProgram(programId);
PRINT_OPENGL_ERROR();
updateBillboard(object);
PRINT_OPENGL_ERROR();
//Buffer binding
//glGenVertexArrays(1, &object.VAO);
//glBindVertexArray(object.VAO);
glBindBuffer(GL_ARRAY_BUFFER, object.vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.indexBuffer);
//Attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), buffer_offset(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), buffer_offset(6 * sizeof(float)));
glEnableVertexAttribArray(2);
//Uniform
PRINT_OPENGL_ERROR();
float c[4]{ 0.0f,0.0f,0.0f,0.0f };
glUniform4fv(get_uni_loc(programId, "color"), 1, c);
glUniform3fv(get_uni_loc(programId, "rotation"), 1, object.rotation);
glUniform4fv(get_uni_loc(programId, "translation"), 1, object.translate);
GLuint text_id = glGetUniformLocation(programId, "texture");
glUniform1i(text_id, texture);
PRINT_OPENGL_ERROR();
//Draw
glDrawElements(GL_TRIANGLES, 6 * object.nbBillboards, GL_UNSIGNED_INT, nullptr);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
//glDeleteBuffers(1,&object.vertexBuffer);
//glDeleteBuffers(1, &object.indexBuffer);
}
void Renderer::updateBillboard(Billboard& object) {
//Vertex array buffer update
glBindBuffer(GL_ARRAY_BUFFER, object.vertexBuffer);// PRINT_OPENGL_ERROR();
glBufferSubData(GL_ARRAY_BUFFER,0, (object.nbBillboards) * 36 * sizeof(float), &object.vertexArray[0]);
//index array buffer update
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.indexBuffer);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, object.nbBillboards * 6 * sizeof(int), &object.indexArray[0]);
}
//Terrains
void Renderer::initTerrain(Terrain& object) {
//Vertex array buffer generation
glGenBuffers(1, &object.vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, object.vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, object.nbSquares * 24 * sizeof(float), &object.vertexArray[0], GL_DYNAMIC_DRAW);
//Index array buffer generation
glGenBuffers(1, &object.indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object.nbSquares * 6 * sizeof(int), &object.indexArray[0], GL_DYNAMIC_DRAW);
}
void Renderer::renderTerrain(Terrain& object, GLuint programId,GLuint texture) {
glDisable(GL_POLYGON_OFFSET_FILL);
glUseProgram(programId);
//Buffer binding
//glGenVertexArrays(1, &object.VAO);
//glBindVertexArray(object.VAO);
glBindBuffer(GL_ARRAY_BUFFER, object.vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.indexBuffer);
//Attrib pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), buffer_offset(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//Uniform
float c[4]{ object.color.x,object.color.y,object.color.z,object.alpha };
//PRINT_OPENGL_ERROR();
glUniform4fv(get_uni_loc(programId, "color"), 1, c);
GLuint text_id = glGetUniformLocation(programId, "texture");
glUniform1i(text_id, texture);
//Draw
glDrawElements(GL_TRIANGLES, 6 * object.nbSquares, GL_UNSIGNED_INT, nullptr);
}
Thanks you in advance !