如何在 GLSL 中使用 4x4 矩阵作为顶点属性?

Posted

技术标签:

【中文标题】如何在 GLSL 中使用 4x4 矩阵作为顶点属性?【英文标题】:How to use a 4x4 matrix as a vertex attribute in GLSL? 【发布时间】:2012-10-09 03:31:54 【问题描述】:

我正在尝试使用 4x4 矩阵作为顶点属性,使用以下代码:

Mat4 matrices[numVerts];

int mtxBoneID = glGetAttribLocation(hProgram, "aMtxBone");

glEnableVertexAttribArray(mtxBoneID + 0);
glEnableVertexAttribArray(mtxBoneID + 1);
glEnableVertexAttribArray(mtxBoneID + 2);
glEnableVertexAttribArray(mtxBoneID + 3);
glVertexAttribPointer(mtxBoneID + 0, 4, GL_FLOAT, GL_FALSE, sizeof(Mat4), ((Vec4*)matrices) + 0);
glVertexAttribPointer(mtxBoneID + 1, 4, GL_FLOAT, GL_FALSE, sizeof(Mat4), ((Vec4*)matrices) + 1);
glVertexAttribPointer(mtxBoneID + 2, 4, GL_FLOAT, GL_FALSE, sizeof(Mat4), ((Vec4*)matrices) + 2);
glVertexAttribPointer(mtxBoneID + 3, 4, GL_FLOAT, GL_FALSE, sizeof(Mat4), ((Vec4*)matrices) + 3);

// shader:
// ...
attribute mat4 aMtxBone;
// ...

但我在屏幕上看到的都是垃圾。

【问题讨论】:

如果你想进行网格蒙皮,最好将矩阵作为制服传递,并使用一个或多个整数向量属性来尊重它们。 您找到解决方案了吗?我遇到了完全相同的问题。 查看这个***.com/questions/17355051/… @sak 就像 Luca 所说,您可以将整数索引作为顶点属性传递到数组中,但不要将矩阵作为制服发送(着色器有最大数量的制服,这可能还不够)您可以将所有矩阵存储在浮点纹理中,然后使用最近邻采样对其进行采样。 Mat4 类型是什么样子的? 【参考方案1】:

你可以试试这样的 在你的着色器中使用布局

layout(location=x) in mat4 <name>;

x 不会等于glGetAttribLocation,你必须自己维护它。它等于你调用glVertexAttribPointer 的次数。 例子

layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
layout(location=2) in vec4 in_Normal;

glVertexAttribPointer(0, xxxxxxxx);
glVertexAttribPointer(1, xxxxxx);
glVertexAttribPointer(2, xxxxxx);

【讨论】:

应该注意,位置索引并不总是如上所述的“相等”,因为为每对 4 个顶点分配了一个索引。因此,一个矩阵将包含 4 个索引位置(或 16 个浮点数)。如果您尝试在位置 0 存储矩阵,在位置 1 存储 vec4,则链接着色器后会出现错误,因为这两个属性会导致重叠。您需要将 vec4 放置在位置 4,或将 mat4 放置在 vec4 之后以避免此类错误。【参考方案2】:

所以,我的答案因为未知原因被删除了。

我又来了,这次换个格式吧。

我遇到了与问题完全相同的问题,东西会被画得一团糟。至少描述是这样的。

为我解决的问题是调用

glDrawElementsInstancedBaseVertex(GL_TRIANGLES,
                                    d->drawCount,
                                    GL_UNSIGNED_INT,
                                    0,
                                    p_objects.size(),
                                    0);

要画我的东西,仅此而已。

但是!

如果您的东西绘制不正确,这可能不是您遇到的唯一问题。你需要纠正它的整个清单是巨大的。所以我要在这里放一个链接,它有一个关于如何画很多东西的很棒的教程。另外,您可以获取源代码并自己尝试。

http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html

来源:http://ogldev.atspace.co.uk/ogldev-source.zip

再次拒绝我并删除我的答案,它的内容与原来的完全没有改变。

禁止我访问该网站,你的损失。

【讨论】:

【参考方案3】:

首先您需要为您的矩阵创建 VBO (glGenBuffers),然后将其 (glBindBuffer) 绑定为当前,然后使用

glVertexAttribPointer(mtxBoneID + 0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(mtxBoneID + 1, 4, GL_FLOAT, GL_FALSE, 0, 4);
glVertexAttribPointer(mtxBoneID + 2, 4, GL_FLOAT, GL_FALSE, 0, 8);
glVertexAttribPointer(mtxBoneID + 3, 4, GL_FLOAT, GL_FALSE, 0, 12);

而不是您的glVertexAttribPointer 电话。

【讨论】:

顶点缓冲区对象不是强制性的。所以,不,这不是解决方案。 更新了我的答案。但是您似乎正在使用 OpenGL 2。我建议切换到 OpenGL 3,因为它似乎没有那么错误(我在使用 OpenGL 2 时经常遇到一些奇怪的行为,而 OpenGL 3 没有这个问题)。 现在答案已经完全过时了,只是展示他已经使用的代码。只有一个区别,这种区别甚至会让你的答案错误,因为12 * sizeof(float) 的步幅是行不通的。您需要从一个顶点的开始 到下一个顶点的字节,所以很可能是16 * sizeof(float),或者更好的是sizeof(Mat4)。但是等一下,那将完全是他的代码,你已经准备好删除答案了。 @AntonGuryanov OpenGL 2 的漏洞丝毫不比 OpenGL 3 少。唯一可能有漏洞的是您的实现(硬件+驱动程序)(您没有使用 ATI Intel GPU,是吗?)。可能只是核心 OpenGL 3 更简洁的界面让驱动程序失败的机会更少。 @ChristianRau 哎呀,我的错。然后我只能建议使用 OpenGL 3 尝试 VBO,问题就会消失。关于我的 GPU,当我使用 OpenGL 2 时,我有 NVidia GPU,我遇到了一些奇怪的问题。然后我切换到 OpenGL 3 并获得了一台装有 AMD Radeon 的新计算机。从那以后,我没有发现任何错误或奇怪的行为。【参考方案4】:

您的偏移量似乎已关闭。应该是

((Vec4*)matrices) + sizeOf(Vec4)*i

而不是

((Vec4*)matrices) + i

【讨论】:

这是错误的。当您将整数添加到指针时,添加的偏移量等于该整数与对象大小(以字节为单位)的乘积。您提供的代码相当于-> ((char*)matrices) + (sizeof(Vec4) * i) * sizeof(Vec4)

以上是关于如何在 GLSL 中使用 4x4 矩阵作为顶点属性?的主要内容,如果未能解决你的问题,请参考以下文章

GLSL:如何使用投影矩阵计算光线方向?

GLSL 每个顶点固定大小的数组

GLSL Instancing - 顶点数据的最大输入数?

GLSL:用旋转矢量旋转?

GLSL 2D 旋转矩阵无法按预期工作

无法获取在GLSL 1.5中工作的整数顶点属性