在很早之前的文章,有針對XNA 1.0的版本做3D模型顯像的範例程式說明。
使用著還是可以參考之前的說明,然後對照看一下即可。
兩著不會差異太多。
要將模型顯像出來,首先需要宣告一個Model的物件
可以在類別中空白位置宣告一個變數
EX: Model mModel; (變數名字隨個人喜好,不過這邊建議各位可以使用匈牙利命名法則來做命名)
在LoadContent函數中,將檔案載入
mModel = this.Game.Content.Load<Model>("tank");
在Draw的函數中,使用basicEffect來將模型繪製(Camera的部分使用這可以依據自己的喜好設定,也可以直接使用右邊側欄位的Camera程式碼)
void fBasicEffectRendering()
{
Matrix[] transforms = new Matrix[mModel.Bones.Count];
mModel.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in mModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index] * Matrix.Identity;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
------------------------------------------------------------------------------
比較需要特別說明的就是
Matrix[] transforms = new Matrix[mModel.Bones.Count];
mModel.CopyAbsoluteBoneTransformsTo(transforms);
....
effect.World = transforms[mesh.ParentBone.Index] * Matrix.Identity;
如果沒有這三行程式碼,我們得到的結果會是
加入三行程式碼以後得到的結果為
這三行程式碼主要是做矩陣的轉換,因為這個tank的模型是由很多不同的零件(part)組成。
每個零件的在模型製作期間都是在原點的位置上,所以如果我們不乘上他們各自的轉換矩陣(transform matrix)就會出現第一張圖片的問題。
而轉換矩陣就像是基本的平移旋轉等等。
所以下次你看到模型顯像的結果有些問題,可以先看看這樣處理有沒有效果。
有時候我們會需要顯示一些2D文字訊息在上面。
會使用spriteBatch的DrawString方法來繪製字串。
如果你將3D模型畫出來再加上2D文字,你會發現你的模型變得很詭異...像這樣 (主要是深度測試出錯才會這樣,因為在畫2Dsprite的時候會關閉深度測試)
要解決的方式如下
1. 可以在spriteBatch.begin的地方設定:
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied,SamplerState.LinearWrap,DepthStencilState.Default,RasterizerState.CullCounterClockwise);
最主要的參數就是DepthStencilState,這部分在draw sprite的時候是被關閉的,我們需要把他打開設定成Default,這樣才會保有原來的3D深度測試。
2. 除了上述方法,還可以再spriteBatch.Begin();之前加入
GraphicsDevice.BlendState = BlendState.AlphaBlend;
GraphicsDevice.DepthStencilState = DepthStencilState.None;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
畫玩2D圖片以後,再加入
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
這樣也可以獲得正確的結果。
2D+ 3D兩個並存方式,在XNA 3.1以前是使用設定SaveState的方式,將當下的flag狀態全部儲存起來,在4.0則是將裡面的flag分解成很多小小的物件。
所以我們可以針對不同的物件去做設定,而非將整個狀態全部儲存起來。