- OpenGL顶点规范和绘图命令 Vertex Specification and Drawing Commands
- 图元类型 Primitive Types
- 当前顶点属性值 Current Vertex Attribute Values
- 顶点数组 Vertex Arrays
- 通用顶点属性的数组 Specifying Arrays for Generic Vertex Attributes
- 顶点属性除数 Vertex Attribute Divisors
- 使用顶点数组绘制命令 Drawing Commands Using Vertex Arrays
- 条件渲染 Conditional Rendering
相关API如下:
void glDrawArrays( enum mode, int first, sizei count );
void glDrawArraysInstancedBaseInstance( enum mode, int first, sizei count, sizei instancecount, uint baseinstance );
void glDrawArraysInstanced( enum mode, int first, sizei count, sizei instancecount );
void glDrawArraysIndirect( enum mode, const void *indirect );
void glMultiDrawArrays( enum mode, const int *first, const sizei *count, sizei drawcount );
void glMultiDrawArraysIndirect( enum mode, const void *indirect, sizei drawcount, sizei stride );
void glMultiDrawArraysIndirectCount( enum mode, const void *indirect, intptr drawcount, intptr maxdrawcount, sizei stride );
void glDrawElements( enum mode, sizei count, enum type, const void *indices );
void glDrawElementsInstancedBaseInstance( enum mode, sizei count, enum type, const void *indices, sizei instancecount, uint baseinstance );
void glDrawElementsInstanced( enum mode, sizei count, enum type, const void *indices, sizei instancecount );
void glMultiDrawElements( enum mode, const sizei *count, enum type, const void * const *indices, sizei drawcount );
void glDrawRangeElements( enum mode, uint start, uint end, sizei count, enum type, const void *indices );
void glDrawElementsBaseVertex( enum mode, sizei count, enum type, const void *indices, int basevertex );
void glDrawRangeElementsBaseVertex( enum mode, uint start, uint end, sizei count, enum type, constvoid *indices, int basevertex );
void glDrawElementsInstancedBaseVertex( enum mode, sizei count, enum type, const void *indices, sizei instancecount, int basevertex );
void glDrawElementsInstancedBaseVertexBaseInstance(enum mode, sizei count, enum type, const void *indices, sizei instancecount, int basevertex, uint baseinstance );
void glDrawElementsIndirect( enum mode, enum type, const void *indirect );
void glMultiDrawElementsIndirect( enum mode, enum type, const void *indirect, sizei drawcount, sizei stride );
void glMultiDrawElementsIndirectCount( enum mode, enum type, const void *indirect, intptr drawcount, sizei maxdrawcount, sizei stride );
void glMultiDrawElementsBaseVertex( enum mode, const sizei *count, enum type, const void * const *indices, sizei drawcount, const int *basevertex );
void glDrawArrays( enum mode, int first, sizei count )
glDrawArrays
是 OpenGL 的一个基础函数,用于从缓冲区中读取顶点数据并绘制一系列图元(如点、线段或三角形)。
-
mode
:这是一个枚举类型参数,定义了要绘制的图元类型。它可以是以下值之一:GL_POINTS
GL_LINE_STRIP
GL_LINE_LOOP
GL_LINES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
GL_TRIANGLES
-
first
:一个整数,表示从当前绑定的顶点数组缓冲中开始读取顶点的位置索引。通常,它是从0开始的。 -
count
:指定要绘制的连续顶点数量。OpenGL 将按照mode
指定的方式使用这些顶点来生成图元。
例如,如果你有一个包含100个顶点的数据,并且你想要绘制前36个顶点作为一个三角形列表,你可以这样调用 glDrawArrays
:
glDrawArrays(GL_TRIANGLES, 0, 36);
这将会从顶点数组的第一个元素开始,连续读取36个顶点并渲染为独立的三角形。
void glDrawArraysInstancedBaseInstance( enum mode, int first, sizei count, sizei instancecount, uint baseinstance )
glDrawArraysInstancedBaseInstance
用于实例化绘制一系列基于数组的图元,并允许指定每个实例组的基实例索引。
-
mode
:与glDrawArrays
中相同,是一个枚举类型参数,定义了要绘制的图元类型,可以是点、线段或三角形等。 -
first
:整数,表示从当前绑定的顶点数组缓冲中开始读取顶点的位置索引。 -
count
:指定连续使用的顶点数量来生成单个图元。 -
instancecount
:整数,指定了要绘制的实例数量。这意味着相同的图元数据将根据实例相关的变量(如变换矩阵)的不同值被多次渲染。 -
baseinstance
:无符号整数,提供了绘制调用中的基实例索引。在进行实例化绘制时,每个实例可能需要访问不同的实例特定数据,baseinstance
与实例ID相加可以用来索引到这些数据。
例如,如果你有一个包含三角形顶点的数据结构,并且想要创建100个基于这些顶点的不同实例,每个实例应用不同的模型变换,你可以这样调用此函数:
glDrawArraysInstancedBaseInstance(GL_TRIANGLES, 0, 3, 100, 0);
这里假设每个三角形由连续的三个顶点组成,并且你不需要跳过任何基实例。如果有多个实例组,且每个组之间有偏移,则可以设置非零的 baseinstance
值。
void glDrawArraysInstanced( enum mode, int first, sizei count, sizei instancecount )
glDrawArraysInstanced
允许基于相同的顶点数组数据多次绘制几何图元(如点、线段或三角形),每次绘制时可以应用不同的实例特定变量(例如模型变换矩阵)。
-
mode
:这是一个枚举类型参数,定义了要绘制的图元类型。 -
first
:整数,表示从当前绑定的顶点数组缓冲中开始读取顶点的位置索引。 -
count
:指定连续使用的顶点数量来生成单个图元。例如,如果你要绘制一个三角形,count
应为 3。 -
instancecount
:整数,指定了要绘制的实例数量。这意味着使用同一组顶点数据将绘制出多个实例,每个实例可以关联不同的实例属性。
例如,假设你有一个三角形网格,并希望用不同的变换对同一个三角形进行100次渲染:
glDrawArraysInstanced(GL_TRIANGLES, 0, 3, 100);
这行代码会从顶点数组的第一个顶点开始,连续读取3个顶点以构建一个三角形,并把这个三角形按照实例数据的不同重复渲染100次。为了在不同实例之间应用不同的变换,通常会在着色器程序中使用内置的 gl_InstanceID
变量或者其他实例化相关的uniform块或纹理。
void glDrawArraysIndirect( enum mode, const void *indirect )
glDrawArraysIndirect
函数允许通过间接方式指定绘制参数,而不是直接提供顶点数据。它允许应用程序在不从 CPU 到 GPU 传输数据的情况下发起绘制命令。
-
mode
参数指定了要绘制的几何图元的类型,可以是诸如点、线、三角形等类型之一。 -
indirect
参数是指向存储绘制参数的结构体的指针。这个结构体包含了绘制命令所需的所有信息,例如要绘制的实例数量、起始索引等。
下面是一个简单的示例,演示了如何使用 glDrawArraysIndirect
函数:
struct DrawArraysIndirectCommand {
GLuint count;
GLuint instanceCount;
GLuint first;
GLuint baseInstance;
};
DrawArraysIndirectCommand cmd = {3, 1, 0, 0}; // 绘制一个三角形
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer); // 绑定间接缓冲区
glDrawArraysIndirect(GL_TRIANGLES, &cmd); // 通过间接缓冲区发起绘制命令
在这个示例中,我们使用了一个 DrawArraysIndirectCommand
结构体来指定绘制命令的参数,然后将这个结构体写入了一个间接缓冲区(indirect buffer)。最后,通过调用 glDrawArraysIndirect
函数来发起绘制命令。
void glMultiDrawArrays( enum mode, const int *first, const sizei *count, sizei drawcount )
glMultiDrawArrays
允许程序员一次性提交多个 glDrawArrays
调用。这种方式在需要绘制大量独立图元集合时可以减少上下文切换开销,提高渲染效率。函数签名如下:
void glMultiDrawArrays(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
-
mode
:这是一个枚举类型参数,指定要绘制的图元类型,例如 GL_POINTS、GL_LINE_STRIP、GL_TRIANGLES 等。 -
first
:一个指向整数数组的指针,数组中的每个元素分别对应每次绘制调用的起始顶点索引。 -
count
:同样是一个指向整数数组的指针,数组中的每个元素分别对应每次绘制调用所需绘制的顶点数量。 -
drawcount
:表示first
和count
数组中有效条目的数量,即要执行的连续glDrawArrays
调用次数。
举例来说,如果你想要连续绘制多个三角形列表,且它们的顶点索引和数量都不相同,你可以这样做:
GLint firsts[] = {0, 30, 60};
GLsizei counts[] = {12, 24, 9};
// 假设这些顶点已经通过 glVertexAttribPointer 绑定并准备好渲染
glMultiDrawArrays(GL_TRIANGLES, firsts, counts, 3); // 执行三次绘制调用
在这个例子中,glMultiDrawArrays
将会依次从顶点缓冲区中按照 [0, 11]
、[30, 53]
和 [60, 68]
的范围绘制三个三角形列表。
void glMultiDrawArraysIndirect( enum mode, const void *indirect, sizei drawcount, sizei stride )
glMultiDrawArraysIndirect
函数允许以间接方式一次性发起多个绘制命令,其中绘制命令的参数存储在缓冲区中。
-
mode
参数指定了要绘制的几何图元的类型,可以是诸如点、线、三角形等类型之一。 -
indirect
参数是一个指向存储绘制命令参数的缓冲区的指针。 -
drawcount
参数指定了要执行的绘制命令的数量。 -
stride
参数指定了绘制命令在缓冲区中的字节间隔。
缓冲区中的数据结构应该包含每个绘制命令的参数,通常包括起始顶点索引、顶点数量等信息。
下面是一个示例,展示了如何使用 glMultiDrawArraysIndirect
函数:
struct DrawArraysCommand {
GLuint count;
GLuint instanceCount;
GLuint first;
GLuint baseInstance;
};
DrawArraysCommand commands[] = {
{3, 1, 0, 0}, // 绘制第一个几何图元
{6, 1, 3, 0} // 绘制第二个几何图元
};
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(commands), commands, GL_STATIC_DRAW);
glMultiDrawArraysIndirect(GL_TRIANGLES, nullptr, 2, sizeof(DrawArraysCommand));
在这个示例中,我们创建了一个缓冲区 buffer
来存储绘制命令的参数。然后,我们将命令数据 commands
存储到缓冲区中,最后调用 glMultiDrawArraysIndirect
函数以间接方式发起多个绘制命令。
void glMultiDrawArraysIndirectCount( enum mode, const void *indirect, intptr drawcount, intptr maxdrawcount, sizei stride )
glMultiDrawArraysIndirectCount
函数允许以间接方式一次性发起多个绘制命令,并且还提供了一个额外的参数来指定绘制命令的数量。
-
mode
参数指定了要绘制的几何图元的类型,可以是诸如点、线、三角形等类型之一。 -
indirect
参数是一个指向存储绘制命令参数的缓冲区的指针。 -
drawcount
参数是一个指向存储要执行的绘制命令的数量的值的指针。 -
maxdrawcount
参数指定了缓冲区中存储的绘制命令的最大数量。 -
stride
参数指定了绘制命令在缓冲区中的字节间隔。
缓冲区中的数据结构应该包含每个绘制命令的参数,通常包括起始顶点索引、顶点数量等信息。
下面是一个示例,展示了如何使用 glMultiDrawArraysIndirectCount
函数:
struct DrawArraysCommand {
GLuint count;
GLuint instanceCount;
GLuint first;
GLuint baseInstance;
};
DrawArraysCommand commands[] = {
{3, 1, 0, 0}, // 绘制第一个几何图元
{6, 1, 3, 0} // 绘制第二个几何图元
};
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(commands), commands, GL_STATIC_DRAW);
GLint drawCount = 2;
glMultiDrawArraysIndirectCount(GL_TRIANGLES, nullptr, &drawCount, 0, sizeof(DrawArraysCommand));
在这个示例中,我们创建了一个缓冲区 buffer
来存储绘制命令的参数。然后,我们将命令数据 commands
存储到缓冲区中,最后调用 glMultiDrawArraysIndirectCount
函数以间接方式发起多个绘制命令,并指定了绘制命令的数量。
在示例代码中,第二个参数 nullptr
表示不使用任何附加的间接数据。这意味着绘制命令的参数是通过缓冲区提供的,而不是通过其他方式提供的。
在OpenGL函数glMultiDrawArraysIndirectCount
中,maxdrawcount
参数表示缓冲区中能容纳的最大绘制命令数量。将其设置为0可能是一种约定,表示在使用缓冲区中提供的间接数据时,不对最大绘制命令数量做限制。
void glDrawElements( enum mode, sizei count, enum type, const void *indices )
glDrawElements
是 OpenGL 中的一个核心函数,用于执行基于索引的绘制调用。这个函数从指定的顶点数组中按照给定索引列表来绘制一系列图元(如点、线段或三角形等)。其函数原型如下:
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
-
mode
:这是一个枚举类型参数,指定了要绘制的图元类型。 -
count
:表示要绘制的图元数量。比如在绘制三角形时,它就是实际要绘制的三角形个数。 -
type
:定义了索引数据的格式。常见的类型包括 GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT 和 GL_UNSIGNED_INT。 -
indices
:指向包含索引数据的缓冲区的指针。这些索引数据决定了从顶点数组中选取哪些顶点来构建图元。
通过 glDrawElements
函数,GPU 可以高效地根据提供的索引来遍历并组合顶点数据,生成复杂的几何图形,而无需连续存储所有顶点数据或者重复相同的顶点信息。
GLfloat vertices[] = {
// 位置 // 颜色
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
// 顶点的索引数组
GLuint indices[] = {
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
glBindVertexArray(VAO); // 绑定VAO
// 绑定VBO(包含顶点数据)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 绑定EBO(包含索引数据)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 绘制三角形
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// 解绑
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
void glDrawElementsInstancedBaseInstance( enum mode, sizei count, enum type, const void *indices, sizei instancecount, uint baseinstance )
glDrawElementsInstancedBaseInstance
函数用于绘制带有实例化和基础实例参数的元素数组。下面是该函数的参数说明:
mode
:指定绘制的图元类型,比如GL_TRIANGLES
表示绘制三角形。count
:指定要绘制的索引数目。type
:指定索引数据的类型,比如GL_UNSIGNED_INT
。indices
:指向索引数据的指针。instancecount
:指定要绘制的实例数目。baseinstance
:指定基础实例的值。
以下是一个使用示例:
// 绘制带有实例化和基础实例参数的元素数组
glDrawElementsInstancedBaseInstance(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, 5, 10);
在这个示例中,我们使用 glDrawElementsInstancedBaseInstance
函数绘制了一个索引数组,绘制了 5 个实例,并且基础实例为 10。
void glDrawElementsInstanced( enum mode, sizei count, enum type, const void *indices, sizei instancecount )
glDrawElementsInstanced
函数用于绘制带有实例化参数的元素数组。下面是一个简单的介绍和示例:
mode
:指定绘制的图元类型,如GL_TRIANGLES
、GL_LINES
等。count
:指定要绘制的索引数量。type
:指定索引数据的类型,如GL_UNSIGNED_BYTE
、GL_UNSIGNED_SHORT
或GL_UNSIGNED_INT
。indices
:指向索引数据的指针。instancecount
:指定要绘制的实例数量。
以下是一个使用示例:
// 定义索引数据
GLuint indices[] = { 0, 1, 2, 3, 4, 5 };
// 绘制带有实例化参数的元素数组
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices, 5);
在这个示例中,我们使用 glDrawElementsInstanced
函数绘制了一个索引数组,绘制了 5 个实例。
void glMultiDrawElements( enum mode, const sizei *count, enum type, const void * const *indices, sizei drawcount )
glMultiDrawElements
函数允许一次性绘制多个具有不同索引数组的元素。下面是函数的参数说明:
mode
:指定绘制的基本图元类型,比如GL_TRIANGLES
表示绘制三角形。count
:一个整型数组,表示每个绘制命令要绘制的元素数量。type
:表示索引数组中元素的数据类型,比如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:一个指向指针数组的指针,每个指针指向一个索引数组。drawcount
:表示要执行的绘制命令的数量。
以下是一个示例使用 glMultiDrawElements
函数的情况:
// 假设有两个绘制命令,每个命令绘制不同数量的元素
const sizei counts[2] = {5, 8};
// 指向两个索引数组的指针数组
const void* indices[2] = {indexArray1, indexArray2};
// 绘制两个命令
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indices, 2);
在这个例子中,glMultiDrawElements
将会依次绘制 indexArray1
和 indexArray2
中的元素,分别绘制5个和8个元素,使用 GL_TRIANGLES
作为基本图元类型。
void glDrawRangeElements( enum mode, uint start, uint end, sizei count, enum type, const void *indices )
glDrawRangeElements
函数类似于DrawElements
函数,但它允许您指定一个索引范围来绘制元素,而不是使用整个索引数组。以下是函数的参数说明:
mode
:指定要绘制的基本图元类型,比如GL_TRIANGLES
表示绘制三角形。start
:指定要绘制的元素范围的起始索引。end
:指定要绘制的元素范围的结束索引。count
:指定要绘制的元素数量。type
:指定索引数组中元素的数据类型,比如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:指向索引数组的指针,它包含要绘制的元素的索引。
以下是一个使用glDrawRangeElements
函数的示例:
// 绘制索引范围为[start, end]的元素
glDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indices);
在这个例子中,绘制从索引start
到end
的元素,共计count
个元素,使用GL_TRIANGLES
作为基本图元类型,索引数据的类型为GL_UNSIGNED_INT
。
void glDrawElementsBaseVertex( enum mode, sizei count, enum type, const void *indices, int basevertex )
glDrawElementsBaseVertex
函数与DrawElements
函数类似,但它允许您指定一个基准顶点偏移量,以便在绘制时添加到索引中。这对于在一个顶点数组中包含多个模型并共享顶点数据的情况非常有用。
以下是函数的参数说明:
mode
:指定要绘制的基本图元类型,比如GL_TRIANGLES
表示绘制三角形。count
:指定要绘制的元素数量。type
:指定索引数组中元素的数据类型,比如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:指向索引数组的指针,它包含要绘制的元素的索引。basevertex
:指定要添加到索引中的基准顶点偏移量。
例如,有三个三角形,每个三角形由不同的顶点索引引用同一组顶点数据:
// 顶点数据(共有9个顶点)
GLfloat vertices[] = {
// 三角形1
-1.0f, -1.0f, 0.0f, // 顶点0
1.0f, -1.0f, 0.0f, // 顶点1
0.0f, 1.0f, 0.0f, // 顶点2
// 三角形2
1.5f, -1.5f, 0.0f, // 顶点3
2.5f, -1.5f, 0.0f, // 顶点4
2.0f, 0.5f, 0.0f, // 顶点5
// 三角形3
-0.5f, 1.0f, 0.0f, // 顶点6
0.0f, 2.0f, 0.0f, // 顶点7
0.5f, 1.5f, 0.0f // 顶点8
};
// 索引数据
GLubyte indices[] = {
// 三角形1
0, 1, 2,
// 三角形2
3, 4, 5,
// 三角形3
6, 7, 8,
};
// 假设基础顶点偏移值分别为0、3和6,对应于三个三角形各自对应的顶点起始位置
GLint baseVertices[] = {0, 3, 6};
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); // 绑定顶点缓冲对象
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定元素索引缓冲对象
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
for (int i = 0; i < 3; ++i) {
glDrawElementsBaseVertex(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, (void *)(sizeof(GLubyte) * i * 3), baseVertices[i]);
}
在这个例子中,glDrawElementsBaseVertex
函数被调用三次,每次传入当前三角形对应的索引范围和基础顶点偏移量。这样,虽然所有的三角形共享了同一个顶点缓冲区,但通过设置不同的 basevertex
参数,可以分别绘制出位于不同位置的三角形。
void glDrawRangeElementsBaseVertex( enum mode, uint start, uint end, sizei count, enum type, constvoid *indices, int basevertex )
glDrawRangeElementsBaseVertex
函数与glDrawElementsBaseVertex
函数类似,但它允许您指定要绘制的索引范围,而不是从整个索引数组中绘制。
以下是函数的参数说明:
mode
:指定要绘制的基本图元类型,比如GL_TRIANGLES
表示绘制三角形。start
:指定索引数组中的起始索引。end
:指定索引数组中的结束索引。count
:指定要绘制的元素数量。type
:指定索引数组中元素的数据类型,比如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:指向索引数组的指针,它包含要绘制的元素的索引。basevertex
:指定要添加到索引中的基准顶点偏移量。
以下是一个使用glDrawRangeElementsBaseVertex
函数的示例:
// 绘制指定范围和带有基准顶点偏移量的元素
glDrawRangeElementsBaseVertex(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indices, basevertex);
在这个例子中,GL_TRIANGLES
表示绘制三角形,start
和end
指定了要绘制的索引范围,count
是要绘制的元素数量,GL_UNSIGNED_INT
表示索引数组中的数据类型是无符号整数,indices
是指向索引数组的指针,basevertex
是要添加到索引中的基准顶点偏移量。
void glDrawElementsInstancedBaseVertex( enum mode, sizei count, enum type, const void *indices, sizei instancecount, int basevertex )
glDrawElementsInstancedBaseVertex
函数用于绘制带有基准顶点偏移量和实例化的元素数组。该函数允许您在绘制元素时指定实例化的数量以及基准顶点的偏移量。
下面是该函数的参数说明:
mode
:指定要绘制的基本图元类型,比如GL_TRIANGLES
表示绘制三角形。count
:指定要绘制的元素数量。type
:指定索引数组中元素的数据类型,比如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:指向索引数组的指针,它包含要绘制的元素的索引。instancecount
:指定要实例化的实例数量,即要绘制的实例数。basevertex
:指定要添加到索引中的基准顶点偏移量。
以下是一个使用glDrawElementsInstancedBaseVertex
函数的示例:
// 绘制带有基准顶点偏移量和实例化的元素数组
glDrawElementsInstancedBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_INT, indices, instancecount, basevertex);
在这个示例中,GL_TRIANGLES
表示要绘制的基本图元类型为三角形,count
指定要绘制的元素数量,GL_UNSIGNED_INT
表示索引数组中的数据类型是无符号整数,indices
是指向索引数组的指针,instancecount
指定要绘制的实例数量,basevertex
是要添加到索引中的基准顶点偏移量。
void glDrawElementsInstancedBaseVertexBaseInstance(enum mode, sizei count, enum type, const void *indices, sizei instancecount, int basevertex, uint baseinstance )
glDrawElementsInstancedBaseVertexBaseInstance
函数用于绘制带有基准顶点偏移量和实例化的元素数组,并指定基准实例。该函数允许在绘制元素时指定实例化的数量、基准顶点的偏移量以及基准实例。
以下是该函数的参数说明:
mode
:指定要绘制的基本图元类型,例如GL_TRIANGLES
表示绘制三角形。count
:指定要绘制的元素数量。type
:指定索引数组中元素的数据类型,例如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indices
:指向索引数组的指针,其中包含要绘制的元素的索引。instancecount
:指定要实例化的实例数量,即要绘制的实例数。basevertex
:指定要添加到索引中的基准顶点偏移量。baseinstance
:指定要添加到实例ID中的基准实例。
以下是一个使用 glDrawElementsInstancedBaseVertexBaseInstance
函数的示例:
// 顶点数据
GLfloat vertices[] = {
// 顶点坐标 // 颜色
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, // 0
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // 1
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 2
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, // 3
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, // 4
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // 5
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, // 6
-0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f // 7
};
// 索引数据
GLuint indices[] = {
0, 1, 2, 2, 3, 0, // 前面
4, 5, 6, 6, 7, 4, // 后面
1, 5, 6, 6, 2, 1, // 右侧
0, 4, 7, 7, 3, 0, // 左侧
3, 2, 6, 6, 7, 3, // 上面
0, 1, 5, 5, 4, 0 // 下面
};
// 创建顶点缓冲对象
GLuint VBO, EBO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 绑定并填充顶点缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 绑定并填充索引缓冲对象
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 链接顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// 创建一个顶点数组对象
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// 解绑缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// 绘制多个实例
glBindVertexArray(VAO);
glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0, 5, 0, 2);
glBindVertexArray(0);
在这个例子中,我们使用glDrawElementsInstancedBaseVertexBaseInstance函数绘制了一个立方体的多个实例。我们设置了绘制36个索引,每个实例绘制5个顶点,并在顶点和实例数据的基础上进行了偏移。
void glDrawElementsIndirect( enum mode, enum type, const void *indirect )
glDrawElementsIndirect
函数用于通过间接方式绘制元素数组。它允许使用一个间接的参数缓冲区来指定绘制命令的参数,包括绘制的基本图元类型、绘制的元素数量和偏移量、实例化的数量以及用于实例化的起始索引。
以下是该函数的参数说明:
mode
:指定要绘制的基本图元类型,例如GL_TRIANGLES
表示绘制三角形。type
:指定索引数组中元素的数据类型,例如GL_UNSIGNED_INT
或GL_UNSIGNED_SHORT
。indirect
:指向间接参数缓冲区的指针,该缓冲区包含了绘制命令的参数。
间接参数缓冲区的格式如下:
struct DrawElementsIndirectCommand {
GLuint count; // 要绘制的元素数量
GLuint instanceCount; // 要实例化的实例数量
GLuint firstIndex; // 索引数组的起始索引
GLuint baseVertex; // 要添加到索引中的基准顶点偏移量
GLuint baseInstance; // 要添加到实例ID中的基准实例
};
以下是一个使用 glDrawElementsIndirect
函数的示例:
// 创建间接参数缓冲区
GLuint indirectBuffer;
glGenBuffers(1, &indirectBuffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawElementsIndirectCommand), &indirectCommand, GL_STATIC_DRAW);
// 绘制元素数组
glBindVertexArray(vao);
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
在此示例中,我们首先创建了一个间接参数缓冲区 indirectBuffer
,然后将其绑定到 GL_DRAW_INDIRECT_BUFFER
目标上,并填充了包含绘制命令参数的结构体 DrawElementsIndirectCommand
。最后,我们绑定顶点数组对象并调用 glDrawElementsIndirect
函数来执行绘制命令。
在函数调用 glDrawElementsIndirect(mode, type, indirect)
中,参数 indirect
是一个指向间接参数缓冲区的指针。当传递 nullptr
给 indirect
时,意味着没有提供间接参数缓冲区,而是希望直接使用当前绑定的间接参数缓冲区进行绘制。
如果你已经通过 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer)
将一个间接参数缓冲区绑定到了 GL_DRAW_INDIRECT_BUFFER
目标上,并且想要使用这个缓冲区作为间接参数,就不需要在 glDrawElementsIndirect
函数调用中提供 indirect
参数,因为 OpenGL 会自动使用当前绑定的缓冲区作为间接参数。
void glMultiDrawElementsIndirect( enum mode, enum type, const void *indirect, sizei drawcount, sizei stride )
在函数调用 glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride)
中:
mode
表示要绘制的基本图元类型,例如GL_TRIANGLES
。type
表示索引数据的数据类型,例如GL_UNSIGNED_INT
。indirect
是一个指向间接参数缓冲区的指针,其中包含绘制命令的参数。这些参数是以结构数组的形式存储的,每个结构体描述了一个绘制命令的参数,包括索引的数量、偏移量等。drawcount
表示要执行的绘制命令的数量。stride
是间接参数结构体的字节步长,用于在缓冲区中定位下一个间接参数结构体。
当 indirect
参数设置为 nullptr
时,意味着没有提供间接参数缓冲区,OpenGL 将不会执行绘制操作。
如果你已经通过 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer)
将一个间接参数缓冲区绑定到了 GL_DRAW_INDIRECT_BUFFER
目标上,并且想要使用这个缓冲区作为间接参数,就不需要在 glMultiDrawElementsIndirect
函数调用中提供 indirect
参数,因为 OpenGL 会自动使用当前绑定的缓冲区作为间接参数。
void glMultiDrawElementsIndirectCount( enum mode, enum type, const void *indirect, intptr drawcount, sizei maxdrawcount, sizei stride )
在函数调用 glMultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride)
中:
mode
表示要绘制的基本图元类型,例如GL_TRIANGLES
。type
表示索引数据的数据类型,例如GL_UNSIGNED_INT
。indirect
是一个指向间接参数缓冲区的指针,其中包含绘制命令的参数。这些参数是以结构数组的形式存储的,每个结构体描述了一个绘制命令的参数,包括索引的数量、偏移量等。drawcount
表示要执行的绘制命令的数量。maxdrawcount
表示间接参数缓冲区中的绘制命令数量的最大值。这个参数是用来防止访问超出缓冲区范围的绘制命令数据。stride
是间接参数结构体的字节步长,用于在缓冲区中定位下一个间接参数结构体。
当 indirect
参数设置为 nullptr
时,意味着没有提供间接参数缓冲区,OpenGL 将不会执行绘制操作。
如果你已经通过 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer)
将一个间接参数缓冲区绑定到了 GL_DRAW_INDIRECT_BUFFER
目标上,并且想要使用这个缓冲区作为间接参数,就不需要在 glMultiDrawElementsIndirectCount
函数调用中提供 indirect
参数,因为 OpenGL 会自动使用当前绑定的缓冲区作为间接参数。
// 定义间接绘制命令结构体
struct DrawElementsIndirectCommand {
GLuint count; // 索引数量
GLuint instanceCount; // 实例数量
GLuint firstIndex; // 第一个索引在索引数组中的偏移量
GLint baseVertex; // 基础顶点偏移量
GLuint baseInstance; // 基础实例偏移量
};
// 假设有三个绘制命令
DrawElementsIndirectCommand commands[] = {
{3, 1, 0, 0, 0}, // 绘制第一个对象
{3, 1, 3, 0, 0}, // 绘制第二个对象
{3, 1, 6, 0, 0} // 绘制第三个对象
};
// 绘制多个对象
glMultiDrawElementsIndirectCount(GL_TRIANGLES, GL_UNSIGNED_INT, commands, sizeof(commands) / sizeof(DrawElementsIndirectCommand), 0, sizeof(DrawElementsIndirectCommand));
// 定义绘制命令结构体
struct DrawElementsIndirectCommand {
GLuint count; // 索引数量
GLuint instanceCount; // 实例数量
GLuint firstIndex; // 第一个索引在索引数组中的偏移量
GLint baseVertex; // 基础顶点偏移量
GLuint baseInstance; // 基础实例偏移量
};
// 假设有三个绘制命令
DrawElementsIndirectCommand commands[] = {
{3, 1, 0, 0, 0}, // 绘制第一个对象
{3, 1, 3, 0, 0}, // 绘制第二个对象
{3, 1, 6, 0, 0} // 绘制第三个对象
};
// 创建一个缓冲区对象来存储绘制命令数据
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(commands), commands, GL_STATIC_DRAW);
// 绘制多个对象
glMultiDrawElementsIndirectCount(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, sizeof(commands) / sizeof(DrawElementsIndirectCommand), 0, sizeof(DrawElementsIndirectCommand));
void glMultiDrawElementsBaseVertex( enum mode, const sizei *count, enum type, const void * const *indices, sizei drawcount, const int *basevertex )
glMultiDrawElementsBaseVertex
函数允许一次性绘制多个元素数组,每个元素数组都可以有一个不同的基础顶点偏移量。
mode
表示要绘制的基本图元类型,例如GL_TRIANGLES
。count
是一个指向包含每个元素数组的索引数量的数组的指针。type
表示索引数据的数据类型,例如GL_UNSIGNED_INT
。indices
是一个指针数组,每个元素都指向一个包含元素数组索引的缓冲区。drawcount
表示要绘制的元素数组的数量。basevertex
是一个指向包含每个元素数组的基础顶点偏移量的数组的指针。
每个元素数组的基础顶点偏移量指定了在顶点数组中查找顶点的起始位置。这对于从不同的顶点数组中检索顶点数据非常有用。
举例来说,如果 basevertex[i]
为 3
,那么在绘制第 i
个元素数组时,OpenGL 将从顶点数组中的第 3
个顶点开始获取顶点数据。
// 定义顶点数据和索引数据
GLfloat vertices[] = {
// 第一个对象的顶点数据
0.0f, 0.5f, 0.0f, // 顶部顶点
-0.5f, -0.5f, 0.0f, // 左下角顶点
0.5f, -0.5f, 0.0f, // 右下角顶点
// 第二个对象的顶点数据
0.0f, 0.5f, 0.0f, // 顶部顶点
-0.5f, -0.5f, 0.0f, // 左下角顶点
0.5f, -0.5f, 0.0f, // 右下角顶点
// 第三个对象的顶点数据
0.0f, 0.5f, 0.0f, // 顶部顶点
-0.5f, -0.5f, 0.0f, // 左下角顶点
0.5f, -0.5f, 0.0f // 右下角顶点
};
GLuint indices[] = {
// 第一个对象的索引数据
0, 1, 2,
// 第二个对象的索引数据
3, 4, 5,
// 第三个对象的索引数据
6, 7, 8
};
// 定义基础顶点偏移量数组
GLint baseVertices[] = { 0, 3, 6 }; // 每个对象的顶点数据在数组中的起始位置
// 定义每个对象的索引数量
GLsizei indexCounts[] = { 3, 3, 3 }; // 每个对象使用的索引数量
// 绘制多个对象
glMultiDrawElementsBaseVertex(GL_TRIANGLES, indexCounts, GL_UNSIGNED_INT, (const void * const *) indices, 3, baseVertices);
注意:在使用 glMultiDrawElementsBaseVertex
函数时,请确保提供的数组和缓冲区具有正确的大小和数据格式,以避免访问超出数组范围或缓冲区的未定义行为。