某些GL函数的好奇“void *”参数

时间:2014-08-01 06:23:10

标签: c++ pointers opengl casting

对于OpenGL中的某些函数,必须为stride指定字节偏移量,例如在glVertexAttribPointer()中。起初我会猜到它将是一个像整数一样的正常数值。但经过检查,我意识到需要将其转换为void*(更具体地说是GLvoid*)。我的问题是:void*的意图是什么?为什么必须将它用于字节偏移?

3 个答案:

答案 0 :(得分:5)

glVertexAttribPointer()是Vertex Buffer Objects之前的旧函数。

在VBO之前,您的顶点数据将存储在客户端数组中,您需要在绘制之前将指向数据的指针传递给OpenGL。

当VBO出现时,他们通过允许指针用于传递整数偏移来重新调整此函数。

e.g。 void* offset = (void*)offsetof(vertexStructName, vertexMemberName);

答案 1 :(得分:3)

某些OpenGL函数(例如glDrawElements)采用与上下文相关的GLvoid *参数。在旧的GL上,在Vertex Buffers之前,程序员会将一个整数索引数组直接传递给glDrawElements,如下所示:

const GLuint indexes[] = { ... };
glDrawElements(GL_TRIANGLES, numIndexes, GL_UNSIGNED_INT, indexes);

这被称为立即模式绘图。

当引入顶点和索引缓冲区时,OpenGL架构板决定它们应该重用现有的接口,从而为glDrawElementsglVertexAttribPointer的最后一个空指针参数提供新的上下文相关含义,一些其他类似的功能。

使用索引缓冲区,渲染数据已经在GPU上,因此void指针参数意味着是 offset 进入缓冲区。例如:第一个渲染的索引。导致glDrawElements的新用法:

size_t firstIndex = ...
size_t indexDataSize = sizeof(GLuint);
glDrawElements(GL_TRIANGLES, numIndexes, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(firstIndex * indexDataSize));

这适用于在现代OpenGL上重新使用的所有旧功能,例如glDrawElementsInstancedglDrawElementsBaseVertexglDrawRangeElements和其他功能。

现在处于glVertexAttribPointer的具体情况:

void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, const GLvoid * pointer​);

const GLvoid * pointer​参数是从顶点开始到给定元素的偏移量(以字节为单位)。同样,它保持这样,因为函数存在于Vertex / Index Buffers之前并重新用于它们,而在立即模式时,你会传递一个顶点数组作为'指针'参数。

所以在过去,glVertexAttribPointer的用法有点像:

const vec3 positions[] = { ... };
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, positions);

在现代GL中,你会使用:

struct Vert {
    vec3 position;
    vec3 normal;
};

size_t offset;

offset = offsetof(Vert, position);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, reinterpret_cast<const GLvoid *>(offset));

offset = offsetof(Vert, normal);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, reinterpret_cast<const GLvoid *>(offset));

答案 2 :(得分:0)

它被称为void指针,它可以指向任何类型,如char *,但它略有不同。首先,你必须记住指针只是一个数字,一个地址到正确的位置,仅此而已。要使用void指针指向的数据,必须将其显式转换为正确的类型,不能直接取消引用它们。它们允许您跳过类型检查,应该避免它们。

我看到的另一个不同之处是意图明确。当你看到char *指针时,你无法确定它是否会指向char / char数组。它可能是别的东西,它是高度情境化的:我看到它混淆的情况,有时很明显;另一方面,void指针的意图是明确的:它可以是任何东西,你必须考虑应用程序的上下文来找到类型。

另一件事是指针算术,AFAIR在无效指针的情况下它没有被标准定义。

我认为OpenGL中的void指针用于使API更通用,从而为驱动程序提供更多控制(通过设置可以更轻松地将浮动类型更改为双打)。但这只是猜测,需要确认。