假设我在数组中的结构 Vertex
中给出了完整的顶点数据。为了将数据发送到顶点着色器,我需要调用 glVertexAttribPointer
来设置 Vertex
成员和着色器参数之间的正确映射。
我正在尝试以一种很好的模板化方式封装一个 OpenGL 函数 glVertexAttribPointer
。
glVertexAttribPointer
用作从 CPU 到 GPU 的数据上传的一种类型描述,根据 specification 采用以下参数:
GLUint 索引
- 句柄GLint 大小
- 组件数量(与此问题无关)GLenum type
- 表示类型的枚举值(GL_FLOAT
、GL_SHORT
等...)GLboolean normalized
- 标准化为 [0..1] 或 [-1..1](与此问题无关)GLsizei stride
- 连续顶点元素之间的字节差。在我的例子中,这是Vertex
的大小。const GLvoid* pointer
- 第一个元素相对于数据开头的偏移量。在我的例子中,这将是成员相对于Vertex
开头的偏移量。
为了实现我的目标,我提出了以下解决方案:
template <typename WholeVertex, typename Element>
void attribute(GLuint shaderProgram, const char* name, Element WholeVertex::* memberPointer) {
GLint handle = glGetAttribLocation(shaderProgram, name);
glVertexAttribPointer (
handle,
opengl_type<Element>::arity,
opengl_type<Element>::type,
GL_FALSE,
sizeof(WholeVertex),
(const GLvoid*)(memberPointer) //error
);
}
其中 opengl_type
是我自己的特征类,计算给定类型的正确 GLenum 值。
不幸的是,这个解决方案假定成员指针只是一个整数偏移量并且可以转换为 (const GLvoid*)
。据我所知,假设 WholeVertex
有一个 standard layout那是真实的。不过,在一般情况下,这可能不是真的,编译器禁止我执行这种转换。事实上,如果没有对象,我无法对 memberPointer
做任何事情。
我发现有一个 offsetof
类似函数的宏,可以计算我需要的东西,但问题是它将成员名称作为参数,如果名称未知,则无法使用。
那么,您是否还有其他关于如何实现此包装函数的想法? 也许是一种不同的计算偏移量的方法?或者将其作为不同类型的参数传递?
最佳答案
摆脱成员指针的常量性并不容易。
你不会很喜欢这个 hack,但它确实有效:
template <typename WholeVertex, typename Element>
void attribute(GLuint shaderProgram, const char* name, Element WholeVertex::* memberPointer)
{
GLint handle = glGetAttribLocation(shaderProgram, name);
GLvoid *offset=0;
memcpy(&offset, &memberPointer, sizeof(GLvoid*));
printf("ooook:%p\n",offset);
glVertexAttribPointer (
handle,
opengl_type<Element>::arity,
opengl_type<Element>::type,
GL_FALSE,
sizeof(WholeVertex),
offset
);
}
也许更可取的方式是使用 union cast hack(仍然不合规,所以可能也不符合您的喜好):
template <typename WholeVertex, typename Element>
void attribute(GLuint shaderProgram, const char* name, Element WholeVertex::* memberPointer)
{
GLint handle = glGetAttribLocation(shaderProgram, name);
union
{
Element WholeVertex::* x;
GLvoid* y;
}
offset;
offset.x=memberPointer;
glVertexAttribPointer (
handle,
opengl_type<Element>::arity,
opengl_type<Element>::type,
GL_FALSE,
sizeof(WholeVertex),
offset.y
);
}
&最后,通过 de-referencing指向 null 的指针(但仍然是 hack :/):
GLvoid* offset=reinterpret_cast<GLvoid*>(&((static_cast<WholeVertex*>(NULL))->*memberPointer));
为这些黑客辩护:
我的理解是,对于 POD 对象,当前的 C++ 标准确保
memberPointer
的值将是一个简单的偏移量计算。glVertexAttribPointer
是一个 API,它具有从前的可怕遗产 尝试保持向后兼容性的时间。不合规的方式是可以接受的。
关于c++ - 在 glVertexAttribPointer 的模板中获取成员偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22729054/