假设我在数组中的结构Vertex
中给出了完整的顶点数据。为了将数据发送到顶点着色器,我需要调用glVertexAttribPointer
来设置Vertex
成员与着色器参数之间的正确映射。
我试图以一种很好的模板方式封装一个OpenGL函数glVertexAttribPointer
。
glVertexAttribPointer
用作从CPU到GPU上传数据的一种类型描述,按照specification采用以下参数:
GLUint index
- 句柄GLint size
- 组件数量(与此问题无关)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
函数的宏可以计算我需要的东西,但问题是它将成员名称作为参数,如果名称未知则会使其无法使用。 / p>
那么,您是否有任何其他想法如何实现此包装函数? 也许以不同的方式计算偏移量?或者将其作为一种不同的参数传递?
答案 0 :(得分:1)
远离成员指针的常量并不容易。
你不会非常喜欢这个黑客,但它有效:
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
);
}
也许更好的方式使用联合演员黑客(仍然不符合,所以也许不符合你的喜好):
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
);
}
&amp;最后,通过de-referencing指向null的指针(但仍然是hack:/):
GLvoid* offset=reinterpret_cast<GLvoid*>(&((static_cast<WholeVertex*>(NULL))->*memberPointer));
为这些黑客辩护:
我的理解是,对于POD对象,当前的C ++标准可以确保
memberPointer
的值将是一个简单的偏移计算。
glVertexAttribPointer
是一个具有丑陋遗产的API
时间试图保持向后兼容性。不合规的手段是可以接受的。