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

标签 c++ opengl

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

我正在尝试以一种很好的模板化方式封装一个 OpenGL 函数 glVertexAttribPointer

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

  • GLUint 索引 - 句柄
  • GLint 大小 - 组件数量(与此问题无关)
  • 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类似函数的宏,可以计算我需要的东西,但问题是它将成员名称作为参数,如果名称未知,则无法使用。

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

最佳答案

摆脱成员指针的常量性并不容易。

你不会很喜欢这个 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));


为这些黑客辩护:

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

  2. glVertexAttribPointer 是一个 API,它具有从前的可怕遗产 尝试保持向后兼容性的时间。不合规的方式是可以接受的。

关于c++ - 在 glVertexAttribPointer 的模板中获取成员偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22729054/

相关文章:

c++ - 检查提供给 std::array 编译时间的元素数量

c++ - @parm 在 C++ 中是什么意思或暗示?

c++ - 使用 vector 的 vector 在 opengl 中绘制地面

c++ - OpenGL - 翻译拉伸(stretch)和扭曲 Sprite

C++ "OR"条件被忽略

c++ - 删除char的正确方法是什么**

c++ - 传递 const 类型地址时模板参数推导失败

c++ - EGL 在第一次 opengl 函数调用时崩溃

python - 使用 python opengl (PyOpenGL) 创建几何着色器失败

c++ - OpenGL 将 glutSpecialFunc 指向成员函数