Gần đây tôi đang làm việc về nhập hình động xương, vì vậy tôi đã tạo mô hình 3D giống như minecraft với một số kỹ thuật IK để kiểm tra nhập hoạt ảnh Assimp. Định dạng Ouput là COLLADA (*. Dae), và công cụ tôi sử dụng là Blender. Về phía lập trình, môi trường của tôi là opengl/glm/assimp. Tôi nghĩ rằng những thông tin cho vấn đề của tôi là đủ. Một điều, các hình ảnh động của mô hình, tôi chỉ ghi 7 unmove keyframe để thử nghiệm hoạt hình assimp.Biến đổi xương hoạt hình Assimp
Đầu tiên, tôi đoán chuyển đổi của tôi ngoại trừ phần biến đổi cục bộ là chính xác, vì vậy hãy để hàm chỉ trả về glm::mat4(1.0f)
và kết quả cho thấy mô hình ràng buộc (không chắc chắn). (xem hình bên dưới)
Thứ hai, Xoay lại giá trị glm::mat4(1.0f)
thành bone->localTransform = transform * scaling * glm::mat4(1.0f);
, sau đó là biến dạng của mô hình. (Xem bên dưới hình ảnh)
hình ảnh thử nghiệm và mô hình trong máy xay sinh tố: (bone->localTransform = glm::mat4(1.0f) * scaling * rotate;
: hình ảnh này là dưới mặt đất :()
Mã ở đây:
void MeshModel::UpdateAnimations(float time, std::vector<Bone*>& bones)
{
for each (Bone* bone in bones)
{
glm::mat4 rotate = GetInterpolateRotation(time, bone->rotationKeys);
glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);
glm::mat4 scaling = GetInterpolateScaling(time, bone->scalingKeys);
//bone->localTransform = transform * scaling * glm::mat4(1.0f);
//bone->localTransform = glm::mat4(1.0f) * scaling * rotate;
//bone->localTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f));
bone->localTransform = glm::mat4(1.0f);
}
}
void MeshModel::UpdateBone(Bone * bone)
{
glm::mat4 parentTransform = bone->getParentTransform();
bone->nodeTransform = parentTransform
* bone->transform // assimp_node->mTransformation
* bone->localTransform; // T S R matrix
bone->finalTransform = globalInverse
* bone->nodeTransform
* bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix
for (int i = 0; i < (int)bone->children.size(); i++) {
UpdateBone(bone->children[i]);
}
}
glm::mat4 Bone::getParentTransform()
{
if (this->parent != nullptr)
return parent->nodeTransform;
else
return glm::mat4(1.0f);
}
glm::mat4 MeshModel::GetInterpolateRotation(float time, std::vector<BoneKey>& keys)
{
// we need at least two values to interpolate...
if ((int)keys.size() == 0) {
return glm::mat4(1.0f);
}
if ((int)keys.size() == 1) {
return glm::mat4_cast(keys[0].rotation);
}
int rotationIndex = FindBestTimeIndex(time, keys);
int nextRotationIndex = (rotationIndex + 1);
assert(nextRotationIndex < (int)keys.size());
float DeltaTime = (float)(keys[nextRotationIndex].time - keys[rotationIndex].time);
float Factor = (time - (float)keys[rotationIndex].time)/DeltaTime;
if (Factor < 0.0f)
Factor = 0.0f;
if (Factor > 1.0f)
Factor = 1.0f;
assert(Factor >= 0.0f && Factor <= 1.0f);
const glm::quat& startRotationQ = keys[rotationIndex].rotation;
const glm::quat& endRotationQ = keys[nextRotationIndex].rotation;
glm::quat interpolateQ = glm::lerp(endRotationQ, startRotationQ, Factor);
interpolateQ = glm::normalize(interpolateQ);
return glm::mat4_cast(interpolateQ);
}
glm::mat4 MeshModel::GetInterpolateTransform(float time, std::vector<BoneKey>& keys)
{
// we need at least two values to interpolate...
if ((int)keys.size() == 0) {
return glm::mat4(1.0f);
}
if ((int)keys.size() == 1) {
return glm::translate(glm::mat4(1.0f), keys[0].vector);
}
int translateIndex = FindBestTimeIndex(time, keys);
int nextTranslateIndex = (translateIndex + 1);
assert(nextTranslateIndex < (int)keys.size());
float DeltaTime = (float)(keys[nextTranslateIndex].time - keys[translateIndex].time);
float Factor = (time - (float)keys[translateIndex].time)/DeltaTime;
if (Factor < 0.0f)
Factor = 0.0f;
if (Factor > 1.0f)
Factor = 1.0f;
assert(Factor >= 0.0f && Factor <= 1.0f);
const glm::vec3& startTranslate = keys[translateIndex].vector;
const glm::vec3& endTrabslate = keys[nextTranslateIndex].vector;
glm::vec3 delta = endTrabslate - startTranslate;
glm::vec3 resultVec = startTranslate + delta * Factor;
return glm::translate(glm::mat4(1.0f), resultVec);
}
Ý tưởng đang tham chiếu từ Matrix calculations for gpu skinning và Skeletal Animation With Assimp.
Nói chung, tôi cắt bỏ tất cả thông tin từ assimp thành MeshModel và lưu nó vào cấu trúc xương, vì vậy tôi nghĩ rằng thông tin là ổn chứ?
Điều cuối cùng, đỉnh đang đổ bóng của tôi:
#version 330 core
#define MAX_BONES_PER_VERTEX 4
in vec3 position;
in vec2 texCoord;
in vec3 normal;
in ivec4 boneID;
in vec4 boneWeight;
const int MAX_BONES = 100;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 boneTransform[MAX_BONES];
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
out float Visibility;
const float density = 0.007f;
const float gradient = 1.5f;
void main()
{
mat4 boneTransformation = boneTransform[boneID[0]] * boneWeight[0];
boneTransformation += boneTransform[boneID[1]] * boneWeight[1];
boneTransformation += boneTransform[boneID[2]] * boneWeight[2];
boneTransformation += boneTransform[boneID[3]] * boneWeight[3];
vec3 usingPosition = (boneTransformation * vec4(position, 1.0)).xyz;
vec3 usingNormal = (boneTransformation * vec4(normal, 1.0)).xyz;
vec4 viewPos = view * model * vec4(usingPosition, 1.0);
gl_Position = projection * viewPos;
FragPos = vec3(model * vec4(usingPosition, 1.0f));
Normal = mat3(transpose(inverse(model))) * usingNormal;
TexCoords = texCoord;
float distance = length(viewPos.xyz);
Visibility = exp(-pow(distance * density, gradient));
Visibility = clamp(Visibility, 0.0f, 1.0f);
}
Nếu câu hỏi của tôi ở trên, thiếu mã hoặc mô tả mơ hồ, xin vui lòng cho tôi biết, Cảm ơn bạn!
Edit: (1)
Thêm vào đó, thông tin bởi xương tôi như thế này (mã lấy một phần):
for (int i = 0; i < (int)nodeAnim->mNumPositionKeys; i++)
{
BoneKey key;
key.time = nodeAnim->mPositionKeys[i].mTime;
aiVector3D vec = nodeAnim->mPositionKeys[i].mValue;
key.vector = glm::vec3(vec.x, vec.y, vec.z);
currentBone->transformKeys.push_back(key);
}
đã có một số vector chuyển đổi, do đó, mã của tôi ở trên glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);
, Absloutely, nhận số cùng giá trị từ nó. Tôi không chắc chắn tôi đã thực hiện một hình ảnh động keyframe nomove cung cấp các giá trị biến đổi là đúng hay không (tất nhiên nó có 7 khung hình chính).
Nội dung khung chính như thế này (gỡ lỗi trên xương đầu): 7 khung hình chính khác, cùng giá trị vector.
Edit: (2)
Nếu bạn muốn kiểm tra tập tin dae của tôi, tôi đặt nó trong jsfiddle, đến và mang nó :). Một điều nữa, trong Unity tệp của tôi hoạt động chính xác, vì vậy tôi nghĩ có lẽ không phải biến đổi cục bộ của tôi xảy ra vấn đề, có vẻ như vấn đề có thể là một số khác như parentTransform hoặc bone-> transform ... etc? Tôi cũng thêm ma trận biến đổi cục bộ với tất cả xương, Nhưng không thể tìm ra lý do tại sao COLLADA chứa các giá trị này cho hoạt ảnh chưa được mở của tôi ...