Cómo escribir mejor un motor de vóxel en C teniendo en cuenta el rendimiento [cerrado]
Soy una armadura en OpenGl y por esta razón busco aprender solo cosas modernas de OpenGl the 4.x. Una vez que completé los tutoriales básicos (por ejemplo, cubos rotativos), decidí que intentaría crear un programa basado en vóxel que tratara únicamente con cubos. El objetivo de este programa era ser rápido, usar potencia y memoria de CPU limitadas y ser dinámico para que el tamaño del mapa pueda cambiar y los bloques solo se dibujen si en la matriz dice que el bloque está lleno.
Tengo un VBO con los vértices e índices de un cubo construido a partir de triángulos. Al principio, si la función de renderización le digo a OpenGl los sombreadores que deben usar y luego unir el VBO una vez que esté completa, ejecuto este bucle
Dibujar bucle de cubo:
//The letter_max are the dimensions of the matrix created to store the voxel status in
// The method I use for getting and setting entries in the map are very efficient so I have not included it in this example
for(int z = -(z_max / 2); z < z_max - (z_max / 2); z++)
{
for(int y = -(y_max / 2); y < y_max - (y_max / 2); y++)
{
for(int x = -(x_max / 2); x < x_max - (x_max / 2); x++)
{
DrawCube(x, y, z);
}
}
}
Cubo.c
#include "include/Project.h"
void CreateCube()
{
const Vertex VERTICES[8] =
{
{ { -.5f, -.5f, .5f, 1 }, { 0, 0, 1, 1 } },
{ { -.5f, .5f, .5f, 1 }, { 1, 0, 0, 1 } },
{ { .5f, .5f, .5f, 1 }, { 0, 1, 0, 1 } },
{ { .5f, -.5f, .5f, 1 }, { 1, 1, 0, 1 } },
{ { -.5f, -.5f, -.5f, 1 }, { 1, 1, 1, 1 } },
{ { -.5f, .5f, -.5f, 1 }, { 1, 0, 0, 1 } },
{ { .5f, .5f, -.5f, 1 }, { 1, 0, 1, 1 } },
{ { .5f, -.5f, -.5f, 1 }, { 0, 0, 1, 1 } }
};
const GLuint INDICES[36] =
{
0,2,1, 0,3,2,
4,3,0, 4,7,3,
4,1,5, 4,0,1,
3,6,2, 3,7,6,
1,6,5, 1,2,6,
7,5,6, 7,4,5
};
ShaderIds[0] = glCreateProgram();
ExitOnGLError("ERROR: Could not create the shader program");
{
ShaderIds[1] = LoadShader("FragmentShader.glsl", GL_FRAGMENT_SHADER);
ShaderIds[2] = LoadShader("VertexShader.glsl", GL_VERTEX_SHADER);
glAttachShader(ShaderIds[0], ShaderIds[1]);
glAttachShader(ShaderIds[0], ShaderIds[2]);
}
glLinkProgram(ShaderIds[0]);
ExitOnGLError("ERROR: Could not link the shader program");
ModelMatrixUniformLocation = glGetUniformLocation(ShaderIds[0], "ModelMatrix");
ViewMatrixUniformLocation = glGetUniformLocation(ShaderIds[0], "ViewMatrix");
ProjectionMatrixUniformLocation = glGetUniformLocation(ShaderIds[0], "ProjectionMatrix");
ExitOnGLError("ERROR: Could not get shader uniform locations");
glGenVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: Could not generate the VAO");
glBindVertexArray(BufferIds[0]);
ExitOnGLError("ERROR: Could not bind the VAO");
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
ExitOnGLError("ERROR: Could not enable vertex attributes");
glGenBuffers(2, &BufferIds[1]);
ExitOnGLError("ERROR: Could not generate the buffer objects");
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES), VERTICES, GL_STATIC_DRAW);
ExitOnGLError("ERROR: Could not bind the VBO to the VAO");
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VERTICES[0]), (GLvoid*)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VERTICES[0]), (GLvoid*)sizeof(VERTICES[0].Position));
ExitOnGLError("ERROR: Could not set VAO attributes");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BufferIds[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(INDICES), INDICES, GL_STATIC_DRAW);
ExitOnGLError("ERROR: Could not bind the IBO to the VAO");
glBindVertexArray(0);
}
void DestroyCube()
{
glDetachShader(ShaderIds[0], ShaderIds[1]);
glDetachShader(ShaderIds[0], ShaderIds[2]);
glDeleteShader(ShaderIds[1]);
glDeleteShader(ShaderIds[2]);
glDeleteProgram(ShaderIds[0]);
ExitOnGLError("ERROR: Could not destroy the shaders");
glDeleteBuffers(2, &BufferIds[1]);
glDeleteVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: Could not destroy the buffer objects");
}
void DrawCube(float x, float y, float z)
{
ModelMatrix = IDENTITY_MATRIX;
TranslateMatrix(&ModelMatrix, x, y, z);
TranslateMatrix(&ModelMatrix, MainCamera.x, MainCamera.y, MainCamera.z);
glUniformMatrix4fv(ModelMatrixUniformLocation, 1, GL_FALSE, ModelMatrix.m);
glUniformMatrix4fv(ViewMatrixUniformLocation, 1, GL_FALSE, ViewMatrix.m);
ExitOnGLError("ERROR: Could not set the shader uniforms");
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, (GLvoid*)0);
ExitOnGLError("ERROR: Could not draw the cube");
}
El sombreador de vértices solo maneja la rotación y la transformación de los vértices y el sombreador de fragmentos solo se ocupa del color, por lo que no son caros de ejecutar, por lo que no son el cuello de botella.
¿Cómo se puede mejorar este código para renderizar de manera más eficiente y aprovechar al máximo las características modernas de OpenGL para disminuir la sobrecarga?
PD No estoy buscando un libro o una herramienta o un recurso fuera del sitio como respuesta. He utilizado el sacrificio de la cara posterior y la prueba de profundidad OpenGL para tratar de mejorar la velocidad, sin embargo, no han hecho una diferencia dramática, todavía está tardando ~ 50 ms en renderizar un marco y eso es demasiado para una cuadrícula de vóxel de 32 * 32 * 32.
Aquí captura de pantalla de lo que estoy haciendo:
Y aquí enlace al código completo:
GitHUB Voxel Viewer