Bagaimana cara menerapkan animasi kerangka dari file .x (Direct X)?

8

Menggunakan format .x untuk mengekspor model dari Blender, saya dapat memuat mesh, armature, dan animasi. Saya tidak punya masalah menghasilkan mesh dan melihat model dalam game. Selain itu, saya memiliki animasi dan armature dimuat dengan benar ke dalam struktur data yang sesuai.

Masalah saya adalah mengaplikasikan animasi ke model dengan benar. Saya memiliki kerangka kerja untuk menerapkan model dan kode untuk memilih animasi dan melangkah melalui bingkai.

Dari apa yang saya mengerti, bagian AnimationKeydalam AnimationSetmemasok transformasi untuk mengubah pose mengikat ke pose dalam bingkai animasi. Sebagai contoh kecil:

Animation {
  {Armature_001_Bone}
  AnimationKey { 
    2; //Position
    121; //number of frames
    0;3;     0.000000, 0.000000, 0.000000;;,
    1;3;     0.000000, 0.000000, 0.005524;;,
    2;3;     0.000000, 0.000000, 0.022217;;,
    ...
  }
  AnimationKey { 
    0; //Quaternion Rotation 
    121;
    0;4;   -0.707107, 0.707107, 0.000000, 0.000000;;,
    1;4;   -0.697332, 0.697332, 0.015710, 0.015710;;,
    2;4;   -0.684805, 0.684805, 0.035442, 0.035442;;,
    ...
  }
  AnimationKey { 
    1; //Scale
    121;
    0;3;     1.000000, 1.000000, 1.000000;;,
    1;3;     1.000000, 1.000000, 1.000000;;,
    2;3;     1.000000, 1.000000, 1.000000;;,
    ...
  }
}

Jadi, untuk menerapkan frame 2, saya akan mengambil posisi, rotasi, dan skala dari frame 2, membuat matriks transformasi (sebut saja Transform_A) dari mereka dan menerapkan matriks yang dikontrol oleh simpul Armature_001_Bonepada bobotnya. Jadi saya TransformAmemasukkan barang ke shader saya dan mengubah simpul. Sesuatu seperti:

vertexPos = vertexPos * bones[ int(bfs_BoneIndices.x) ] * bfs_BoneWeights.x;

Di mana bfs_BoneIndicesdan bfs_BoneWeightsadalah nilai-nilai khusus untuk simpul saat ini.

Saat memuat dalam simpul jala, saya mengubahnya dengan rootTransformdan meshTransform. Ini memastikan mereka berorientasi dan diskalakan dengan benar untuk melihat pose bind.

Masalahnya adalah ketika saya membuat matriks transformasi (menggunakan posisi, rotasi dan skala dari animasi), itu tidak benar mengubah simpul. Ada kemungkinan lebih dari itu daripada hanya menggunakan data animasi. Saya juga mencoba menerapkan hierarki transformasi tulang, masih tidak ada dadu. Pada dasarnya saya berakhir dengan beberapa model bengkok. Juga harus dicatat bahwa saya bekerja di openGL, jadi setiap transpos matriks yang mungkin perlu diterapkan harus dipertimbangkan.

Data apa yang saya butuhkan dan bagaimana cara menggabungkannya untuk menerapkan animasi .x ke model?

Saya telah membuat beberapa tiruan dari apa ini terlihat, jika itu berguna.

Pertama saya hanya ingin menguji terjemahannya, ini adalah bobbing head, seperti apa di Blender:

http://i.stack.imgur.com/NAc4B.gif

Dan seperti apa itu dalam game (tidak masalah warnanya):

http://i.stack.imgur.com/nj2du.gif

Kemudian untuk rotasi saja, animasi adalah kepala berputar 360 derajat di sekitar sumbu vertikal. Seperti inilah tampilannya dalam game:

http://i.stack.imgur.com/gVyUW.gif

Catatan, seharusnya tidak ada kemiringan, hanya rotasi seperti komidi putar.

Memperbarui

Saya memiliki bagian terjemahan dari karya animasi. Tapi rasanya agak berantakan dan saya tidak tahu bagaimana menerapkannya pada rotasi.

Terjemahan bekerja dengan mengambil langkah-langkah ini:

  1. Ambil posisi dari bingkai animasi dan tukar ydan znilai
  2. Terjemahkan matriks transformasi dengan posisi yang diubah
  3. Ubah posisi matriks transformasi
  4. Terapkan matriks transformasi ke simpul

Jadi itulah bagaimana bisa bekerja, tapi bagaimana itu seharusnya bekerja umumnya untuk posisi, skala dan rotasi?

MichaelHouse
sumber
2
Apakah Anda mengubah simpul dengan matriks pose terbalik sebelum menerapkan skinning?
r2d2rigo
Saya punya, itu punya efek, tapi itu bukan yang diinginkan. Tampaknya mempengaruhi representasi visual dari model (membalikkan semua normals, seperti), tetapi tidak berpengaruh pada gerakan / rotasi / skala.
MichaelHouse
Bisakah Anda memposting tangkapan layar yang menggambarkan masalah?
r2d2rigo
@ r2d2rigo Saya telah memperbarui dengan gif animasi.
MichaelHouse
1
Saya sebagian besar brainstorming di sini, tetapi jika urutan vektor (xyz, zxy) berbeda antara .x dan opengl Anda akan mendapatkan beberapa efek yang menyenangkan. Fakta bahwa transposing membantu artinya menggunakan vektor kolom (atau baris) untuk posisi itu, bukan sebaliknya. en.wikipedia.org/wiki/… memiliki deskripsi rotasi untuk 2D. Saya tidak tahu bagaimana cara memodifikasi angka empat. Atau perbedaan antara format .x dan openGL
Daniel Carlsson

Jawaban:

3

Juga harus dicatat bahwa saya bekerja di openGL, jadi setiap transpos matriks yang mungkin perlu diterapkan harus dipertimbangkan.

Mungkin itu kuncinya, sudahkah Anda mencoba meniadakan beberapa koordinat Z untuk mengkonversi dari koordinat kidal DirectX ke OpenGL yang kanan?

Anda bisa meniadakan semua Zs sebelum menerapkan transformasi Anda, dan meniadakan kembali ketika selesai, melihat apakah hasilnya menjadi lebih baik.

EDIT

Mengganti koordinat Y dan Z adalah cara lain untuk mengubah kidal. Jadi Anda harus menyesuaikan transformasi Anda, periksa makalah ini untuk detailnya .

Fakta bahwa Anda harus memindahkan matriks Anda juga berarti Anda beralih dari baris-utama ke kolom-utama atau sebaliknya. Ini seharusnya tidak terlalu rumit untuk ditangani, Anda mungkin hanya perlu menemukan "tempat" yang tepat untuk melakukannya di saluran pipa Anda. Saya hanya menebak, tetapi melakukannya pada angka empat bisa berarti mengubah mereka menjadi matriks, mengubah posisi, dan kembali angka empat, jika lib Math Anda menawarkan pilihan ini.

Laurent Couvidou
sumber
Agak memberi tahu saya apa yang sudah saya ketahui di sini ...
MichaelHouse
1
Ya, Anda tidak menyebut-nyebut masalah dalam pertanyaan Anda, dan saya yakin itu setidaknya merupakan bagian dari masalah Anda. Saya tidak dapat berasumsi Anda tahu atau tidak tahu bahwa DirectX dan OpenGL mengikuti konvensi yang berbeda pada titik ini (ini sebenarnya sedikit lebih kompleks ). Perhatikan bahwa ini dapat membantu orang lain yang membaca pertanyaan ini untuk melihatnya disebutkan, yang merupakan inti dari seluruh situs web ini.
Laurent Couvidou
Cukup adil, Anda benar. Saya hanya mengisyaratkan fakta bahwa saya tahu tentang konversi yang perlu terjadi ketika saya menyebutkan menggunakan OpenGL dan transpos yang perlu terjadi.
MichaelHouse
2

OK, saya meluangkan lebih banyak waktu untuk ini dan membuatnya bekerja untuk banyak tulang, dan jauh lebih sedikit seperti hack (meskipun masih sedikit). Sistem yang saya miliki di tempat semula hampir benar. Namun, masalah utama adalah:

  1. Blender menyimpan Quaternions dalam format W, X, Y, Z. Saya memuat mereka X, Y, Z, W .
  2. Kode saya untuk mengonversi Quaternion ke matriks salah. Saya sebenarnya masih tidak yakin mengapa ini salah, tapi saya tahu kode berikut berfungsi, sebagai bagian dari kelas Quaternion saya:

    public Matrix4f toMatrix() {
        Matrix4f tmpMatrix = new Matrix4f();
        if (this.length() > 0)
            this.normalise();
    
        float xx = this.x * this.x;
        float xy = this.x * this.y;
        float xz = this.x * this.z;
        float wx = this.x * this.w;
    
        float yy = this.y * this.y;
        float yz = this.y * this.z;
        float wy = this.y * this.w;
    
        float zz = this.z * this.z;
        float wz = this.z * this.w;
        //note the "* -1"s
        //I needed those to make the same matrices Blender was expecting
        tmpMatrix.m00 = (1.0f - 2.0f * (yy + zz)) * -1;
        tmpMatrix.m01 = (       2.0f * (xy - wz)) * -1;
        tmpMatrix.m02 =        2.0f * (xz + wy);
        tmpMatrix.m03 = 0;
    
        tmpMatrix.m10 =        2.0f * (xy + wz);
        tmpMatrix.m11 = 1.0f - 2.0f * (xx + zz);
        tmpMatrix.m12 = (       2.0f * (yz - wx)) * -1;
        tmpMatrix.m13 = 0;
    
        tmpMatrix.m20 =        2.0f * (xz - wy);
        tmpMatrix.m21 =        2.0f * (yz + wx);
        tmpMatrix.m22 = (1.0f - 2.0f * (xx + yy)) * -1;
        tmpMatrix.m23 = 0;
        return tmpMatrix;
    }

Selain itu, hanya saja:

finalMatrix = boneMatrix * skinMatrix * invertedBindMatrix;

Perhatikan bahwa boneMatrixharus menggunakan matriks animasi untuk setiap tulang, bukan matriks mengikat. Ini juga harus mendapatkan semua matriks orang tua seperti:

private Matrix4f getBoneMatrix() {
        if (parent == null) {
            return Matrix4f.mul(Matrix4f.mul(parentArmature.getBindMatrix(), parentArmature.getArmatureRootMatrix(), null), boneMatrix, null);
        } else {
            return Matrix4f.mul(parent.getBoneMatrix(), boneMatrix, null);
        }
    }

Dan itu berhasil. Tinggalkan komentar jika Anda membutuhkan klarifikasi.

MichaelHouse
sumber
Saya menulis beberapa info lebih umum tentang cara agar ini berfungsi di blog saya: byte56.com/2012/12/the-blender-connection.html
MichaelHouse