如何将矩阵数组更新为 glsl 着色器

Posted

技术标签:

【中文标题】如何将矩阵数组更新为 glsl 着色器【英文标题】:How to update array of matrices to glsl shader 【发布时间】:2017-05-18 12:33:37 【问题描述】:

我目前正在处理骨骼动画,而且我真的很接近让它工作。目前,我有一个具有 100 个点的矩阵的结构(这样我最多可以有 100 个关节),如下所示:

struct skelShader 

glm::mat4 currentJointTrans[100];

;

结构体应该绑定在着色器中,我是这样做的:

    glGenBuffers(1, &sksBuff);
glBindBuffer(GL_UNIFORM_BUFFER, sksBuff);
// bind buffer to work further with it...
// allocate memory for the buffer in the GPU
glBufferData(GL_UNIFORM_BUFFER, sizeof(skelShader), NULL, GL_STATIC_DRAW);
// because we hard-coded "binding=3" in the shader code we can do this:
// bind Uniform Buffer to binding point 3 (without caring about index of UBO)
glBindBufferBase(GL_UNIFORM_BUFFER, 4, sksBuff);
// good practice, unbind buffer
glBindBuffer(GL_UNIFORM_BUFFER, 0);

sksBuff 只是一个 GLuint。

我在每个经过的渲染/帧都用新值填充这个数组,这些值是关节的新转换。我是这样做的:

    for (int i = 0; i < skeleton.size(); i++) 

    globalSkelInfo.currentJointTrans[i] = skeleton[i]->transformMat[currentFrame - 1] * skeleton[i]->globalBindPosMat;


这对根关节正常工作,但其余关节/网格仍处于绑定姿势。问题应该出在我更新数组的地方。目前,在我为每个关节完成乘法之后,我在渲染函数中这样做:

    for (int i = 0; i < skeleton.size(); i++) 
    glUniformMatrix4fv(glGetUniformLocation(aShaderProgram, ("currentJointTrans[" + std::to_string(i) + "]").c_str()),
        1, GL_FALSE, glm::value_ptr(globalSkelInfo.currentJointTrans[i]));

在这之后我画了。根关节值似乎正确移动,但网格的其余部分处于绑定姿势并且不会移动。在顶点着色器中,我尝试像这样更新矩阵:

#version 440

const int maxJoints = 100;
const int maxWeights = 4;

layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec2 vertex_UV;
layout(location = 2) in vec3 vertex_normal;

layout(location = 3) in vec4 vertex_weight;
layout(location = 4) in ivec4 vertex_controllers;


out vec2 outUVs;
out vec3 outNorm;

layout(binding = 3 , std140) uniform uniformBlock

    vec3 camPos;
    mat4 world;
    mat4 LookAt;
    mat4 projection;
    mat4 MVP;
;

layout(binding = 4 , std140) uniform animationStruct

    mat4 currentJointTrans[maxJoints];
;

void main() 


vec4 finalModelPos = vec4(0.0);
vec4 finalNormal = vec4(0.0);

for (int i = 0; i < 4; i++) 

    mat4 jointTrans = currentJointTrans[vertex_controllers[i]];
    vec4 posePos = jointTrans * vec4(vertex_position, 1.0);
    finalModelPos += posePos * vertex_weight[i];

    vec4 worldNormal = jointTrans * vec4(vertex_normal, 0.0);
    finalNormal += worldNormal * vertex_weight[i];



gl_Position = MVP * finalModelPos;
outNorm = finalNormal.xyz;

outUVs = vertex_UV;

我的理论是用我的 currentJointTrans 数组更新 struct skelShader 是不正确的。关于我应该如何执行此操作的任何提示?

【问题讨论】:

【参考方案1】:

glUniform* 调用无法在uniform buffers 中设置数据。事实上,统一缓冲区的全部意义在于统一数据来自一个缓冲区对象。这就是为什么你必须创建一个。

因此,如果您想为统一块设置统一数据,则将该数据设置到缓冲区对象中。

【讨论】:

感谢您的帮助!你说的很有用,让我更深入地研究它。我通过这样做解决了它:for (int i = 0; i &lt; 100; i++) glUniformMatrix4fv(glGetUniformLocation(aShaderProgram, ("currentJointTrans[" + std::to_string(i) + "]").c_str()), 1, GL_FALSE, glm::value_ptr(currentJointTrans[i])); glm::mat4 test = currentJointTrans[i]; @Haplue:这无法解决,因为您无法通过glUniform 调用设置统一块数据。如果这行得通,那么要么是因为你停止使用统一块,要么是纯属意外。每个glGetUniformLocation 调用都应该返回-1。 对不起,我很着急,所以我忘了提到我将 glsl 顶点着色器中的 mat4 制作成一个统一的 mat4,没有结构之类的。最近发生了很多事情,所以我希望我没有忘记提及我改变的任何其他内容。再次道歉,谢谢!

以上是关于如何将矩阵数组更新为 glsl 着色器的主要内容,如果未能解决你的问题,请参考以下文章

在 glsl 着色器中将矩阵作为纹理访问

OpenGL着色器语言GLSL资料汇编

OpenGL着色器语言GLSL资料汇编

OpenGL着色器语言GLSL资料汇编

运行时的 glsl 着色器编译问题

Python之OpenGL笔记(5):OpenGL着色器语言(GLSL)应用画三角形