[英]Get member offset in a template for glVertexAttribPointer
假设我在数组的结构Vertex
中给出了完整的顶点数据。 为了将数据发送到顶点着色器,我需要调用glVertexAttribPointer
来设置Vertex
成员和着色器参数之间的正确映射。
我正在尝试以一种很好的模板化方式封装OpenGL函数glVertexAttribPointer
。
glVertexAttribPointer
用作从CPU到GPU上载数据的一种类型描述,根据规范采用以下参数:
GLUint index
-句柄 GLint size
-组件数(与该问题无关) GLenum type
GL_FLOAT
GL_SHORT
设置类型( 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*)
为(const GLvoid*)
。 据我所知,假设WholeVertex
具有正确的标准布局 。 但是,在一般情况下,可能并非如此,编译器禁止我执行这种类型的转换。 实际上,如果没有对象,我无法对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
);
}
最后,通过取消引用指向null的指针(但仍然是hack:/):
GLvoid* offset=reinterpret_cast<GLvoid*>(&((static_cast<WholeVertex*>(NULL))->*memberPointer));
为了防御这些黑客:
我的理解是,对于POD对象,当前的C ++标准确保memberPointer
的值将是简单的偏移量计算。
glVertexAttribPointer
是一种API,具有曾经试图维持向后兼容性的可怕遗产。 不合格的手段是可以接受的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.