我目前正在编写一个关于OpenGL的glUniform
函数的包装器,以便使它们类型安全。我有一堆set_uniform
函数被重载以接受OpenGL POD(GLint
,GLuint
,GLfloat
)或任何GLM向量和矩阵类型。< / p>
我认为到目前为止一切都很直接,但后来我遇到了布尔类型的问题。 GLSL提供了bool
,bec2
,bvec3
和bvec4
,因此我必须为set_uniform
提供GLboolean
重载以及GLM布尔向量类型。
根据OpenGL手册,没有glUniform
函数接受GLboolean
或指向GLboolean
数组的指针。我必须通过GLint
,GLuint
或GLfloat
,然后驱动程序会为我进行转换。
i,ui或f变体可用于为bool,bvec2,bvec3,bvec4或其数组的均匀变量提供值。如果输入值为0或0.0f,则uniform变量将设置为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
is implemented as a struct of 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
,typedef
而不是int
而不是GLint
但也许这可以归结为图书馆设计师知道尺寸是相同的。#/ p>
第二个也是更重要的问题是,glm::value_ptr
为just passing the address of the first struct
member并将struct
视为array
而不考虑填充。
我在这里遗漏了什么吗? GLM库与OpenGL一起被广泛使用,它甚至被列在Khronos&#39;自己的维基。然而,它为将结构传递给OpenGL所提供的功能,即glm::value_ptr
,并没有努力确保它传递的类型实际上与OpenGL期望的类型相同,并且完全忽略任何填充。可能存在。 GLM库是否在类型大小和结构填充方面做了一些隐藏的技巧,以便发送到OpenGL的数据有效或者这个库有一些严重的基本问题吗?
答案 0 :(得分:4)
GLM库是否在类型大小和结构填充方面做了一些隐藏的技巧,以便发送到OpenGL的数据有效或者这个库有一些严重的基本问题吗?
都不是。它只是简单地制作了其他人对结构布局和指针算法的行为所做的same assumptions。
C ++标准不允许value_ptr
工作;这显然是未定义的行为。但它也是处理此类事物的常用技术。许多真实的功能代码假定struct { int x; int y;};
可以被认为等同于int[2]
。在大多数C ++实现中,这都将按预期运行。
在处理低级编程时,做出这种性质的假设并非没有道理。
我对此不是100%满意,因为
glm::ivec3
的值类型为glm::detail::mediump_int_t
,typedef
而不是int
而不是GLint
但也许这可以归结为图书馆设计师知道尺寸是相同的。#/ p>
这与它无关。虽然GLM被称为&#34; OpenGL数学&#34;,但它不依赖于OpenGL 本身。因此,它无法访问GLint
或任何其他OpenGL定义的类型。
因此,您可以假设ivec3
&#39; value_type
与[{1}}的类型相同(您甚至可以编写GLint
来验证它)或者你可以做出自己的变化。毕竟,GLM是模板化的:
static_assert