背景
我目前正在围绕C 的OpenGL glUniform
功能编写包装器,以使其键入安全。我有一堆set_uniform
功能,这些功能被超载以接受OpenGL POD(GLint
,GLuint
,GLfloat
(或任何GLM Vector和Matrix类型。
我以为到目前为止一切都很直截了当,但是后来我遇到了布尔类型的问题。GLSL提供bool
,bec2
,bvec3
和bvec4
,因此我必须为GLboolean
以及GLM Boolean Vector类型提供set_uniform
过载。
根据OpenGL手册,没有glUniform
功能可以接受GLboolean
或指向GLboolean
数组的指针。我必须通过GLint
,GLuint
或GLfloat
,驱动程序将为我进行转换。
可以使用i,ui或f变体来提供Bool类型,BVEC2,BVEC3,BVEC4或阵列的均匀变量的值。如果输入值为0或0.0F,则统一变量将设置为false,否则将设置为true。
在通过之前将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
的实现为3 bool
s的结构(不是GLboolean
,而是C bool
(。我不相信我应该直接通过它,因为glUniform3iv
期望将void
指针指向某些GLint
s。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
而不是GLint
的typedef
,但也许可以将其粉刷为'图书馆设计师知道尺寸相同的尺寸。/p>
第二个也是更多的主要问题是glm::value_ptr
只是传递第一个struct
成员的地址,并将struct
视为array
,而无需填充。
我在这里错过了什么吗?GLM库与OpenGL一起广泛使用,甚至在Khronos自己的Wiki上列出。然而,它提供的功能将其结构传递给OpenGL,即glm::value_ptr
,并没有努力确保其所传递的类型实际上与OpenGL期望的类型相同,并且完全无视任何可能存在的填充物。GLM库在类型尺寸和结构填充方面做了一些隐藏的骗局,以使发送给OpenGL的数据有效,或者此库有一些严重的基本问题?
GLM库在类型尺寸和构造填充方面做了一些隐藏的骗局,以便发送给OpenGL的数据有效或该库有一些严重的基本问题吗?
都不。它只是做出与其他人对结构布局和指针算术行为所做的相同假设。
C 标准不允许value_ptr
工作;显然是不确定的行为。但这也是一种处理此类事情的常用技术。那里的许多真实的功能代码都假定struct { int x; int y;};
可以视为等同于int[2]
。在大多数C 实现下,这些都将按预期运行。
在处理低级编程时,假设这种性质并不是不合理的。
我对此并不100%,因为
glm::ivec3
具有glm::detail::mediump_int_t
的值类型,它是int
而不是GLint
的typedef
,但也许可以将其粉刷为"图书馆设计师知道尺寸相同"。/p>
与之无关。虽然GLM被称为" OpenGL数学",但对OpenGL 本身并不依赖。因此,它无法访问GLint
或任何其他OpenGL定义类型。
因此,您可以假设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));