Advanced Meshes
Level 9 GRAFIKA KOMPUTER DAN ANIMASI
2
Using Basic Meshes
What is a Mesh?
Making Preconstructed Meshes
The Finished Program
Loading Meshes from X Files
About Subsets
Loading an X File to a Mesh
The Finished Program
Loading Textured Meshes
Loading and Displaying Textures
The Finished Program Animated Meshes
Basic Concepts
Loading the Mesh
Rendering the Mesh
Cleanup
The Finished Program
4
Tanpa menggunakan tekstur, sangatlah sulit untuk membuat pemodelan yang realistis.
Untungnya, meshes memiliki kemampuan untuk
menambahkan tekstur ke suatu file .x, sehingga Anda tidak perlu menambahkannya secara manual untuk setiap tekstur yang ada.
Sayangnya, terdapat beberapa code tambahan yang perlu diterapkan.
Akan dijelaskan pada pertemuan kali ini.
G px?lessonid=9-6-3
2 langkah untuk menampilkan tekstur:
1. Load the textures while loading the mesh
6
G -H A N S U N
Creates a blank texture for each subset
G -H A N S U N
8
10
12
14
16
18
20
G -H A N S U N
Jangan lupa .x file diletakkan dalam folder project
Anda.
Untuk contoh ini, airplane 2.x beserta file
22
Untuk membuat suatu animasi, tidak cukup hanya dengan memanggil fungsi D3DXLoadMeshFromX().
Terdapat beberapa hal yang perlu diketahui terlebih dahulu, seperti:
Mesh skeletons
Mesh hierarchy
Frames and mesh containers
Skinning and vertex weight
Keyframes
Model animasi memiliki cara yang lebih baik untuk menangani dirinya sendiri.
Daripada mengubah koordinat tiap titik setiap kali proses render dilakukan, 3D art programs
menanganinya dengan menggunakan skeletons.
Skeleton merupakan kumpulan obyek-obyek yang
disebut bones, yang digunakan oleh seorang animator
untuk mengubah bentuk dari modelnya.
24
G -H A N S U N
Dalam DirectX, digunakan matriks untuk
merepresentasikan joints yang menggambarkan apa yang terjadi dalam code programnya.
Setiap matriks merepresentasikan satu joint dan
dapat memiliki rotasi dan translasi.
Matriks setiap joint memiliki informasi rotasi joint
dan posisi joint terhadap matriks terakhir lainnya.
3D modeling program membangun matriks-matriks
ini untuk Anda.
Setelah di-load, Anda dapat mengikuti hirarki model, dengan mengalikan matriks-matriks tersebut.
26
G -H A N S U N
Terdapat 2 komponen dalam animated mesh: joints
dan mesh containers.
Joint disebut juga sebagai frame.
Mesh container adalah suatu struct yang menyimpan
seluruh data tentang mesh, atau suatu bagian dari
mesh.
Frame adalah suatu struct yang mengandung suatu
matriks, yang mendefinisikan lokasi dan rotasi suatu
28
Jika bones merupakan bagian yang menyatukan
semuanya, maka skin adalah apa yang Anda lihat di permukaan.
Skin adalah suatu larik polygons yang membangun suatu model.
Skin disimpan dalam mesh container dari suatu
animated mesh sebagai titik-titik dan indeks-indeks.
Dalam animated mesh, setiap titik disimpan dalam suatu frame (joint) dan memiliki suatu bobot.
Bobot (weight) merupakan suatu nilai yang
menentukan seberapa besar suatu titik dipengaruhi oleh perubahan joint.
Keyframe merupakan posisi suatu mesh yang mendefinisikan titik awal dan akhir dari suatu animasi.
Sekumpulan keyframes disimpan dalam animated
mesh.
Setelah DirectX menentukan posisi awal dan akhir dan berapa lama waktu yang dibutuhkan dari satu posisi ke posisi lainnya, DirectX akan menghitung sekumpulan matriks baru untuk mesh setiap kali
mesh di-render.
Hal ini membuat animasi menjadi mudah.
30
Merupakan langkah terbanyak yang perlu dilakukan.
DirectX 9 memberikan kita kendali penuh untuk
mengatur bagaimana data mesh dan hirarki disimpan dalam memory.
Memberikan programmer kendali penuh terhadap
mesh dengan mengizinkan mereka untuk menulis
allocation code sendiri.
G
Sangat berguna karena animasi mesh
dapat bervariasi tergantung pada lingkungan, seperti karakter model yang memanjat tebing, dan sebagainya.
Meskipun memberikan banyak fleksibilitas bagi game
developers, namun sayangnya hal ini juga membuat
banyak hal menjadi lebih rumit, karena API untuk
animated mesh belum dikembangkan dengan terlalu
baik, dan banyak hal yang harus dikerjakan.
3 hal yang harus dilakukan untuk me-load dan menyiapkan suatu animated mesh:
1. Load the data from the .x file
2. Take each frame and mesh container and store it
in memory
3. Link each mesh container to its connecting frames
32
Sayangnya urutan dalam coding tidak sama persis seperti urutan yang diberikan sebelumnya.
Yang harus dilakukan dalam menulis code-nya:
1. Add to the D3DXFRAME and
D3DXMESHCONTAINER structs
2. Write the four mesh allocation and deallocation
functions
3. Call the allocation functions using
D3DXLoadMeshHierarchyFromX()
4. Allocate memory for the modified frame positions 5. In each mesh container, store a pointer to each
frame associated with it
34
Kedua structs tersebut membawa semua variabel yang dibutuhkan untuk me-load hirarki dari frames
dan mesh containers, namun belum memiliki semua
nilai yang dibutuhkan untuk me-render-nya.
Perlu ditambah nilai-nilai tertentu, dengan cara membuat struct kita sendiri.
36
G -H A N S U N
38
Pada langkah ke-3, kita akan memanggil fungsi D3DXLoadMeshHierarchyFromX().
Fungsi ini akan memulai seluruh proses loading, yakni me-load data dan menyiapkannya untuk dialokasikan.
Sayangnya, kita harus melakukan alokasi dan dealokasi-nya sendiri.
D3DXLoadMeshHierarchyFromX() memanggil
sekumpulan fungsi untuk mengatur mana yang harus dialokasikan dan mana yang didealokasikan.
Yang disediakan hanyalah prototype, yang tersimpan dalam ID3DXAllocateHierarchy interface.
G -H A N S U N
A macro that defines a COM function that returns an HRESULT Common function
40
DirectX loads a new
joint from the x file Name of the frame Create a new pointer and allocate
memory for it
Contain the address of CUSTOM_FRAME
Initialize the new CUSTOM_FRAME with ZeroMemory()
Fungsi ini dipanggil saat suatu mesh container di-load
dari x file.
Mengikuti pola yang sama seperti CreateFrame(), dimana kita mengalokasikan memory untuk suatu
mesh container baru, membersihkannya (zero it), dan
kemudian meng-copy parameter-parameternya.
Namun fungsi ini sedikit lebih kompleks karena ada banyak parameter yang harus di-copy.
42
44
46
A. Create and initialize the custom mesh container struct B. Check to make sure it’s a normal mesh
C. Copy the name
D. Copy the mesh data E. Copy the materials
F. Copy the number of materials G. Copy the adjacency data
H. Copy the skin data (if any)
I. Allocate memory for the ppFrameMatrices value J. Create a duplicate of the mesh
K. Load each texture
Fungsi ini dimulai dengan cara yang sama seperti pada CreateFrame().
Pertama dibentuk suatu mesh container baru (yang disebut pMeshContainer), mengatur parameter ppNewMeshContainer ke alamat baru yang sama, dan kemudian menghapus memory-nya.
Ingat pMeshContainer ini karena akan sering digunakan.
48
Terdapat 3 jenis mesh, yakni
1. Patch Meshes, baik digunakan untuk me-render
kurva (namun kurang cepat).
2. Progressive Meshes, dapat mengatur dirinya sendiri
untuk memiliki titik-titik yang lebih sedikit dan
me-render lebih cepat.
3. Normal Meshes, normal dan akan kita gunakan.
G -H A N S U N
Check to make sure it’s a normal
mesh
Deallocate all the memory this function allocates
50
Sama seperti saat kita meng-copy nama suatu frame.
Bedanya hanyalah mengganti pFrame dengan pMeshContainer.
Langkah ini akan meng-copy nama dari parameter
‘Name’ ke pMeshContainer->Name.
G -H A N S U N
Copy the mesh type
Using the AddRef() function which allows a COM object to continue even after the Release()
function has been called
52
G -H A N S U N
Allocate some memory for the array of materials
Loop through each D3DXMATERIAL and copy it, and make the ambient
54
Adjacency data adalah informasi tentang
segitiga-segitiga apa yang saling bertautan satu dengan yang lainnya.
Terdiri dari suatu larik DWORDs, dan berukuran 3
kali lebih besar (satu DWORD untuk 1 sisi segitiga).
Saat mengalokasikan larik, digunakan fungsi GetNumFaces() untuk memperoleh jumlah
permukaan segitiga, lalu mengalikannya dengan 3.
Mesh merupakan suatu COM object, dan cara
meng-copy-nya mudah, cukup copy pointer-nya dan panggil fungsi AddRef().
Namun, tidak selalu ada informasi skin.
Model-model yang tidak dianimasikan tidak
menggunakan skin information, sehingga kita copy
pointer dan panggil AddRef() hanya jika modelnya
dianimasikan.
56
Merupakan suatu larik pointer-pointer yang merujuk
pada matriks-matriks frame.
Digunakan GetNumBones() untuk memperoleh jumlah frame yang ada, mengalokasikan sebanyak ruang tersebut ke ppFrameMatrices, kemudian
me-loop kembali satu per satu dengan GetNumBones() dan mengatur nilainya menjadi NULL.
Pada langkah ini, digunakan fungsi CloneMesh() untuk membuat tiruan mesh.
G
A mesh copy of the original, will be used to change all the vertices around as the animation progressed
Flags for memory management, use D3DXMESH_MANAGED
Pointer to device, d3dev Used when we want to change
58
Pada langkah ini, kita me-loop setiap material, lalu me-load tekstur-nya jika ada.
Perhatikan bahwa kita me-load tekstur ke dalam pMeshContainer->pTextures[i]; dan kita harus mengalokasikan ruang yang dibutuhkan terlebih dahulu, dengan pMeshContainer->NumMaterials.
MaxFrames merupakan global variabel yang
menyimpan jumlah maksimum frame yang akan dikaitkan dengan sembarang mesh container.
Dibutuhkan untuk langkah ke-4 dalam proses loading
mesh berikutnya.
Dimulai dengan mengecek ada atau tidaknya
informasi skin, lalu digunakan fungsi GetNumBones() untuk memperoleh jumlah frames, kemudian
dibandingkan dengan angka sebelumnya (jika ada), dan ambil nilai terbesarnya dengan fungsi max().
60
G -H A N S U N
Two macros which similar to SAFE_RELEASE()
A macro that checks a pointer to make sure it can be deleted, deletes it, and sets it to NULL
Pada tahap ini kita melepas dan men-dealokasi-kan seluruh hal yang dialokasikan di fungsi
CreateMeshContainer().
62
64
66
68
Fungsi ini dipanggil dari dalam fungsi init_graphics().
D3DXLoadMeshHierarchyFromX() adalah fungsi yang memulai seluruh proses loading.
Hal pertama yang dilakukannya adalah me-load data
dari x file.
Kemudian memanggil CreateMeshContainer() dan CreateFrame() berulang kali hingga tidak ada lagi
frames dan mesh containers tersisa.
Setelah seluruh data di-copy, fungsi ini akan
mempersiapkan hal-hal lainnya di belakang layar.
G
The filename of the .x file we wish to load
How the memory is managed for the mesh
A pointer to that big class we just wrote
Usual d3ddev
A pointer to a pointer to an animation controller
A pointer to a pointer to a frame.
70
Pada langkah ini, kita akan mengalokasikan memori untuk suatu array matriks-matriks.
Saat DirectX menganimasi mesh containers, DirectX menginginkan frames ditangani sebagai suatu array
matriks-matriks, daripada suatu array dari D3DXFRAMEs atau CUSTOM_FRAMEs.
G
Highest number of frames any mesh container will need
72
Tujuan dari langkah ini adalah menginisialisasi
ppFrameMatrices member untuk setiap mesh container.
Pertama perlu ditemukan seluruh mesh container.
Caranya dengan mencari dalam setiap frame dan cek pMeshContainer dari setiap frame. Setelah looping
seluruh frames, kita temukan semua mesh containers.
Ingat setiap mesh container dapat memiliki lebih dari 1
frame. Fungsi GetNumBones() memberitahu kita berapa banyak frame-nya. Untuk setiap mesh container, kita loop
setiap frame dan buat ppFrameMatrices[] mengarah pada
combined matrix frame.
74
Me-render suatu mesh jauh lebih mudah daripada me-load-nya.
Terdapat 4 langkah dasar:
1. Advance the time in the animation controller,
getting new animation data
2. Update each combined matrix with the new data 3. Update each mesh container using the combined
matrices
4. Render each mesh container individually
76
Akan digunakan fungsi AdvanceTime(), yang
merupakan anggota dari AnimationController yang dirujuk saat kita memanggil
D3DXLoadMeshHierarchyFromX().
Merupakan suatu obyek COM yang menangani seluruh animasi di belakang layar.
Pada dasarnya, kita cukup memberikan parameter yang kita ingin agar dilakukan oleh model, dan obyek tersebut akan melalui seluruh CUSTOM_FRAMEs dan meng-update seluruh matriks untuk kita.
Untuk saat ini, parameter yang diisi cukup jumlah waktu yang berlalu sejak model terakhir di-render.
78
Baris pertama code mengecek apakah ada animasi atau
tidak.
Di dalam if(), terdapat sebuah variabel bernama Time yang bersifat static. Variabel tersebut diinisialisasi dengan fungsi GetTickCount() yang mengembalikan jumlah
waktu OS telah berjalan dalam miliseconds.
Selanjutnya digunakan AdvanceTime() yang memiliki 2
parameter, tapi yang akan digunakan hanya parameter pertama yang mengindikasikan jumlah waktu (dalam detik) animasi tersebut mesti berjalan.
Di baris terakhir dalam if(), kita me-reset variabel Time
untuk render berikutnya lagi.
Fungsi AdvanceTime() terhubung, di belakang layar, dengan puncak dari mesh hierarchy.
Artinya fungsi tersebut mampu menelusuri dan meng-update setiap frame dari
TransformationMatrix.
Namun, di awal kita gunakan matriks tambahan
untuk tiap frame, yakni CombTransformationMatrix.
Untuk langkah ini, kita panggil fungsi rekursif lainnya, yakni update_frames().
Fungsi ini akan menelusuri tiap frame, satu per satu, dan meng-update CombTransformationMatrix.
80
82
Setelah meng-update setiap frame matrices, kita harus menerapkan data tersebut ke mesh containers yang sebenarnya.
Akan digunakan fungsi UpdateSkinnedMesh() untuk
tiap mesh container.
Sebelum melakukannya, kita harus menerapkan apa yang disebut sebagai offset matrices, yang akan me-reposisi mesh containers sehingga animation matrices
diterapkan dengan benar.
Pertama, perhatikan fungsi rekursif update_mesh_containers() berikut.
84
matrices with offsets
Updating the mesh
Fungsi ini juga rekursif dan berjalan di seluruh
frames.
Parameter fungsi yang diberikan adalah pointer ke TopFrame.
Di baris pertama isi, kita buat suatu pointer mesh
container dan memperoleh pointer-nya dari pFrame.
Selanjutnya kita punya if() statement.
Kita hanya akan melakukan proses selanjutnya bila terdapat mesh container yang memiliki informasi skin. Jika tidak ada salah satunya, maka kita cukup rekursif
86
Di dalam if(), terdapat for() loop.
Kita peroleh nilai NumFrames dari GetNumBones(), dan
menggunakannya dalam loop.
Di dalam loop digunakan fungsi baru yang disebut
GetBoneOffsetMatrix(), yang diperoleh dari pSkinInfo.
Suatu offset matrix adalah matriks untuk suatu frame yang
memindahkan titik-titik yang dipengaruhi oleh suatu frame ke pusat dari model secara keseluruhan.
Agar modelnya dapat tampil dengan benar harus digandakan
frame matrices dengan frame offset matrices.
Di dalam loop kita set FinalMatrices ke frame offset
menggunakan GetBoneOffsetMatrix(), lalu dikalikan dengan frame matrix.
Updating the Mesh
88
Updating the Mesh
G
The array of matrices to apply Advanced, set it NULL
A pointer to the mesh where the resulting mesh will be saved, has to be locked A pointer to a mesh where
the original mesh is stored, has to be locked
Flags that handle various details about the lock, set it NULL
Satu fungsi lagi yang akan dibahas adalah
draw_mesh(), yang juga merupakan fungsi rekursif.
90
Seperti bagian lainnya, parameter untuk fungsi ini adalah suatu pointer ke suatu frame, dan kita
kirimkan TopFrame.
Baris pertama membuat pMeshContainer, pointer yang diperoleh dari pFrame->pMeshContainer.
Selanjutnya dipastikan ada atau tidaknya mesh
container, karena kita ingin menggambarnya.
Jika ada, kita loop setiap material. Karena terdapat
subset untuk setiap material, kita set material, tekstur, dan baru kemudian menggambar subset-nya.
Sisa dari code tersebut adalah pemanggilan rekursif seperti bagian lainnya.
92
Jangan lupa, kita juga harus membersihkan memory
yang telah dialokasikan sebelumnya.
Beberapa hal yang perlu dilakukan:
1. Release the animation controller
2. Free the memory allocated for the animated mesh 3. Free the FinalMatrices array
Digunakan fungsi D3DXFrameDestroy().
G -H A N S U N
The pointer to the topmost frame, or TopFrame
94
96
98
100
102
104
106
108
110
112
114
116
Untuk menjalankan code di atas, diperlukan Tiny.x
model, dan teksturnya, Tiny_skin.dds.
Kedua files tersebut dapat ditemukan dalam folder
Samples di dalam DirectX SDK.
118
http://directxtutorial.com/ Other web resources.