通过 glUniform 将 GLM 的矢量类型传递给 OpenGL
Passing GLM's vector types to OpenGL via glUniform
背景
我目前正在用 C++ 围绕 OpenGL 的 glUniform
函数编写一个包装器,以努力使它们类型安全。我有一堆 set_uniform
函数被重载以接受 OpenGL PODs (GLint
, GLuint
, GLfloat
) 或任何 GLM 向量和矩阵类型。
我认为到目前为止一切都很简单,但后来我遇到了布尔类型的问题。 GLSL 提供 bool
、bec2
、bvec3
和 bvec4
,因此我必须为 GLboolean
以及 GLM 布尔向量提供 set_uniform
重载类型。
根据 OpenGL 手册,没有 glUniform
函数接受 GLboolean
或指向 GLboolean
数组的指针。我必须传递 GLint
、GLuint
或 GLfloat
,驱动程序会为我进行转换。
Either the i, ui or f variants may be used to provide values for uniform variables of type bool, bvec2, bvec3, bvec4, or arrays of these. The uniform variable will be set to false if the input value is 0 or 0.0f, and it will be set to true otherwise.
在传递之前将 GLboolean
转换为 GLint
很容易,但事实证明 GLM 向量类型更加困难。我越深入实施,就越担心这个库。
问题
将 GLM 矢量类型传递给 OpenGL 的推荐方法是使用 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++ bool
)。我认为我不应该直接传递它,因为 glUniform3iv
需要 void
指向某些 GLint
的指针。 C++ 规范不保证 bool
的大小。这意味着 glUniform3iv
可能会读取第二个和第三个组件的垃圾,或者更糟的是,它实际上正在读取数组末尾。
为了纠正这个问题,我在传递给 OpenGL 之前从 glm::bvec3
转换为 glm::ivec3
:
glm::bvec3 bv(true, true, false);
glm::ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));
我对此不是 100% 满意,因为 glm::ivec3
的值类型为 glm::detail::mediump_int_t
,它是 int
的 typedef
而不是 GLint
但也许这可以归结为 'the library designer knows the sizes are the same'.
第二个也是更主要的问题是 glm::value_ptr
是 just passing the address of the first struct
member 并且将 struct
视为 array
而不考虑填充。
我是不是漏掉了什么? GLM 库与 OpenGL 一起使用非常广泛,它甚至列在 Khronos 自己的 wiki 上。然而,它提供的用于将其结构传递给 OpenGL 的函数,即 glm::value_ptr
,并没有努力确保它传递的类型实际上与 OpenGL 期望的类型大小相同,并且完全忽略了可能存在的任何填充。 GLM 库是否在类型大小和结构填充方面做了一些隐藏的欺骗,以便发送到 OpenGL 的数据是有效的,或者这个库是否有一些严重的基本问题?
Is the GLM library doing some hidden trickery with regard to type sizes and struct padding so that the data sent to OpenGL is valid or does this library have some serious fundamental problems?
都没有。它只是使 其他人对结构布局和指针算法的行为所做的那样。
C++ 标准不允许 value_ptr
工作;这显然是未定义的行为。但它也是处理此类事情的常用技术。许多真实的函数式代码假设 struct { int x; int y;};
可以被认为等同于 int[2]
。在大多数 C++ 实现下,这都将按预期运行。
在处理low-level编程时,做出这种性质的假设并非没有道理。
I'm not 100% happy with this since glm::ivec3
has a value type of glm::detail::mediump_int_t
which is a typedef
for int
rather than GLint
but maybe this can be chalked up to 'the library designer knows the sizes are the same'.
这与它无关。虽然 GLM 被称为 "OpenGL Mathematics",但它不依赖于 OpenGL 本身 。因此,它无法访问 GLint
或任何其他 OpenGL-defined 类型。
所以你可以假设 ivec3
的 value_type
与 GLint
的类型相同(你甚至可以写 static_assert
s 来验证它)或者你可以做你自己的变化。毕竟GLM是模板化的:
using gl_ivec3 = glm::tvec<GLint, 3>;
...
glm::gl_ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));
背景
我目前正在用 C++ 围绕 OpenGL 的 glUniform
函数编写一个包装器,以努力使它们类型安全。我有一堆 set_uniform
函数被重载以接受 OpenGL PODs (GLint
, GLuint
, GLfloat
) 或任何 GLM 向量和矩阵类型。
我认为到目前为止一切都很简单,但后来我遇到了布尔类型的问题。 GLSL 提供 bool
、bec2
、bvec3
和 bvec4
,因此我必须为 GLboolean
以及 GLM 布尔向量提供 set_uniform
重载类型。
根据 OpenGL 手册,没有 glUniform
函数接受 GLboolean
或指向 GLboolean
数组的指针。我必须传递 GLint
、GLuint
或 GLfloat
,驱动程序会为我进行转换。
Either the i, ui or f variants may be used to provide values for uniform variables of type bool, bvec2, bvec3, bvec4, or arrays of these. The uniform variable will be set to false if the input value is 0 or 0.0f, and it will be set to true otherwise.
在传递之前将 GLboolean
转换为 GLint
很容易,但事实证明 GLM 向量类型更加困难。我越深入实施,就越担心这个库。
问题
将 GLM 矢量类型传递给 OpenGL 的推荐方法是使用 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++ bool
)。我认为我不应该直接传递它,因为 glUniform3iv
需要 void
指向某些 GLint
的指针。 C++ 规范不保证 bool
的大小。这意味着 glUniform3iv
可能会读取第二个和第三个组件的垃圾,或者更糟的是,它实际上正在读取数组末尾。
为了纠正这个问题,我在传递给 OpenGL 之前从 glm::bvec3
转换为 glm::ivec3
:
glm::bvec3 bv(true, true, false);
glm::ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));
我对此不是 100% 满意,因为 glm::ivec3
的值类型为 glm::detail::mediump_int_t
,它是 int
的 typedef
而不是 GLint
但也许这可以归结为 'the library designer knows the sizes are the same'.
第二个也是更主要的问题是 glm::value_ptr
是 just passing the address of the first struct
member 并且将 struct
视为 array
而不考虑填充。
我是不是漏掉了什么? GLM 库与 OpenGL 一起使用非常广泛,它甚至列在 Khronos 自己的 wiki 上。然而,它提供的用于将其结构传递给 OpenGL 的函数,即 glm::value_ptr
,并没有努力确保它传递的类型实际上与 OpenGL 期望的类型大小相同,并且完全忽略了可能存在的任何填充。 GLM 库是否在类型大小和结构填充方面做了一些隐藏的欺骗,以便发送到 OpenGL 的数据是有效的,或者这个库是否有一些严重的基本问题?
Is the GLM library doing some hidden trickery with regard to type sizes and struct padding so that the data sent to OpenGL is valid or does this library have some serious fundamental problems?
都没有。它只是使
C++ 标准不允许 value_ptr
工作;这显然是未定义的行为。但它也是处理此类事情的常用技术。许多真实的函数式代码假设 struct { int x; int y;};
可以被认为等同于 int[2]
。在大多数 C++ 实现下,这都将按预期运行。
在处理low-level编程时,做出这种性质的假设并非没有道理。
I'm not 100% happy with this since
glm::ivec3
has a value type ofglm::detail::mediump_int_t
which is atypedef
forint
rather thanGLint
but maybe this can be chalked up to 'the library designer knows the sizes are the same'.
这与它无关。虽然 GLM 被称为 "OpenGL Mathematics",但它不依赖于 OpenGL 本身 。因此,它无法访问 GLint
或任何其他 OpenGL-defined 类型。
所以你可以假设 ivec3
的 value_type
与 GLint
的类型相同(你甚至可以写 static_assert
s 来验证它)或者你可以做你自己的变化。毕竟GLM是模板化的:
using gl_ivec3 = glm::tvec<GLint, 3>;
...
glm::gl_ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));