首先先看一張圖片

這張圖片是本範例的模型架構圖,這張圖片可以看出整個模型的架構,為什麼要貼上這張圖片呢?這就是接下來的關鍵了,要讓模型隨著旋轉角度的不同做旋轉,當然要了解,現在是哪個元件需要做轉動,所以我們就必須知道模型的整個設定資料。

首先我們宣告一些變數

Model tankModel;

上面的宣告式使用XNA FrameworkModel類別,將等等載入的模型資訊儲存起來

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就是設定數值,這個方式類是getset函數的方式,只是他應該不算式函數。

 

接下來看看Load函數,他所傳入的參數就是ContentManager類別,這個類別等等可以載入我們要的模型。

         tankModel = content.Load<Model>("Content/tank");

ContentManagerLoad函數將模型載入進來,存在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"];

上面的宣告使用ModelBonesBone讀入,當作等一下要做動畫的骨架,使用的方法就是上面的方式,然後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函數裡面傳入三個參數,分別就是WorldViewProjection 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下載的到範例,這只是中文的解說,如果有涉及到任何版權的問題,歡迎指出

創作者介紹
創作者 teexit1224 的頭像
teexit1224

StreamWhite

teexit1224 發表在 痞客邦 留言(2) 人氣()