背景
我正在用C++编写一个OpenGL glUniform
函数的包装器,旨在使它们类型安全。我有许多 set_uniform
函数,可以重载以接受 OpenGL PODs(GLint
、GLuint
、GLfloat
)或任何 GLM 向量和矩阵类型。
我认为到目前为止一切都很简单,但是我遇到了布尔类型的问题。GLSL 提供了 bool
、bec2
、bvec3
和 bvec4
,因此我必须提供一个 set_uniform
重载以支持 GLboolean
和 GLM 布尔向量类型。
可以使用i、ui或f变体来为bool、bvec2、bvec3、bvec4或这些类型的数组提供统一变量的值。如果输入值为0或0.0f,则统一变量将设置为false,否则将设置为true。
在传递之前将GLboolean转换为GLint很容易,但是GLM向量类型证明更加困难。我深入实现,对该库越来越担心。
问题
向OpenGL传递GLM向量类型的推荐方法是使用glm::value_ptr:
glm::bvec3 v(true, true, false);
glUniform3iv(some_uniform_id, 1, glm::value_ptr(v));
我对这段代码有很多问题。
首先,
glm::bvec3
被实现为一个由3个bool
组成的结构体(不是GLboolean
,而是C++的bool
)。我认为我不应该直接传递它,因为glUniform3iv
期望一个指向一些GLint
的void
指针。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));
我对此并不完全满意,因为glm::ivec3
的值类型是glm::detail::mediump_int_t
,它是一个typedef
,代表int
而不是GLint
,但也许可以归结为“库设计人员知道大小相同”的原因。
第二个更重要的问题是glm::value_ptr
仅传递第一个struct
成员的地址,并将struct
视为没有考虑填充的array
。
这里有什么我没注意到的吗?GLM库与OpenGL一起被广泛使用,甚至在Khronos自己的维基上都有列出。然而,它提供给OpenGL的传递结构的函数,即glm::value_ptr
,没有努力确保它传递的类型实际上与OpenGL期望的类型大小相同,完全忽略可能存在的任何填充。GLM库是否在类型大小和结构填充方面做了一些隐藏的技巧,以使发送到OpenGL的数据有效,还是该库存在一些严重的基本问题?