【问题标题】:glDrawElementBaseVertex() vs glDrawElement()glDrawElementsBaseVertex() 与 glDrawElements()
【发布时间】:2013-09-21 02:56:30
【问题描述】:

我想直截了当,这就是我从这个场景开始的原因:-

假设您要绘制两个立方体,并假设您已经创建、绑定、填充缓冲区对象,其中包含两个立方体的数据,并且您拥有两个立方体的元素数组,如下所示:

const GLshort indexData[] =
{
//Object 1
0, 2, 1,        3, 2, 0,
4, 5, 6,        6, 7, 4,
8, 9, 10,       11, 13, 12,
14, 16, 15,     17, 16, 14,

//Object 2
18, 20, 19,     21, 20, 18,
22, 23, 24,     24, 25, 22,
26, 27, 28,     29, 31, 30,
32, 34, 33,     35, 34, 32,
};

绘制两个对象的第一种方法如下:-

// first Cube
glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);

// second Cube
glDrawElementsBaseVertex(GL_TRIANGLES, ARRAY_COUNT(indexData),GL_UNSIGNED_SHORT, 0, numberOfVertices / 2);

但是是否可以使用以下代码来绘制两个立方体?

// first cube
glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);

//second cube
// set the indice pointer to 24 so that it starts reading data for the second cube
glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, pointer to 24th element);

如果是,那么使用glDrawElementBaseVertex() 有什么意义?

【问题讨论】:

    标签: c++ opengl graphics gpu


    【解决方案1】:

    没有。

    在代码中:

    glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
    

    最后一个元素是指向索引数组的指针。在这种情况下,您传递的是 0,它是空指针,这意味着 OpenGL 将从绑定数组中获取索引。这不是偏移量。

    第二段:

    glDrawElementsBaseVertex(GL_TRIANGLES, ARRAY_COUNT(indexData),GL_UNSIGNED_SHORT, 0, numberOfVertices / 2);
    

    如您所愿,最后一个参数是偏移量。 此外,如果您计划为每次调用仅绘制一半缓冲区,则应将 count 参数从

    ARRAY_COUNT(indexData)
    

    ARRAY_COUNT(indexData)/2
    

    为了每次调用绘制一半的缓冲区。

    请阅读有关这两个函数的文档以获取更多信息:
    glDrawElements
    glDrawElementsBaseVertex

    【讨论】:

    • 我的意思是,如果我们使用该函数指定一个指向 24 日的指针就足够了??
    • 是的,但是 opengl 不能使用绑定的索引缓冲区。这就是它在索引缓冲区之前的工作方式。
    • 当然。您可以轻松地将指针传递到您希望数据开始的位置。
    • 所以如果我们想充分利用索引缓冲区,对于第一个对象,我们应该使用 0 的 basevertex,第二个使用 8 的 basevertex,使用 glDrawElementsBaseVertex() 我是对的???
    【解决方案2】:

    是的。

    其实我和你在看同一个网书,遇到和你一样的问题。

    我已经测试了您的代码(带有“第 24 个元素”的代码),它的工作原理与原始代码一样:

    与原版

    glDrawElementsBaseVertex(GL_TRIANGLES, ARRAY_COUNT(indexData),
        GL_UNSIGNED_SHORT, 0, numberOfVertices / 2);
    

    我明白了

    glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 
        (void*)(indexData + 24));
    

    我明白了

    它们是一样的。

    其实我整天都在想这个问题。

    正如书中指出的(here,检查最后一个注释的第二段),(在 32 位操作系统上)如果您的模型包含超过 65536(2 个字节)的顶点,则元素数组不能再使用 GL_UNSIGNED_SHORT(2 bytes) 作为索引的类型。相反,它必须使用 GL_UNSIGNED_INT(4 个字节)。它需要两倍的存储空间。

    然后检查here 以查看 glDrawElementsBaseVertex 的描述。它表示如果 (indices[i] + basevertex) 的值超过 type 的最大值,则该值将向上转换为 32 -bit unsigned int.

    考虑到这些参考资料,我有以下结论:

    例如,假设我有一个由 1,000,000 个顶点组成的 3D 角色。如果我使用 glDrawElements 来渲染它,我必须使用 GL_UNSIGNED_INT 来存储索引,这大约需要 3.8MB。但是,如果我可以使用“65536 * numberOfPage + index”之类的东西(如果我可以将这些顶点分解为不同的“页面”,就像随机访问一样,并且使用 index 来指示该页面中的顶点;并且 65536 可能是页面的大小)与 glDrawElementsBaseVertex,我仍然可以使用 GL_UNSIGNED_SHORT 来存储这些索引。在这种情况下,它将为我节省大约 1.9MB。

    也许 1.9MB 听起来不是一个大数字,但想想现代 3D 视频游戏的情况。我确信这些字符必须包含超过 1,000,000 个顶点,在这种情况下,glDrawElementsBaseVertex 为您保存的可能是 190MB 而不是 1.9MB。

    无论如何,这只是我的猜测,因为我也是 OpenGL 和计算机图形学的初学者。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多