Я, кажется, использую glMultiDrawIndirect (MDI) и / или DrawElementsIndirectCommand (DEIC) неправильно, поскольку я не могу правильно отобразить все объекты. Метод, пытающийся повторно использовать команды рисования для похожих объектов и текстур ('instancing' ... ish), рисует все объекты во всех местах. Метод 'debug' просто использует 1 команду рисования на объект (два треугольника), но на выходе всегда слишком мало объектов, причем местоположение первого объекта никогда не используется ни для какого объекта.
Вот что происходит при неудачной попытке создания экземпляра:
Вот что происходит при использовании метода отладки одного объекта (двух треугольников) для каждого DEIC:
Цель состоит в том, чтобы правильно использовать instanceCount в DEIC, чтобы позволить чему-то приближаться к экземпляру, в то же время рисуя правильное количество объектов в правильных местах . Мои приключения в google-raiding предполагают, что поле baseInstance DEIC может использоваться в качестве drawID, если DEIC хранятся в буфере. Если это невозможно или я сильно неправильно понимаю использование, пожалуйста, позвоните мне и дайте мне знать! Я попытался включить наименьшее количество применимого кода, чтобы избежать поста в 10000 слов.
Ниже я создаю объекты «рисования пути», которые представляют собой набор идентификаторов буферов и векторов, которые должны быть загружены в буферы (на основе многочисленных переменных, не связанных с этим вопросом).
// VAO
glGenVertexArrays(1, &p->vertexArrayObject);
glBindVertexArray(p->vertexArrayObject);
// vertices
glCreateBuffers(1, &p->vertexBuffer);
glBindVertexBuffer(bindingIndex, p->vertexBuffer, 0, sizeof(Vertex));
glEnableVertexArrayAttrib(p->vertexArrayObject, 0);
glEnableVertexArrayAttrib(p->vertexArrayObject, 1);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, offsetof(Vertex, position));
glVertexAttribBinding(0, bindingIndex);
glVertexAttribFormat(1, 2, GL_FLOAT, GL_TRUE, offsetof(Vertex, uv));
glVertexAttribBinding(1, bindingIndex);
if(p->pathType == DrawPathType::FAST)
{
glNamedBufferStorage(p->vertexBuffer, p->rbVertices.bufferSize, nullptr, m_persistentCreateFlags);
p->rbVertices.ptr = (Vertex*)glMapNamedBufferRange(p->vertexBuffer, 0, p->rbVertices.bufferSize, m_persistentMapFlags);
p->rbVertices.bufferFragment = p->rbVertices.bufferSize / 3;
}
// indices
glCreateBuffers(1, &p->indexBuffer);
glVertexArrayElementBuffer(p->vertexArrayObject, p->indexBuffer);
// draw commands
// glCreateBuffers(1, &p->drawCmdBuffer);
// glBindBuffer(GL_DRAW_INDIRECT_BUFFER, p->drawCmdBuffer);
// glNamedBufferStorage(p->drawCmdBuffer, p->rbCommands.bufferSize, nullptr, m_persistentCreateFlags);
// p->rbCommands.ptr = (DEIC*)glMapNamedBufferRange(p->drawCmdBuffer, 0, p->rbCommands.bufferSize, m_persistentMapFlags);
// p->rbCommands.bufferFragment = p->rbCommands.bufferSize / 3;
// unsure how this works
// glEnableVertexArrayAttrib(p->vertexArrayObject, 2);
// glVertexAttribIFormat(2, 1, GL_UNSIGNED_INT, offsetof(DrawElementsIndirectCommand, baseInstance));
// glVertexAttribBinding(2, bindingIndex);
// glVertexBindingDivisor(bindingIndex, 1);
// draw IDs
glCreateBuffers(1, &p->drawIDBuffer);
glBindBuffer(GL_ARRAY_BUFFER, p->drawIDBuffer);
glEnableVertexAttribArray(2);
glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(GLuint), 0);
glVertexAttribDivisor(2, 1);
// transforms
glCreateBuffers(1, &p->transformBuffer);
if(p->pathType == DrawPathType::LONG || p->pathType == DrawPathType::FAST)
{
glNamedBufferStorage(p->transformBuffer, p->rbTransforms.bufferSize, nullptr, m_persistentCreateFlags);
p->rbTransforms.ptr = (glm::mat4*)glMapNamedBufferRange(p->transformBuffer, 0, p->rbTransforms.bufferSize, m_persistentMapFlags);
p->rbTransforms.bufferFragment = p->rbTransforms.bufferSize / 3;
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, p->transformBuffer);
}
// texture addresses
glCreateBuffers(1, &p->textureAddressBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, p->textureAddressBuffer);
Это полезная часть функции renderPrep.
for(size_t i = 0; i < glyphs->size(); i++)
{
auto it = glyphs->at(i);
// ensure we have a valid texture address
if(!it->textureAddress.defined())
{
Logger::getInstance().Log(Logs::CRIT, Logs::Drawing, "Renderer2D::drawPrep()", "Iteration [{}] of [{}] has a null texture address (0,0)!", i, glyphs->size());
failed++;
}
else
{
offset = verts->size();
for(int in = 0; in < QUAD_VERTS; in++) { indices->push_back(baseQuadIndices[in] + offset); }
// creating our model space to world space matrix ('model' in "projection * view * model")
glm::mat4 transRotate = glm::rotate(identMat, glm::radians(it->angle), glm::vec3(0.0f, 0.0f, 1.0f));
transforms->push_back(transRotate);
transforms->back() = glm::translate(transforms->back(), it->position);
// push back modelspace vertices
for(auto& v : it->vertices) { verts->push_back(v); }
// update previous draw command or create a new one
if(currentTex.exists() && currentTex == it->textureAddress)
{
// append previous draw command
DEICs->back().vertexCount += QUAD_VERTS;
DEICs->back().instanceCount += 1; // two triangles, thus two instances
}
else
{
// different texture, new draw command
DEIC tmp = { QUAD_VERTS, 1, (inc * QUAD_VERTS), (inc * BASE_VERTS), inc };
DEICs->push_back(tmp);
currentTex = it->textureAddress;
}
/// \NOTE: Current issue is that the draw command is only drawing one object, in two iterations.
/// This is responsible for the blank second box
/* DEIC tmp = { QUAD_VERTS, 1, (inc * QUAD_VERTS), (inc * BASE_VERTS), 0 };
DEICs->push_back(tmp);
texAddrs->push_back(it->textureAddress); */
Logger::getInstance().Log(Logs::DEBUG, Logs::Drawing, "Renderer2D::drawPrep()",
"\n\033[93mDEIC #{}\033[0m:\n\tvertCount\t\t{}\n\tinstCount\t\t{}\n\tfirstInd\t\t{}\n\tbaseVert\t\t{}\n\tbaseInst\t\t{}\n",
DEICs->size(), DEICs->back().vertexCount, DEICs->back().instanceCount, DEICs->back().firstIndex, DEICs->back().baseVertex, DEICs->back().baseInstance);
texAddrs->push_back(currentTex);
p->drawIDs.push_back(inc);
inc++;
}
}
Этот фрагмент фактически отвечает за рендеринг.
int activeProgramID = 0; // currently used glsl program
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgramID);
// active passed glsl program id, or enable existing if not already enabled
if(glProgID > 0) { glUseProgram(glProgID); }
else if(activeProgramID == 0) { glUseProgram(m_prog->getProgramID()); }
// all clear, do it!
glBindVertexArray(p->vertexArrayObject);
// bind SSBOs, if applicable
if(p->transformBuffer) { glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, p->transformBuffer); }
if(p->textureAddressBuffer) { glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, p->textureAddressBuffer); }
// finally render
//if(p->drawCmdBuffer) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, p->drawCmdBuffer); glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, 0, p->drawCommands.size(), 0); }
//else { glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, p->drawCommands.data(), p->drawCommands.size(), 0); }
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, p->drawCommands.data(), p->drawCommands.size(), 0);
// update ring buffer(s), if applicable
if(p->rbCommands.ptr != nullptr) { m_bufferLockManager->lockRange(p->rbCommands.oldHead, p->rbCommands.bufferFragment); }
if(p->rbTransforms.ptr != nullptr) { m_bufferLockManager->lockRange(p->rbTransforms.oldHead, p->rbTransforms.bufferFragment); }
if(p->rbVertices.ptr != nullptr) { m_bufferLockManager->lockRange(p->rbVertices.oldHead, p->rbVertices.bufferFragment); }
// options specific to a "fast" draw path (if a fast draw path, glyphs are single use)
if(p->pathType == DrawPathType::FAST) { p->clear(true); }
// clean up
glBindVertexArray(0);
// change to previous glProgram
if(activeProgramID) { glUseProgram(activeProgramID); }
else { glUseProgram(0); }
РЕДАКТИРОВАТЬ # 1, 2019-04-05 11: 53a EST :
Сначала я забыл шейдеры! Извиняюсь за то, что пропустил это.
// --------- Vertex shader ------------
// uniforms / shader_storage_buffer object
layout(std140, binding = 0) buffer CB0 { mat4 Transforms[]; };
// view & projection in one
uniform mat4 ViewProjection;
// input
layout(location = 0) in vec3 In_v3Pos;
layout(location = 1) in vec2 In_v2TexCoord;
layout(location = 2) in uint In_uiDrawID;
// output
out DrawBlock
{
vec2 v2TexCoord;
flat uint iDrawID;
} Out;
void main()
{
mat4 World = Transforms[In_uiDrawID + gl_InstanceID];
vec4 worldPos = World * vec4(In_v3Pos, 1.0);
gl_Position = ViewProjection * worldPos;
Out.v2TexCoord = In_v2TexCoord;
Out.iDrawID = In_uiDrawID;
}
// --------- Fragment shader ------------
struct TexAddress
{
sampler2DArray arr;
float slice;
};
layout (std430, binding = 1) buffer CB1 { TexAddress texAddress[]; };
// input
in DrawBlock
{
vec2 v2TexCoord;
flat uint iDrawID;
} In;
// output
layout(location = 0) out vec4 Out_v4Color;
vec4 Texture(TexAddress addr, vec2 uv) { return texture(addr.arr, vec3(uv, addr.slice)); }
void main()
{
int DrawID = int(In.iDrawID);
Out_v4Color = vec4(Texture(texAddress[DrawID], In.v2TexCoord).xyz, 1.0f);
}
Если я удалил блок drawIDs с использованием не-DSA и заменил его фрагментом ниже, он рисует белые треугольники, фокусирующиеся на центре экрана.
glCreateBuffers(1, &p->drawCmdBuffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, p->drawCmdBuffer);
glNamedBufferStorage(p->drawCmdBuffer, p->rbCommands.bufferSize, nullptr, m_persistentCreateFlags);
p->rbCommands.ptr = (DEIC*)glMapNamedBufferRange(p->drawCmdBuffer, 0, p->rbCommands.bufferSize, m_persistentMapFlags);
p->rbCommands.bufferFragment = p->rbCommands.bufferSize / 3;
glEnableVertexArrayAttrib(p->vertexArrayObject, 2);
glVertexAttribIFormat(2, 1, GL_UNSIGNED_INT, offsetof(DrawElementsIndirectCommand, baseInstance));
glVertexAttribBinding(2, bindingIndex);
glVertexBindingDivisor(2, 1);
Результат:
РЕДАКТИРОВАТЬ # 2 @ 2019-04-06 12: 09p EST : Создана сущность на github с полным заголовком / источником для средства визуализации. Ссылка: https://gist.github.com/bbilyeu/bbf74ef4eaf979b5d2b4f2c2a9dcce48