繁体   English   中英

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

[英]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_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*)(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));


为了防御这些黑客:

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

  2. glVertexAttribPointer是一种API,具有曾经试图维持向后兼容性的可怕遗产。 不合格的手段是可以接受的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM