摘要:XNA Creator Club – Simple Animation Part2
首先先看一張圖片
這張圖片是本範例的模型架構圖,這張圖片可以看出整個模型的架構,為什麼要貼上這張圖片呢?這就是接下來的關鍵了,要讓模型隨著旋轉角度的不同做旋轉,當然要了解,現在是哪個元件需要做轉動,所以我們就必須知道模型的整個設定資料。
首先我們宣告一些變數
Model tankModel;
上面的宣告式使用XNA Framework的Model類別,將等等載入的模型資訊儲存起來
ModelBone leftBackWheelBone;
ModelBone rightBackWheelBone;
ModelBone leftFrontWheelBone;
ModelBone rightFrontWheelBone;
ModelBone leftSteerBone;
ModelBone rightSteerBone;
ModelBone turretBone;
ModelBone cannonBone;
ModelBone hatchBone;
上面的宣告就是用來存放骨架的參考,因為等等就是用控制骨架,讓模型去做轉動。這邊就是讓等等要轉動的物件,我們先載入他們骨架。
ModelBone leftBackWheelBone;
ModelBone rightBackWheelBone;
ModelBone leftFrontWheelBone;
ModelBone rightFrontWheelBone;
ModelBone leftSteerBone;
ModelBone rightSteerBone;
ModelBone turretBone;
ModelBone cannonBone;
ModelBone hatchBone;
上面的宣告就是儲存每個動畫的骨架轉換的矩陣
Matrix[] boneTransforms;
這個宣告是準備儲存,所有骨架的轉換矩陣,也就是你在上面看到的所有小格子的物件的轉換矩陣。
float wheelRotationValue;
float steerRotationValue;
float turretRotationValue;
float cannonRotationValue;
float hatchRotationValue;
上述宣告,用來儲存各個需要旋轉的部位的角度
public float WheelRotation
{
get { return wheelRotationValue; }
set { wheelRotationValue = value; }
}
這個部分,就是C#特有的方式,可以去做參數的設定,GET就是取得參數數值,SET就是設定數值,這個方式類是get、set函數的方式,只是他應該不算式函數。
接下來看看Load函數,他所傳入的參數就是ContentManager類別,這個類別等等可以載入我們要的模型。
tankModel = content.Load<Model>("Content/tank");
用ContentManager的Load函數將模型載入進來,存在Model裡面的類別
leftBackWheelBone = tankModel.Bones["l_back_wheel_geo"];
rightBackWheelBone = tankModel.Bones["r_back_wheel_geo"];
leftFrontWheelBone = tankModel.Bones["l_front_wheel_geo"];
rightFrontWheelBone = tankModel.Bones["r_front_wheel_geo"];
leftSteerBone = tankModel.Bones["l_steer_geo"];
rightSteerBone = tankModel.Bones["r_steer_geo"];
turretBone = tankModel.Bones["turret_geo"];
cannonBone = tankModel.Bones["canon_geo"];
hatchBone = tankModel.Bones["hatch_geo"];
上面的宣告使用Model的Bones將Bone讀入,當作等一下要做動畫的骨架,使用的方法就是上面的方式,然後Bone裡面的就是上面那張圖片架構圖的名稱。
leftBackWheelTransform = leftBackWheelBone.Transform;
rightBackWheelTransform = rightBackWheelBone.Transform;
leftFrontWheelTransform = leftFrontWheelBone.Transform;
rightFrontWheelTransform = rightFrontWheelBone.Transform;
leftSteerTransform = leftSteerBone.Transform;
rightSteerTransform = rightSteerBone.Transform;
turretTransform = turretBone.Transform;
cannonTransform = cannonBone.Transform;
hatchTransform = hatchBone.Transform;
儲存原始的動畫骨架的轉換矩陣
boneTransforms = new Matrix[tankModel.Bones.Count];
實作骨架轉換矩陣的矩陣陣列,這邊會儲存上面那張圖片的所有骨骼架構。
在Draw函數裡面傳入三個參數,分別就是World、View、Projection Matrix
tankModel.Root.Transform = world;
設定世界矩陣為模型的Root轉換矩陣,這樣個做法就是你可以針對模型直接做放大、移動等處理,這樣做比較方便,直接針對Root的轉換矩陣做處理。
這邊的轉換矩陣,給的感覺就像是,他是一個矩陣紀錄所有模型的資訊,可能會是座標,或是比例等情況,如果你要對他做動作的話,可能就需要去對那個物件的Transform Matrix做矩陣的運算。(光從以上的敘述可能不了解,建議可以加上Matrix.CreateScale(4,2,1)去做矩陣乘法,可以看到差異性)
Matrix wheelRotation = Matrix.CreateRotationX(wheelRotationValue);
Matrix steerRotation = Matrix.CreateRotationY(steerRotationValue);
Matrix turretRotation = Matrix.CreateRotationY(turretRotationValue);
Matrix cannonRotation = Matrix.CreateRotationX(cannonRotationValue);
Matrix hatchRotation = Matrix.CreateRotationX(hatchRotationValue);
這邊處理的事情,就是設定角度,針對XYZ軸去做轉動,因為一台車可能就是Y軸或是X軸的去做轉動(這也是為什麼在這個範例可以看到的動畫效果)
leftBackWheelBone.Transform = wheelRotation * leftBackWheelTransform;
rightBackWheelBone.Transform = wheelRotation * rightBackWheelTransform;
leftFrontWheelBone.Transform = wheelRotation * leftFrontWheelTransform;
rightFrontWheelBone.Transform = wheelRotation * rightFrontWheelTransform;
leftSteerBone.Transform = steerRotation * leftSteerTransform;
rightSteerBone.Transform = steerRotation * rightSteerTransform;
turretBone.Transform = turretRotation * turretTransform;
cannonBone.Transform = cannonRotation * cannonTransform;
hatchBone.Transform = hatchRotation * hatchTransform;
面上有提到一行
tankModel.Root.Transform = world;
這一行針對模型的全部轉換矩陣去做處理,讓他的值為世界矩陣的數值。由這方面來看的話,上面那一段程式碼,應該不難理解,只是去將旋轉的矩陣去乘上各自要轉動的物件的Transform Matrix,之後再把值做設定。
tankModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
用這個方式,將剛剛所有的轉換矩陣全部組合在一起
foreach (ModelMesh mesh in tankModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = boneTransforms[mesh.ParentBone.Index];
effect.View = view;
effect.Projection = projection;
effect.EnableDefaultLighting();
}
mesh.Draw();
}
上面程式碼大家應該很眼熟才對,就是套用基本特效,而這個特效就是XNA Framework所提供的,可以用基礎的燈光等,全部設定完以後再將模型劃出(這邊說是模型…不過實際畫出來的是Mesh,並不是模型的骨架,所以當他找不到自己設定的Mesh時候,他就會自動幫你套用你模型在繪製的顏色。
以上是基礎的方式,讓模型去做轉動,這個做法可以用在有規律性的模型上面,賽車馬車等車類模型就很適合,基本上,所有的模型都可以用這個做法,只是這樣做的話,你就必須要注意到,哪個物件的轉換矩陣要做多少角度的旋轉等計算,會變得非常麻煩…
接下來將要介紹的就是SkinnedAnimationSample的專案,這個專案就是使用你在3D繪圖軟體所設定好的動畫。
上面的文章,是以為自己的觀點去看,可能會有錯誤的描述或是解說,如果有任何錯誤歡迎指出,同時如果你覺得此文章有幫助,給些鼓勵吧 囧 你們的回覆是我解說的動力orz(好像論壇常看到)
以上程式碼可以在XNA的Creator Club中的Sample下載的到範例,這只是中文的解說,如果有涉及到任何版權的問題,歡迎指出