我想知道是否有办法在GLSL中使用联合。我还没有看到任何关于此的文档。如果没有,使用联合是否有一个干净的解决方法。
我基本上想要一些东西。而且这可能是两件事之一,因此我想用一个联合来定义它。
谢谢!
P.S。可能有一些奇怪的铸造技巧可以做到这一点,我不知道,随时建议一个更好的方法。
修改
代码示例(因为union不可用而无法编译):
struct A{
bool isA;
float value;
};
struct B{
bool isA;
int value;
};
/* union */
union AandB {
A a;
B b;
}
void main()
{
AandB foo;
if(foo.a.isA)
/* process on A */
else
/* process on B */
}
另外,想象A和B很大,你不想复制它们。
编辑2:
这里有更多信息,希望有所帮助:
这些数据来自"外部"并且是特定于顶点的。必须根据类型(A或B)区别对待。他们可能是从VBO访问的。
答案 0 :(得分:1)
根据GLSL specification,关键字union
保留供将来使用,确实会导致编译错误。
GLSL支持一种方法,因为它们鼓励你使用简单的数据结构(没有邪恶的指针分配或奇怪的转换技巧),将使用带有标志的struct数组。
struct AandB {
A a;
B b;
bool isA;
};
然后,你可以使用它有这样的东西:
AandB foo;
if (a.isA) {
/* a process */
}
else {
/* b process */
}
但是,如果某个项目可能不包含任何类型,那么您应该注意这样一个事实,即该标志最初将为false并假设为B类型。在这种情况下,解决方法是使用两个标志和设置正确的。
<强>更新强>
如果内存使用是一个问题,仍然有办法,但它需要一个更有趣的数据结构。想到的一种方法是拥有一个包含索引和标志的项目定义数组。让我们想象一下这个数据结构:
struct Item {
bool isA;
int index;
};
Item items[5];
A a[5];
B b[5];
Item firstAItem;
firstItem.isA = true;
firstItem.index = 0;
items[0] = firstAItem;
Item firstBItem;
firstBItem.isA = false;
firstBItem.index = 0;
items[1] = firstBItem;
迭代时,您可以检查标志并转到相关索引,如下所示,假设N_items
是您拥有的项目数:
for (int i=0; i<N_items; i++) {
Item currentItem = items[i];
if (currentItem.isA) {
A foo = a[currentItem.index];
/* do some stuff with foo */
} else {
B bar = b[currentItem.index];
/* do some stuff with bar */
}
}
答案 1 :(得分:1)
由于我们讨论的是顶点属性,你可以这样做:
layout(location = 0) vec4 floatVal;
layout(location = 0) ivec4 intVal;
OpenGL将此作为属性别名引用,并且明确允许,具有以下警告。要么只访问其中一个别名属性,要么通过着色器的每个代码路径只访问其中一个属性。因此,如果你使用布尔条件保护访问和值计算,你会没事的:
//Don't use either variable yet
if(isFloat)
{
//Do something with `floatVal`
}
else
{
//Do something with `intVal`
}
//Don't use either variable again.
嗯,理论上你会很好 。属性别名是一个非常奇怪的角落,并且使用OpenGL的任何主程序实际上都不太可能这样做。这意味着实现支持可能会出错(未使用的代码是未经过测试的代码)。因此,如果您希望确保您的代码在各个平台上实际正常工作
,我建议您切换程序。