최근 뼈 애니메이션 가져 오기 작업을하고 있습니다. 그래서 Iimp 기술로 3D Minecraft와 같은 모델을 만들어 Assimp 애니메이션 가져 오기를 테스트했습니다. 출력 형식은 COLLADA (*. dae)이고 내가 사용한 도구는 블렌더입니다. 프로그래밍 측면에서, 내 환경은 opengl/glm/assimp입니다. 내 문제에 대한 이러한 정보로 충분하다고 생각합니다. 하나는 모델의 애니메이션으로, 나는 assimp 애니메이션을 테스트하기 위해 7 unmove 키 프레임을 기록합니다.Assimp 애니메이션 뼈대 변환
먼저 로컬 변환 부분을 제외하고는 내 변환이 정확하므로 함수가 glm::mat4(1.0f)
만 반환하도록하고 결과는 바인드 포즈 (확실하지 않음) 모델을 표시합니다. (아래 그림 참조)
두 번째로 glm::mat4(1.0f)
값을 bone->localTransform = transform * scaling * glm::mat4(1.0f);
으로 되돌리고 모델이 변형됩니다. 믹서기에
테스트 이미지와 모델 (이미지 아래 참조) (bone->localTransform = glm::mat4(1.0f) * scaling * rotate;
:이 이미지는 땅 :(아래) :
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);
}
코드 아이디어가 참조 여기에 코드가
Matrix calculations for gpu skinning과 Skeletal Animation With Assimp
전반적으로 assimp에서 MeshModel까지의 모든 정보를 뼈대 구조에 저장하고, 정보가 괜찮은 것 같아요?
마지막 것은, 내 버텍스 쉐이더 코드 :
#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);
}
내 질문에 위의 코드의 부족 또는 막연하게 설명 알려 주시기 바랍니다, 감사합니다!
편집 : (1) 추가에
,이 같은 내 뼈 정보 (코드 가져 오는 부분) :
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);
}
일부 형질 전환 벡터를했다, 그래서 glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);
위의 내 코드, Absloutely는 얻을 같은 값입니다. 변형 값을 제공하는 nomove 키 프레임 애니메이션을 만들었는지 확실하지 않습니다 (당연히 7 키 프레임이 있습니다).
다음과 같은 키 프레임 내용 (머리 뼈의 디버그) : 다른 키 프레임, 동일한 벡터 값.
편집 : (2)
내 DAE 파일을 테스트하려면, 나는 :) 와서 가져 jsfiddle에 넣어. Unity에서 내 파일이 올바르게 작동하는 또 다른 문제는 내 로컬 변환이 문제를 발생시키지 않는다는 것입니다. 문제는 parentTransform 또는 bone-> transform ...과 같은 다른 문제 일 수 있습니다. 나는 또한 모든 뼈와 함께 로컬 변환 행렬을 추가하지만, 왜 COLLADA에 내 unmove 애니메이션에 대해 이러한 값이 포함되어 있는지 파악할 수 없습니다 ...