glMultiDrawIndirect 和 DrawElementsIndirectCommands 不渲染所有对象

2023-12-25

我似乎正在使用glMultiDraw间接(MDI)和/或绘制元素间接命令(DEIC)不正确,因为我无法正确渲染所有对象。该方法尝试对相似的对象和纹理重用绘制命令(“实例化”...ish),在所有位置绘制所有对象。 “调试”方法仅对每个对象(两个三角形)使用 1 个绘制命令,但输出的对象始终太少,第一个对象的位置从未用于任何对象。

This is what happens when using the failed attempt at instancing: enter image description here

This is what happens when using the 'debug' method of one object (two triangles) per DEIC: debug render method

目标是正确使用 DEIC 中的 instanceCount 来允许接近实例化的东西,同时在正确的位置绘制正确数量的对象。我在 google-raid 中的经历表明 DEIC 的 baseInstance 字段could如果 DEIC 存储在缓冲区中,则可用作drawID。如果这是不可能的,或者如果我对用途有很大误解,请打电话告诉我!我尝试包含最少量的适用代码,以避免发布 10,000 字的帖子。

下面,我创建“绘制路径”对象,它们是要加载到缓冲区中的缓冲区 ID 和向量的集合(基于与此问题无关的许多变量)。

// 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 美国东部时间:

首先,我忘记了着色器!抱歉错过了这一点。

// --------- 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);
    }

如果我使用非 DSA 删除了 drawIDs 块并替换为下面的代码片段,它会绘制聚焦于屏幕中心的白色三角形。

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);

Outcome: outcome using DEIC baseInst


编辑 #2 @ 2019-04-06 12:09p 美国东部时间:在 github 上创建了一个要点,其中包含渲染器的完整标头/源代码。关联 :https://gist.github.com/bbilyeu/bbf74ef4eaf979b5d2b4f2c2a9dcce48 https://gist.github.com/bbilyeu/bbf74ef4eaf979b5d2b4f2c2a9dcce48


元素、实例和绘制命令的数量都不同,并且指代不同的事物。特别是,使用任何多重绘制命令并不一定意味着您执行任何实例化。

下面的代码使用one glMultiDrawArraysIndirect呼吁发行two绘图命令:

  1. 渲染三实例“四边形”对象的
  2. 渲染五实例“三角形”物体的

Data

struct Vert {
    float position[2];
};

struct Inst {
    float position[4]; // as two corners
    float color[4];
};

static const Vert verts[] = {
    // quad
    { { 0, 0 } }, // vertex 0
    { { 1, 0 } },
    { { 0, 1 } },
    { { 1, 1 } },
    
    // triangle
    { { 0, 0 } }, // vertex 4
    { { 1, 0 } },
    { { 0.5, 1 } },
};

static const Inst insts[] = {
    // three quads
    { { -0.8, -0.8, -0.6, -0.6 }, { 1, 0, 0, 1 } }, // instance 0
    { { -0.1, -0.8, 0.1, -0.6 }, { 0, 1, 0, 1 } },
    { { 0.6, -0.8, 0.8, -0.6 }, { 0, 0, 1, 1 } },
    
    // five triangles
    { { -0.8, 0.6, -0.6, 0.8 }, { 1, 1, 0, 1 } }, // instance 3
    { { -0.4, 0.6, -0.2, 0.8 }, { 0.1, 0.1, 0.1, 1 } },
    { { -0.1, 0.6, 0.1, 0.8 }, { 0, 1, 1, 1 } },
    { { 0.2, 0.6, 0.4, 0.8 }, { 0.1, 0.1, 0.1, 1 } },
    { { 0.6, 0.6, 0.8, 0.8 }, { 1, 0, 1, 1 } },
};

static const DrawArraysIndirectCommandSN cmds[] = {
    // quads: 4 vertices, 3 instances, first vertex=0, first instance=0
    { 4, 3, 0, 0 },

    // triangles: 3 vertices, 5 instances, first vertex=4, first instance=3
    { 3, 5, 4, 3 },
};

初始化代码:

GLuint buf[3]; // vertex, instance, draw-command buffers
glCreateBuffers(3, buf);
glNamedBufferStorage(buf[0], sizeof(verts), verts, 0);
glNamedBufferStorage(buf[1], sizeof(insts), insts, 0);
glNamedBufferStorage(buf[2], sizeof(cmds), cmds, 0);

GLuint va;
glCreateVertexArrays(1, &va);
glVertexArrayVertexBuffer(va, 0, buf[0], 0, sizeof(Vert));
glVertexArrayVertexBuffer(va, 1, buf[1], 0, sizeof(Inst));
glVertexArrayBindingDivisor(va, 1, 1);
glVertexArrayAttribBinding(va, 0, 0);
glEnableVertexArrayAttrib(va, 0);
glVertexArrayAttribFormat(va, 0, 2, GL_FLOAT, 0, offsetof(Vert, position));
glVertexArrayAttribBinding(va, 1, 1);
glEnableVertexArrayAttrib(va, 1);
glVertexArrayAttribFormat(va, 1, 4, GL_FLOAT, 0, offsetof(Inst, position));
glVertexArrayAttribBinding(va, 2, 1);
glEnableVertexArrayAttrib(va, 2);
glVertexArrayAttribFormat(va, 2, 4, GL_FLOAT, 0, offsetof(Inst, color));

渲染部分:

glClear(GL_COLOR_BUFFER_BIT);
glBindProgramPipeline(pp.get());
glBindVertexArray(va);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buf[2]);
glMultiDrawArraysIndirect(GL_TRIANGLE_STRIP, 0, sizeof(cmds)/sizeof(cmds[0]), 0);

顶点着色器:

#version 450 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec4 inst_position;
layout(location = 2) in vec4 color;

out gl_PerVertex {
    vec4 gl_Position;
};

layout(location = 0) out PerVertex {
    vec4 color;
} OUT;

void main() {
    OUT.color = color;
    gl_Position = vec4(mix(inst_position.xy, inst_position.zw, position), 0, 1);
}

片段着色器:

#version 450 core
layout(location = 0) in PerVertex {
    vec4 color;
} IN;
layout(location = 0) out vec4 OUT;
void main() {
    OUT = IN.color;
}

结果:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

glMultiDrawIndirect 和 DrawElementsIndirectCommands 不渲染所有对象 的相关文章

随机推荐

  • 了解 CompletableFuture::runAsync

    我刚刚读过文档 https docs oracle com javase 8 docs api java util concurrent CompletableFuture html runAsync java lang Runnable
  • 交替行的 jQuery 表格样式与 CSS 表格样式

    对于服务器上生成的奇数 偶数行 使用带有类的 CSS 更快 更好 还是使用 jQuery 设置条纹样式更快 更好document Ready 我想开始使用 jQuery 来使我的标记不那么混乱 但我不确定性能 特别是对于较大 最多 200
  • 在 JS 中计算直方图的相似值的最佳方法是什么?

    我正在尝试创建随机生成的数据的直方图 因此目前我正在执行以下操作 假设创建了以下数组 returns 0 0024 0 0231 0 014 0 0005 0 008 我使用以下方法遍历数组 returnsRounded x Math ro
  • 这种广度优先搜索可以变得更快吗?

    我有一个数据集 它是一个大型未加权循环图 循环发生在大约 5 6 条路径的循环中 它由大约 8000 个节点组成 每个节点有 1 6 个 通常大约 4 5 个 连接 我正在进行单对最短路径计算 并实现了以下代码来进行广度优先搜索 from
  • 从资源设置应用程序图标时应用程序大小会增加

    我有一个大小为 16kb 的应用程序 通过 项目属性 菜单添加图标资源后 应用程序的大小如预期增加到 299kb 现在 在 属性 应用程序 下 当我将图标文件设置为 Resource IconName ico 时 文件大小再次增加到 581
  • 带有临时链接的提交按钮

    好的 我不知道我在做什么 我要回去帮助人们找工作 我在 Fiddle 中运行了所有内容 并将其迁移到两个不同的编辑器 一切都显示正常 但没有任何反应 没有警报 没有单击提交 我在我的笔记本电脑上尝试了一下 显示了两个页面 一个页面上有 pr
  • D3 - 重置 SVG 对象动画

    我正在用交互式标记制作一个图表 每个标记都沿着侧轴开始 单击时会移动到沿线的位置并增大尺寸 我让图标移动和增长 但在重置图表时遇到问题 我可以通过第二次单击使图标返回到其原始位置 但是第二次单击后图标将不再响应单击 我怀疑这很简单 但我没有
  • 防止 git checkout 覆盖文件

    另一位开发人员将他的 rvmrc 检查到了 git 存储库中 我已经删除了它并将其添加到 gitignore 但每次需要返回时它都会覆盖我的 rvmrc 我使用的是 OSX 所以我发现我可以使用 OSX 文件锁定机制 获取信息中的 锁定 复
  • 如何在数据库中保存标签(关键字)?

    我想使用 php 和 mysql 创建一个简单的标签系统 以便用户可以通过表单添加一些标签 我的问题是我应该将标签保存为单个数据库列中的数组吗 例如 tag1 tag2 tag3 或者我应该在数据库表中有单独的列 我应该在每列中保存每个标签
  • PowerShell 按嵌套字段选择和分组

    我有以下对象结构 resources Array resource PSCustomObject 名称 字符串 Tags PSCustomObject 所有者 字符串 more 所以我可以做 resources 0 Tags Owner并获
  • 在 iOS 中使用 AVCapture 捕获视频时进行缩放

    我正在使用 AVCapture 捕获视频并保存它 但我需要提供缩放选项 例如捏合缩放或通过缩放按钮 此外 视频的保存方式应与显示的方式完全相同 我的意思是当放大时 应以缩放的方式保存 如有任何帮助 链接将不胜感激 我设置 AVCapture
  • perl 正则表达式中的 OR 条件

    我正在尝试编写一个脚本 通过 Perl 中的正则表达式执行 OR 函数 我编写了一段代码 其中如果字符串包含 D 或 E 后跟 P 则应该打印 D或E后跟P 否则 D或E后不跟P 假设如果我给出 s ABCDEABCDEPABCDEAB 它
  • SameSite Cookie 标头和 Websocket 不起作用

    在我们设置 SameSite None 之前 我们的游戏无法在任何第 3 方网站上运行 正如这段视频中所示 https youtu be AYCvCrZyDk https youtu be AYCvCrZyDk 网站已加载 但网络套接字无法
  • OCaml 中的惰性“n 选择 k”

    作为枚举集合的更大问题的一部分 我需要编写一个 OCaml 函数 choose 它接受一个列表并输出为由该列表的元素组成的所有可能的大小为 k 的序列的列表 不重复序列 这可以可以通过排列相互获得 它们在最终列表中的顺序无关 例如 choo
  • 如何在reactjs中使用formData添加多个图像

    我是 Reactjs 新手 我正在使用环回存储连接器来存储图像 文件 现在我的问题是使用上传多个文件formData my code constructor props super props this state car photo Ca
  • 按项目分组时,测试显示在测试资源管理器的“外部”类别下

    Whenever I try to run tests on Test Explorer from Visual Studio 2012 SOME test are being categorized as External even th
  • 在两个数字和一个稀有数字之间生成随机数

    我可以使用这个在c中生成两个数字之间的随机数 arc4random high low 1 low 那么现在我的要求是 我想让一个数字变得稀有 这意味着如果 高 5 低 1 稀有 3 比 3 出现的次数比 1 2 4 和 5 少得多 Than
  • #1062 - 密钥 1 的重复条目“1” - 未找到重复条目

    因此 当尝试向字段添加自动增量时 会出现 1062 Duplicate entry 1 for key 1 我尝试删除主键并重新添加它 效果很好 我认为如果有重复项就不会 但是当我尝试向该字段添加自动增量时 它会抛出错误 它为我提供了一个运
  • 在bash脚本中使用Linux命令的正确方法

    就其路径而言 在 bash 脚本中使用 Linux 命令的最佳和最正确的方法是什么 仅使用正确吗ip addr show 依赖于 shell 路径 PATH https pubs opengroup org onlinepubs 96999
  • glMultiDrawIndirect 和 DrawElementsIndirectCommands 不渲染所有对象

    我似乎正在使用glMultiDraw间接 MDI 和 或绘制元素间接命令 DEIC 不正确 因为我无法正确渲染所有对象 该方法尝试对相似的对象和纹理重用绘制命令 实例化 ish 在所有位置绘制所有对象 调试 方法仅对每个对象 两个三角形 使