Не обращайте внимания на голосование против, скорее всего, оно не имеет ничего общего с контентом. Просто ответы на закрытые вопросы время от времени опускаются, чтобы отговаривать отвечать на закрывающие вопросы (что не является плохой вещью), но я не согласен с закрытием в этом случае, так как вопрос всегда имеет то, что должен иметь (по крайней мере, с точки зрения спрашивающих) Мы увидим позже, после возобновления цикла голосования, если сообщество согласится или нет.
рматура в OpenGl и по этой причине я стараюсь изучать только современные OpenGl 4.x. После того, как я закончил базовые уроки (например, вращающиеся кубы), я решил попробовать создать программу на основе вокселей, работающую исключительно с кубами. Цели этой программы заключались в том, чтобы быть быстрым, использовать ограниченную мощность ЦП и память и быть динамичным, чтобы размер карты мог изменяться, и блоки будут отображаться только в том случае, если в массиве указано, что блок заполнен.
У меня есть один VBO с вершинами и индексами куба, построенного из треугольников. В начале, если функция рендеринга я говорю OpenGl, что шейдеры должны использовать, и затем связываю VBO, как только это будет завершено, я выполняю этот цикл.
Draw Cube Loop:
//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);
}
}
}
Cube.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");
}
Вершинный шейдер обрабатывает только вращение и преобразование вершин, а фрагментный шейдер имеет дело только с цветом, который не требует больших затрат, поэтому он не является узким местом.
Как можно улучшить этот код, чтобы сделать его более эффективным и в полной мере использовать современные возможности OpenGL для уменьшения накладных расходов?
Постскриптум Я не ищу книгу, инструмент или сторонний ресурс в качестве ответа. Я использовал выборку задних поверхностей и тест глубины OpenGL, чтобы попытаться улучшить скорость, однако они не привели к значительным изменениям, которые все еще занимают ~ 50 мс. рендеринг кадра, и это слишком много для сетки вокселей 32 * 32 * 32.
Вот скриншот того, что я делаю:
А вот ссылка на полный код:
GitHUB Voxel Viewer