glDrawElementsBaseVertex()vs glDrawElements()

时间:2013-09-16 20:35:13

标签: c++ opengl graphics gpu

我想直截了当,这就是为什么我从这个场景开始: -

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

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()是什么意思?

2 个答案:

答案 0 :(得分:3)

没有

在代码中:

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

答案 1 :(得分:0)

实际上,我正在阅读和你一样的在线书籍,我遇到了和你一样的问题。

我已经测试了你的代码(带有“第24个元素”的代码),它的工作方式与原始代码类似:

原着

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

我得到了

enter image description here

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

我得到了

enter image description here

他们是一样的。

事实上,我整天都在想这个问题。

正如本书指出的那样(here,检查最后一个注释的第二段),(在32位操作系统上)如果你的模型包含超过65536(2个字节)的顶点,那么element数组不能再使用GL_UNSIGNED_SHORT(2个字节)作为索引的类型。相反,它必须使用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和计算机图形学的初学者。 :)