2011-09-29 9 views
11

Sto lavorando alla scrittura del mio importatore COLLADA. Sono arrivato abbastanza lontano, caricando mesh e materiali e così via. Ma ho colpito un ostacolo sull'animazione, in particolare: rotazioni congiunte.COLLADA: la posa a ritroso inverso nello spazio sbagliato?

La formula che sto utilizzando per la scuoiatura le mie maglie è straight-forward:

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; 

E per quanto riguarda la letteratura è interessato, questa è la formula corretta. Ora, COLLADA specifica due tipi di rotazioni per le articolazioni: locale e globale. Devi concatenare le rotazioni insieme per ottenere la trasformazione locale per il giunto.

Ciò che la documentazione COLLADA non distingue tra la rotazione locale del giunto e la rotazione globale del giunto. Ma nella maggior parte dei modelli che ho visto, le rotazioni possono avere un identificativo di rotate (globale) o jointOrient (locale).

Quando ignoro le rotazioni globali e utilizzo solo quelle locali, ottengo la posa di collegamento per il modello. Ma quando aggiungo le rotazioni globali alla trasformazione locale del giunto, cominciano a succedere cose strane.

Questo è senza utilizzare rotazioni globali:

Bind pose

E questo è con rotazioni globali:

Weird

In entrambe le immagini sto disegnando lo scheletro utilizzando linee, ma in il primo è invisibile perché le articolazioni sono all'interno della mesh. Nella seconda schermata i vertici sono dappertutto!

Per fare un confronto, questo è ciò che il secondo screenshot dovrebbe simile:

Collada viewer

E 'difficile da vedere, ma si può vedere che i giunti siano nella posizione corretta nel secondo screenshot.

Ma ora la cosa strana. Se io trascuro l'associazione inversa pongono come specificato da COLLADA e invece prendo l'inverso della madre del locale comune di trasformare i tempi del locale comune trasformare, ottengo il seguente:

enter image description here

In questo screenshot sto disegnando un linea da ciascun vertice alle articolazioni che hanno influenza. Il fatto che ho la bind posa non è così strano, perché la formula diventa ora:

world_matrix * inverse_world_matrix * position * weight 

Ma mi porta a sospettare che legano inversa di COLLADA pongono è nello spazio sbagliato.

Quindi la mia domanda è: in quale spazio COLLADA specifica la sua posizione inversa? E come posso trasformare la posa del binding inverso nello spazio che mi serve?

+0

Hai letto "Skinning a Skeleton in COLLADA" nella sezione 1.4.1? La tua formula guarda fuori – jterrace

risposta

10

Ho iniziato confrontando i miei valori con quelli che ho letto da Assimp (un caricatore di modelli open source). Passando attraverso il codice ho guardato dove hanno costruito le loro matrici di legame e le loro matrici di inversione del legame.

Alla fine sono finito in SceneAnimator::GetBoneMatrices, che contiene quanto segue:

// 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 è sempre l'identità, perché la rete non trasforma nulla. currentGlobalTransform è la matrice di bind, le matrici locali del genitore congiunto concatenate con la matrice locale del giunto. E mOffsetMatrix è la matrice di bind inversa, che proviene direttamente dalla skin.

Ho controllato i valori di queste matrici per conto mio (oh sì li ho confrontati in una finestra di controllo) ed erano esattamente uguali, spenta forse dello 0,0001% ma ciò è insignificante. Quindi perché la versione di Assimp funziona e la mia non funziona anche se la formula è la stessa?

Ecco quello che ho ottenuto:

Inversed!

Quando Assimp carica, infine, le matrici allo shader scuoiatura, che fanno il seguente:

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

Waaaaait un secondo. Li caricano trasposto? Non potrebbe essere così facile. Non c'è modo.

enter image description here

Yup.

Un'altra cosa che stavo facendo male: stavo convertendo le coordinate del sistema giusto (centimetri a metri) prima dello applicando le matrici di skin. Ciò si traduce in modelli completamente distorti, poiché le matrici sono progettate per il sistema di coordinate originale.

GOOGLER FUTURE

  • Leggere tutte le trasformazioni dei nodi (Ruota, traduzione, scala, ecc) nell'ordine di ricezione.
  • Concatenarli a una matrice locale .
  • Prendere il genitore del giunto e moltiplicarlo con la matrice locale.
  • Memorizza come matrice .
  • Leggere le informazioni sulla pelle.
  • Memorizzare la matrice di posa di binding inverso del giunto.
  • Conservare il comune pesi per ciascun vertice.
  • Moltiplicare la matrice legano con l'associazione inversa posa matrice e trasporla, chiamano la matrice scuoiatura.
  • Moltiplicare la matrice spellatura con la posizione volte il giunto peso ed aggiungerlo alla posizione ponderata.
  • Utilizzare la posizione ponderata per il rendering.

Fatto!

+0

Vecchia domanda ma molto utile! Grazie mille! – Jas

1

BTW, se si traspongono le matrici al momento del loro caricamento invece di trasporre la matrice alla fine (che può essere problematica durante l'animazione) si desidera eseguire la moltiplicazione in modo diverso (il metodo che si utilizza sopra sembra essere l'utilizzo di skinning in DirectX quando si usano matrici OpenGL - ergo the transpose.)

In DirectX I traspone matrici quando vengono caricate dal file e quindi io uso (nell'esempio seguente sto semplicemente applicando la posa di collegamento per motivi di semplicità) :

XMMATRIX l_oWorldMatrix = XMMatrixMultiply (l_oBindPose, in_oParentWorldMatrix);

XMMATRIX l_oMatrixPallette = XMMatrixMultiply (l_oInverseBindPose, l_oWorldMatrix);

XMMATRIX l_oFinalMatrix = XMMatrixMultiply (l_oBindShapeMatrix, l_oMatrixPallette);

Problemi correlati