在glVertexAttribPointer的模板中获取成员偏移量

时间:2014-03-29 09:01:34

标签: c++ opengl

假设我在数组中的结构Vertex中给出了完整的顶点数据。为了将数据发送到顶点着色器,我需要调用glVertexAttribPointer来设置Vertex成员与着色器参数之间的正确映射。

我试图以一种很好的模板方式封装一个OpenGL函数glVertexAttribPointer

glVertexAttribPointer用作从CPU到GPU上传数据的一种类型描述,按照specification采用以下参数:

  • GLUint index - 句柄
  • GLint size - 组件数量(与此问题无关)
  • GLenum type - 代表某种类型的枚举值(GL_FLOATGL_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>

那么,您是否有任何其他想法如何实现此包装函数? 也许以不同的方式计算偏移量?或者将其作为一种不同的参数传递?

1 个答案:

答案 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));


为这些黑客辩护:

  1. 我的理解是,对于POD对象,当前的C ++标准可以确保 memberPointer的值将是一个简单的偏移计算。

  2. glVertexAttribPointer是一个具有丑陋遗产的API 时间试图保持向后兼容性。不合规的手段是可以接受的。