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



背景

我目前正在围绕C 的OpenGL glUniform功能编写包装器,以使其键入安全。我有一堆set_uniform功能,这些功能被超载以接受OpenGL POD(GLintGLuintGLfloat(或任何GLM Vector和Matrix类型。

我以为到目前为止一切都很直截了当,但是后来我遇到了布尔类型的问题。GLSL提供boolbec2bvec3bvec4,因此我必须为GLboolean以及GLM Boolean Vector类型提供set_uniform过载。

根据OpenGL手册,没有glUniform功能可以接受GLboolean或指向GLboolean数组的指针。我必须通过GLintGLuintGLfloat,驱动程序将为我进行转换。

可以使用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而不是GLinttypedef,但也许可以将其粉刷为'图书馆设计师知道尺寸相同的尺寸。/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而不是GLinttypedef,但也许可以将其粉刷为"图书馆设计师知道尺寸相同"。/p>

与之无关。虽然GLM被称为" OpenGL数学",但对OpenGL 本身并不依赖。因此,它无法访问GLint或任何其他OpenGL定义类型。

因此,您可以假设ivec3value_typeGLint相同(您甚至可以编写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));

最新更新