代码之家  ›  专栏  ›  技术社区  ›  Fibbs Kerrek SB

通过glUniform将GLM的向量类型传递给OpenGL

  •  4
  • Fibbs Kerrek SB  · 技术社区  · 7 年前

    出身背景

    我目前正在围绕OpenGL编写一个包装器 glUniform 函数,以使其类型安全。我有很多 set_uniform 重载以接受OpenGL POD的函数( GLint ,则, GLuint ,则, GLfloat )或任何GLM向量和矩阵类型。

    我以为到目前为止一切都很简单,但后来我遇到了布尔类型的问题。GLSL提供 bool ,则, bec2 ,则, bvec3 bvec4 所以我必须提供 set\u统一 过载 GLboolean 以及GLM布尔向量类型。

    根据OpenGL手册,没有 胶状 函数,该函数接受 GLboolean 或指向 GLboolean 大堆我也必须通过 闪烁 ,则, 胶合 GLfloat公司 司机会帮我做转换。

    i、ui或f变量可用于为bool、bvec2、bvec3、bvec4或其数组类型的统一变量提供值。如果输入值为0或0.0f,统一变量将设置为false,否则将设置为true。

    正在转换 GLboolean 闪烁 传球之前很容易,但GLM向量类型证明更难。我对实现越深入,就越担心这个库。

    问题

    向OpenGL传递GLM向量类型的推荐方法是使用 glm::value_ptr :

    glm::bvec3 v(true, true, false);
    glUniform3iv(some_uniform_id, 1, glm::value_ptr(v));
    

    我对这段代码有很多问题。

    第一 glm::bvec3 is implemented as a struct of 3 bool s (不是 GLboolean 但是C++ 布尔 )。我不认为我应该直接通过 glUniform3iv 应为 void 指向某些 闪烁 s、 C++规范不能保证 布尔 。这意味着 glUniform3iv 可能正在读取第二个和第三个组件的垃圾,或者更糟的是,它实际上正在读取超过数组末尾的内容。

    为了纠正这个问题,我从 glm::bvec3 glm::ivec3 在传递到OpenGL之前:

    glm::bvec3 bv(true, true, false);
    glm::ivec3 iv = bv;
    glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));
    

    我对这件事不是百分之百满意 glm::ivec3 值类型为 glm::detail::mediump_int_t 这是一个 typedef 对于 int 而不是 闪烁 但也许这可以归结为“图书馆设计师知道尺寸是一样的”。

    第二个也是更主要的问题是 glm::value\u ptr just passing the address of the first struct member 以及治疗 结构 作为 array 不考虑填充。

    我错过什么了吗?GLM库与OpenGL一起被广泛使用,它甚至被列在Khronos自己的wiki上。然而,它提供的将其结构传递给OpenGL的功能,即 glm::value\u ptr ,不努力确保它传递的类型实际上与OpenGL期望的类型大小相同,并且完全忽略可能存在的任何填充。GLM库是否在类型大小和结构填充方面做了一些隐藏的诡计,以便发送到OpenGL的数据是有效的,或者该库是否存在一些严重的基本问题?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Nicol Bolas    7 年前

    GLM库是否在类型大小和结构填充方面做了一些隐藏的诡计,以便发送到OpenGL的数据是有效的,或者该库是否存在一些严重的基本问题?

    也不它只是让 same assumptions 其他人对结构布局和指针算法的行为所做的。

    C++标准不允许 value_ptr 工作;这显然是未定义的行为。但这也是处理此类事情的常用技巧。很多实际的功能代码都假设 struct { int x; int y;}; 可以认为相当于 int[2] 。在大多数C++实现中,这一切都将按预期运行。

    在处理低级编程时,做出这种性质的假设并非不合理。


    我对这件事不是百分之百满意 glm::ivec3 值类型为 glm::detail::mediump_int_t 这是一个 typedef 对于 int 而不是 GLint 但也许这可以归结为“图书馆设计师知道尺寸是一样的”。

    这与此无关。虽然GLM被称为“OpenGL数学”,但它并不依赖于OpenGL 它本身 。因此,它无法访问 闪烁 或任何其他OpenGL定义的类型。

    所以你可以假设 ivec3 value_type 将与相同类型 闪烁 (你甚至可以写 static_assert 或者您可以自己进行更改。毕竟,GLM是模板化的:

    using gl_ivec3 = glm::tvec<GLint, 3>;
    ...
    glm::gl_ivec3 iv = bv;
    glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));