PDA

View Full Version : GLSL Matrix 2x4 for Skinning



DavidJr
01-09-2016, 09:59 PM
I successfully did the skeletal animation using Quaternion Translation, (thanks to GClements & Dark Poton) but it is in immediate mode, now I try to convert the codes to the GLSL. I did the QT computation in my app and send the QT to the shader by converting it to matrix 2x4 and do the mesh deformation in the shader.

Here is my shader code:

#version 400 core

in vec3 GL_Vertex;
in vec2 GL_TexCoord;
in vec3 GL_Normal;
in int GL_Bone;

out vec2 GL_TexCoord0;

uniform mat4 m_Perspective, m_View, m_Model;
uniform mat2x4 m_QT[100];

vec3 Rotate_Vector(in vec4 q, in vec3 v)
{
return v + 2.0*cross(cross(v, q.xyz) + q.w*v, q.xyz);
}

void main()
{
vec4 q = vec4(m_QT[GL_Bone][0][0], m_QT[GL_Bone][0][1], m_QT[GL_Bone][0][2], m_QT[GL_Bone][0][3]);
vec3 t = vec3(m_QT[GL_Bone][0][0], m_QT[GL_Bone][1][1], m_QT[GL_Bone][1][2]);
vec3 vVertex = Rotate_Vector(q, GL_Vertex) + t;

mat4 mModelView = m_View * m_Model;
gl_Position = m_Perspective * mModelView * vec4(vVertex, 1.0);

GL_TexCoord0 = GL_TexCoord;
}

However, when I try to rotate the vertex position with the QT, it seems the result is 0. I tried to debug it in shader like this:

if (vVertex == GL_Vertex) {
vVertex = vec3(0.0, 0.0, 0.0);
}
and results the model not drawn which means the rotate_vector computation returns 0 so I assume like that. So far the model drawn without problem in the reference position but there's no animation since the function returns 0.

I tried to debug the QT before send it to the shader, they are fine. Also try to compute vertex rotation in my app the QT is still fine, I don't know why it returns 0 when computed in shader. I stored the QT in float m[2][4], first row is quaternion and second row is translation, they are in order x, y, z, w.

This is how I send it to the shader:

Shader_LoadUniformMatrix2x4fv(iShader, "m_QT", pModel->iBone, GL_FALSE, &(pModel->pBone[0].m[0][0]));


Thank you before!

DavidJr
01-10-2016, 10:28 PM
Okay I figured out that my bone index in vertex shader was corrupt and I got it fixed by changing it to float type and cast it to integer. The default position now is messed and still the vertex won't move and keeps staying in that strange position.

The black object is the animated object, it keeps in that shape whenever the frame changes.
http://s25.postimg.org/fwgv3y2lb/Error.jpg

The black object should look like this
2222

I'm kinda stuck here, please help.
Thank you so much

DavidJr
01-11-2016, 01:10 AM
Hey! I could get it working now! The problem is how I send the uniform is wrong, I change from matrix to 2 vec4 uniform.
Here is the way I send it atm:

float *pQuat, *pTrans;
// allocation and storing the value to pQuat and pTrans
Shader_LoadUniform4fv(CurrentShader, "GL_Q", pModel->iBone, &(pModel->pQuat[0]));
Shader_LoadUniform4fv(CurrentShader, "GL_T", pModel->iBone, &(pModel->pTrans[0]));

But I don't really like it, I like the way how I send before like this (the fQuat and fTrans are in Bone Struct):

float fQuat[4], fTrans[4];
// allocation and storing the value to fQuat and fTrans
Shader_LoadUniform4fv(CurrentShader, "GL_Q", pModel->iBone, &(pModel->pBone[0].fQuat[0]));
Shader_LoadUniform4fv(CurrentShader, "GL_T", pModel->iBone, &(pModel->pBone[0].fTrans[0]));

Any solution with the second one?

GClements
01-11-2016, 07:34 AM
Okay I figured out that my bone index in vertex shader was corrupt and I got it fixed by changing it to float type and cast it to integer.
That's less than ideal. My guess would be that the original problem was using glVertexAttribPointer() (which always generates float attributes) rather than glVertexAttribIPointer() (which passes integer attributes without conversion).

GClements
01-11-2016, 08:13 AM
Here is the way I send it atm:
But I don't really like it, I like the way how I send before like this (the fQuat and fTrans are in Bone Struct):
Any solution with the second one?

The glUniform*v() functions don't take a stride. When sending an array, the elements must be contiguous in memory. Provided that your bone structure doesn't have any members other than fQuat and fTrans, you should be able to pass the array of bones via glUniformMatrix2x4fv(). You can't pass the fields separately via two glUniform4fv() calls because the values aren't contiguous.

If the bone structure does have other members, there's no alternative but to copy the data to contiguous arrays.

DavidJr
01-11-2016, 03:13 PM
That's less than ideal. My guess would be that the original problem was using glVertexAttribPointer() (which always generates float attributes) rather than glVertexAttribIPointer() (which passes integer attributes without conversion).

thanks for the information :)


The glUniform*v() functions don't take a stride. When sending an array, the elements must be contiguous in memory. Provided that your bone structure doesn't have any members other than fQuat and fTrans, you should be able to pass the array of bones via glUniformMatrix2x4fv(). You can't pass the fields separately via two glUniform4fv() calls because the values aren't contiguous.

If the bone structure does have other members, there's no alternative but to copy the data to contiguous arrays.

Ah I see, my bone struct has other member than fQuat and fTrans, that's the problem

Btw, a bit off topic question, I have 2 graphic cards, Intel HD 3000 which has GLSL 140 and NVIDIA with 450

I write my shader using 400 core version, question is why I can run that on Intel?

Referring to this question, is there any other way than sending matrix 2x4? Because Intel drivers says mat2x4 was deprecated, that's why I switch to two vec4 :)

Thanks GClements :)

GClements
01-11-2016, 04:50 PM
Ah I see, my bone struct has other member than fQuat and fTrans, that's the problem

Another option is to use a uniform buffer object instead of the default uniform block. This effectively requires fixing the layout of the structure so that it conforms to the std140 layout (at least in terms of its size and the offsets of the fQuat and fTrans fields).



Btw, a bit off topic question, I have 2 graphic cards, Intel HD 3000 which has GLSL 140 and NVIDIA with 450

I write my shader using 400 core version, question is why I can run that on Intel?

If the shader doesn't require any features which the hardware doesn't support, the driver may choose to accept it. Writing a GLSL compiler which understands GLSL 4.0 and making hardware which can (efficiently) execute any valid GLSL 4.0 shader are very different issues.



Referring to this question, is there any other way than sending matrix 2x4? Because Intel drivers says mat2x4 was deprecated, that's why I switch to two vec4

Are you sure that you aren't misinterpreting the message?

DavidJr
01-11-2016, 05:42 PM
Another option is to use a uniform buffer object instead of the default uniform block. This effectively requires fixing the layout of the structure so that it conforms to the std140 layout (at least in terms of its size and the offsets of the fQuat and fTrans fields).
Ah okay, thanks for the info.


If the shader doesn't require any features which the hardware doesn't support, the driver may choose to accept it. Writing a GLSL compiler which understands GLSL 4.0 and making hardware which can (efficiently) execute any valid GLSL 4.0 shader are very different issues.
Good, it is clear for me now.


Are you sure that you aren't misinterpreting the message?
I'm not really sure though, I saw that when I ran it on Intel, or it could be my mistake in my code.

Seems the best way is to go with mat 2x4, I'll try it once again. Thanks for making it clear! :)

DavidJr
01-12-2016, 05:56 AM
OpenGL 3.1 GLSL 140
2223

DavidJr
01-25-2016, 04:29 PM
Seems there's no other way, I will go with uniform buffer object. Thank you! :)