2011-09-29 3 views
11

나는 내 자신의 COLLADA 수입업자를 쓰고있다. 메쉬와 재료 등을 적재하고 있습니다. 그러나 나는 애니메이션에 걸림돌을 쳤다. 특히 관절 회전. COLLADA : 잘못된 공간에서 역 바인드 포즈?

내 메쉬를 스키닝을 위해 사용하고 공식

은 솔직하다 :

weighted; 
for (i = 0; i < joint_influences; i++) 
{ 
    weighted += 
     joint[joint_index[i]]->parent->local_matrix * 
     joint[joint_index[i]]->local_matrix * 
     skin->inverse_bind_pose[joint_index[i]] * 
     position * 
     skin->weight[j]; 
} 
position = weighted; 

그리고 지금까지 문헌에 관한 한,이 올바른 공식이다. 이제 COLLADA는 관절에 대해 두 가지 유형의 회전을 지정합니다. 조인트에 대한 로컬 변환을 얻으려면 회전을 연결해야합니다.

COLLADA 문서에서 구별되지 않는 것은 조인트의 로컬 회전과 조인트의 전역 회전입니다. 그러나 내가 본 대부분의 모델에서 회전은 rotate (글로벌) 또는 jointOrient (로컬) 중 하나의 ID를 가질 수 있습니다.

전역 회전을 무시하고 로컬 회전 만 사용하면 모델의 바인드 포즈가 생깁니다. 그러나 조인트의 지역 변형에 글로벌 회전을 추가하면 이상한 일이 발생하기 시작합니다.

글로벌 회전을 사용하지 않고 있습니다 :

Bind pose

을 그리고 이것은 글로벌 회전 함께 :

Weird

내가 선을 사용하여 골격을 그리기있어 두 스크린 샷에서

만에 첫눈은 관절이 메쉬 안에 있기 때문에 보이지 않습니다. 두 번째 스크린 샷에서 꼭지점이 모든 곳에 있습니다!

Collada viewer

그것은 볼 어렵습니다,하지만 당신은 관절이 두 번째 스크린 샷에서 올바른 위치에 있는지 볼 수 있습니다

는 비교를 위해,이 두 번째 스크린 샷 과 같아야 것입니다.

하지만 지금 이상한 일. 내가 COLLADA에 의해 지정된 포즈 역 바인드를 무시하고 대신 공동의 부모의 역을 맡으면 지역 공동의 지역 변환 시간을 변환, 나는 다음과 같은 얻을 :

enter image description here

를이 스크린 샷에서 나는 그리기 해요 각 꼭지점에서 영향력이있는 관절까지의 선. 수식 지금이되기 때문에 나는 포즈 바인드를 얻을 사실은 이상한되지 않습니다 :

world_matrix * inverse_world_matrix * position * weight 

을하지만 COLLADA의 역 바인드가 잘못된 공간에 포즈 의심하는 날 리드.

내 질문은 : 어떤 공간에서 COLLADA가 역 바인드 포즈를 지정합니까? 그리고 어떻게 역 바인드 포즈를 필요한 공간으로 변환 할 수 있습니까?

+0

1.4.1 사양의 "COLLADA에서 스켈레톤 스키닝"섹션을 읽으셨습니까? 귀하의 공식은 – jterrace

답변

10

필자가 Assimp (오픈 소스 모델 로더)에서 읽은 값과 내 값을 비교하여 시작했습니다. 코드를 살펴보면서 어디에서 바인드 행렬과 역 바인드 행렬을 만들었는지 살펴 보았습니다.

// Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose 
// Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform 
for(size_t a = 0; a < mesh->mNumBones; ++a) 
{ 
    const aiBone* bone = mesh->mBones[a]; 
    const aiMatrix4x4& currentGlobalTransform 
     = GetGlobalTransform(mBoneNodesByName[ bone->mName.data ]); 
    mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix; 
} 

globalInverseMeshTransform

항상 정체성이다, 메쉬 아무것도 변화하지 않기 때문에 :

결국 나는 다음과 같은 포함하는, SceneAnimator::GetBoneMatrices에 끝났다. currentGlobalTransform은 조인 행렬이며 조인트의 부모 행렬은 조인트의 로컬 행렬과 연결됩니다. mOffsetMatrix은 피부에서 직접 오는 역 바인드 행렬입니다.

나는이 매트릭스의 값을 본인 스스로 확인했다. (시계 창에서 비교해 봤다.) 정확히 0.0001 % 정도 차이가 났지만 그다지 중요하지 않다. 그렇다면 Assimp의 버전 작업과 광산은 수식이 동일하더라도 왜 작동하지 않습니까?

여기에 내가 가진 무엇 :

Inversed!

Assimp 마침내 스킨 쉐이더에 행렬을 업로드, 그들은 다음을 수행하십시오

helper->piEffect->SetMatrixTransposeArray("gBoneMatrix", (D3DXMATRIX*)matrices, 60); 

Waaaaait 두 번째. 업로드 한 파일은 입니다. 그렇게 쉬울 수는 없습니다. 안돼.

enter image description here

그래.

내가 잘못하고있는 것 : 좌표계를 올바른 시스템 (센티미터에서 미터로) 으로 변환하기 전에 스키닝 행렬 적용. 행렬은 원래 좌표계 용으로 설계 되었기 때문에 결과적으로 완전히 왜곡 된 모델이됩니다.

미래 Google 직원

  • 은 (회전, 번역, 규모 등) 모든 노드 변환은 당신이 그들을받을 순서를 읽어보십시오.
  • 조인트의 로컬 매트릭스에 연결하십시오.
  • 조인트의 부모를 가져 와서 로컬 매트릭스와 곱하십시오.
  • 바인드 매트릭스으로 저장하십시오.
  • 피부 정보를 읽으십시오.
  • 조인트의 역 바인드 포즈 행렬을 저장하십시오.
  • 각각의 버텍스에 대해 가중치 을 저장하십시오.
  • 는 곱하기 역 바인드 와 결합 매트릭스 매트릭스 포즈와 , 그것은 트랜스 포즈 스키닝 행렬 호출.
  • 위치와 스킨 행렬 배 중량 조인트 와 가중 위치에 추가.
  • 가중치 위치을 사용하여 렌더링합니다.

완료!

+0

을 보입니다. 이전 질문이지만 매우 도움이됩니다! 고마워요! – Jas

1

마지막으로 행렬을 이항하지 않고로드 할 때 행렬을 조 변경하면 (애니메이션을 적용 할 때 문제가 될 수 있음) 곱셈을 다르게 수행하려는 것입니다. 위에서 사용 된 메서드는 스킨을 사용하는 것으로 나타납니다. OpenGL 친화적 인 행렬을 사용하는 경우 DirectX - 전치 행렬)

DirectX에서는 파일에서로드 된 행렬을 변환 한 다음 사용합니다 (아래 예에서는 간단히하기 위해 바인드 포즈를 적용하고 있습니다) :

XMMATRIX l_oWorldMatrix = XMMatrixMultiply (l_oBindPose, in_oParentWorldMatrix);

XMMATRIX l_oMatrixPallette = XMMatrixMultiply (l_oInverseBindPose, l_oWorldMatrix);

XMMATRIX l_oFinalMatrix = XMMatrixMultiply (l_oBindShapeMatrix, l_oMatrixPallette);