Reputation: 1
My "engine" is heavily based on this article.
The overall Question: How to attach weapon to "character arm"?
Although animations work for all characters and animations at mixamorg website including multiple animations im having the hardest time trying to take a separate model and attach that model to the character's ARM/Hand.
void ArmedAnimatedModel::attachHand(const glm::vec3& playerPosition) {
std::string boneName = "mixamorig_RightHand";
std::string parentBoneName = "mixamorig_RightForeArm";
Bone* bone = GetBoneByName(boneName);
Bone* parentBone = GetBoneByName(parentBoneName);
glm::mat4 childfinalBoneMatrix = GetFinalBoneMatrixByID(bone->GetBoneID());
glm::mat4 parentfinalBoneMatrix = GetFinalBoneMatrixByID(parentBone->GetBoneID());
// Combine the parent and child bone transformations maybe?
glm::mat4 finalBoneMatrix = childfinalBoneMatrix;
glm::mat4 weaponModelMatrix = glm::mat4(1.0f);
weaponModelMatrix = glm::scale(weaponModelMatrix, glm::vec3(0.01f));
weaponModelMatrix = glm::translate(weaponModelMatrix, glm::vec3(X,Y,Z));
LogMatrix(weaponModelMatrix, "final Weapon Model matrix");
weaponModel->GetShader()->use();
LogMatrix(finalBoneMatrix, "finalBoneMatrix");
auto transforms = finalBoneMatrix;
weaponModel->GetShader()->setMat4("finalBoneMatrix", transforms);
GLint uniformLocation = glGetUniformLocation(weaponModel->GetShader()->ID,
"finalBoneMatrix");
glUniformMatrix4fv(uniformLocation, 1, GL_FALSE,&transforms[0][0]);
GLuint modelLoc = glGetUniformLocation(weaponModel->GetShader()->ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(weaponModelMatrix));
weaponModel->Draw();
}
The shader:
#version 330 core
layout(location = 0) in vec3 aPos; // Vertex position
layout(location = 1) in vec3 aNormal; // Vertex normal
layout(location = 2) in vec2 aTexCoord; // Texture coordinates
out vec2 TexCoord;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 finalBoneMatrix;
void main()
{
vec4 totalPosition = vec4(0.0f);
Normal = mat3(transpose(inverse(model))) * aNormal; // Correct normal transformat
ion
TexCoord = aTexCoord;
vec4 localPosition = finalBoneMatrix * vec4(aPos,1.0f);
totalPosition += localPosition;
mat4 viewModel = view * model;
gl_Position = projection * viewModel * totalPosition; // Final position in clip s
pace
}
I know it looks here that im not passing in the view and projection but i do that somehwere else not trying to muddy up with too much code, below is my vertex shader:
I tried many alternative approaches including multiplying parent by child matrices, but i never get the right location of the arm in WORLD Space or Model Space.
I know the bones are right because its correct relative to each other AND animations work without a hitch...
Upvotes: -2
Views: 150
Reputation: 1
so it turns out there was a way to transform from model space to bone space in my BoneInfoMap object.
struct BoneInfo
{
/*id is index in finalBoneMatrices*/
int id;
std::string parentBoneName;
/*offset matrix transforms vertex from model space to bone space*/
glm::mat4 offset;
};
so i decided to use the inverseMatrix of offset to compute my model/world transformation!
Ultimately this boils down to:
void ArmedAnimatedModel::attachHand(const glm::vec3& playerPosition) {
std::string boneName = "mixamorig_RightHand";
Bone* bone = GetBoneByName(boneName);
glm::mat4 childfinalBoneMatrix = GetFinalBoneMatrixByID(bone->GetBoneID());
BoneInfo boneInfo = GetBoneInfoByName(boneName);
// Combine the parent and child bone transformations
glm::mat4 finalBoneMatrix = childfinalBoneMatrix * inverseMatrix(boneInfo.offset);
glm::mat4 scaleBoneMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f));
glm::mat4 weaponModelMatrix = glm::mat4(1.0f);
glm::mat4 rotationX = glm::rotate(glm::mat4(1.0f), glm::radians(rotX), glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 rotationY = glm::rotate(glm::mat4(1.0f), glm::radians(rotY), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotationZ = glm::rotate(glm::mat4(1.0f), glm::radians(rotZ), glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 rotationMatrix = rotationZ * rotationY * rotationX;
weaponModelMatrix = weaponModelMatrix * rotationMatrix;
weaponModelMatrix = glm::scale(weaponModelMatrix, glm::vec3(0.01f));
weaponModelMatrix = finalBoneMatrix * weaponModelMatrix;
LogMatrix(weaponModelMatrix, "final Weapon Model matrix");
weaponModelMatrix = glm::translate(weaponModelMatrix, playerPosition + glm::vec3(X,Y,Z));
weaponModel->GetShader()->use();
LogMatrix(finalBoneMatrix, "finalBoneMatrix");
GLuint modelLoc = glGetUniformLocation(weaponModel->GetShader()->ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(weaponModelMatrix));
weaponModel->Draw();
}
This leads to the weapon being placed right on the arm! of course the local weapon rotation needs some adjustment but everything is correct across different animation poses!
and as for the shader it is simply:
#version 330 core
layout(location = 0) in vec3 aPos; // Vertex position
layout(location = 1) in vec3 aNormal; // Vertex normal
layout(location = 2) in vec2 aTexCoord; // Texture coordinates
out vec2 TexCoord;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
TexCoord = aTexCoord;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
Really Appreciate the comments and the help! Thank you all!!! :)
Upvotes: -2
Reputation: 31020
Your shader just needs an extra input:
#version 330 core
...
uniform mat4 weapon; /* weapon -> hand */
uniform mat4 hand; /* hand -> model */
uniform mat4 model; /* model -> world */
uniform mat4 view; /* world -> view */
uniform mat4 projection; /* view -> clip */
...
void main()
{
// normal transformation, does not take bone transformation into account so lighting will be screwed up
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoord = aTexCoord;
vec4 modelPosition = hand * weapon * vec4(aPos,1.0f); // Position relative to model
gl_Position = projection * view * model * modelPosition; // Final position in clip space
}
where hand
is the final bone matrix of your hand and weapon
is whatever transformations you want to do relative to the hand (eg your weaponModelMatrix
)
It is also common to make an extra bone as child of the hand that just serves as a weapon attachment point. This allows you to model the weapon with "Y is up" and have it pointing the correct way.
Upvotes: -1