開發3D遊戲是個很HIGH的事情。
本文介紹如何在XNA架構下使用BasicEffect和DualTexturesEffect顯示模型。
參考文章(E文好的可以不同在這裡看我啰嗦 ╮(╯▽╰)╭):
http://www.codeproject.com/KB/windows-phone-7/3DGraphicsWP7.aspx
本文包括了簡單的模型制作步驟(因為這是我的薄弱環節,個人再摸索這兩個效果時候耗時最多,是以對模組化說明的也比較詳細),對代碼的分析沒有太深入(因為XNA架構個人認為代碼結構比較容易了解,按照流程走下來,多想想 因該很容易上手~)
Tips:
1、XNA中預設使用“厘米”為機關。再模組化時最好把模型機關設定為厘米。
以3DsMAX為例,設定機關再“自定義”菜單的“機關設定”選項。
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
将“顯示機關比例”設定為 “公制-厘米”
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
2、輸出模型的貼圖注意一定不要使用sRGB顔色空間,并且保證模型的貼圖寬度都是2的次幂形式 (比如512*512,128*128這樣)。
當時我在MAX裡導出png格式的UV模闆然後再畫圖工具裡直接修改導出的這個UV模闆的顔色。結果在XNA裡顯示出來的顔色就像褪了色一樣,研究好長時間 後來發現居然是顔色空間的問題。(MAX2012的UV貼圖貌似使用的是sRGB空間,用photoshop可以看到)![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 當然。。如果是這樣,别怕。。改成adobe RGB就可以了,或者上色的時候幹脆建立一個圖檔,或者不要使用png格式。。![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
3、XNA程式預設橫屏。
4、為了效率和節能WindowsphoneSDK中XNA并不支援shader。做光影效果使用DualTexturesEffect
BasicEffect
BasicEffect,很明顯就是基本效果的意思。。也就是最簡單的模型顯示方式。
先在3DsMAX中建立一個模型。并加個貼圖。
Like this:
這裡建立了一個機關為5cm的茶壺模型。。
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
UV展開的貼圖和上色後的貼圖如下(上色的時候建立一個圖檔然後将貼圖作為圖層後上色注意顔色空間别是sRGB就OK)
貼圖不一定要再模組化的時候就添加到模型上。
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
(貼圖簡單上色,有點二。。但是,别怕)
将模型導出為FBX檔案
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
差不多就這些。。。夠了。準備工作完成,然後打開VS。
建立一個項目。選擇Visual C# / XNA Game Studio 4.0 / WindowsPhoneGame(4.0) 起名就叫BasicEffectTest
VS會自動建立好一個XNA項目的模闆。![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) Game1.cs就是主函數,别的可以暫時不用管。。
XNA架構簡單說就是個死循環啊死循環。(此圖應該多處可見,不做贅述)
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 開始正題。首先進行簡單的設定
XNA中模型對象類型為Model,貼圖對象類型為Texture2D。
首先要做的就是聲明這兩個變量(類屬性?),分别用來儲存模型和貼圖。
1: Texture2D texture;
2: Model model;
然後将模型和貼圖添加到Content中![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 添加的結果是這樣的![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 然後可以将資源加入到代碼中。在主類(Game1.cs)中載入貼圖,添加載入資源代碼的LodContent方法如下。![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 1: protected override void LoadContent()
2: {
3: // Create a new SpriteBatch, which can be used to draw textures.
4: spriteBatch = new SpriteBatch(GraphicsDevice);
6: texture = Content.Load<Texture2D>(@"teapotTexture"); //載入貼圖
7: model = Content.Load<Model>(@"teapot");//載入模型
9: // TODO: use this.Content to load your game content here
10: }
好了 然後就是最激動人心的時刻了。。
顯示模型,首先要定義3個矩陣。(關于3D世界中矩陣的知識,請自行抱佛腳)
1、世界矩陣:讓模型知道他應該顯示在那裡,也就是他在虛拟世界中的位置,最基本的一個矩陣,用來描述模型在整個場景的基準位置。
Matrix world = Matrix.Identity; //定義一個機關矩陣,就是模型的基準是世界的原點
2、視圖矩陣:可以了解為一個錄影機,用來描述你在世界裡用怎樣的視角來觀察這個該死的模型。
Matrix view = Matrix.CreateLookAt(new Vector3(0,0,50), Vector3.Zero, Vector3.Up); //從(0,0,50)這個坐标向(0,0,0)這個角度看去,預設向上和世界坐标的上是一個方向
3、投影矩陣:可以了解為一個大幕布,整個世界模型擺好了,錄影機也擺好了,這個投影矩陣用來把場景中的模型投影在幕布上,這樣從錄影機看去的影像就是最後拍成電影呈獻給觀衆的畫面。
Matrix projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45), //視角
GraphicsDevice.Viewport.AspectRatio, //螢幕長寬比
0.1f, //最近拍攝範圍
100f //最遠拍攝範圍
);
好了 矩陣設定好了。然後就是最簡單的 讓模型顯示就好了。。最基本的顯示模型的代碼很簡單。。。。 - -
model.Draw(world, view, projection);
OK,That's all ,吧這些統統添加到主類(Game1.cs)的Draw方法中,添加後的Draw方法如下。
1: protected override void Draw(GameTime gameTime)
2: {
3: GraphicsDevice.Clear(Color.CornflowerBlue);
5: // TODO: Add your drawing code here
6: Matrix world = Matrix.Identity; //定義一個機關矩陣,就是模型的基準是世界的原點
7: Matrix view = Matrix.CreateLookAt(new Vector3(0,0,50), Vector3.Zero, Vector3.Up); //從(0,0,50)這個坐标向(0,0,0)這個角度看去,預設向上和世界坐标的上是一個方向
8: Matrix projection = Matrix.CreatePerspectiveFieldOfView(
9: MathHelper.ToRadians(45), //視角
10: GraphicsDevice.Viewport.AspectRatio, //螢幕長寬比
11: 0.1f, //最近拍攝範圍
12: 100f //最遠拍攝範圍
13: );
14: model.Draw(world, view, projection); //模型顯示代碼
16: base.Draw(gameTime);
然後,run下,看看效果。。。(因為我模組化的時候沒有直接給模型加上貼圖,是以看起來就是這樣。。)17: }
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
好,模型顯示出來了。現在要做的就是添加貼圖。顯然。要添加貼圖那種基本的顯示方法明顯不夠用了啊。是以這裡要使用比較笨得方法顯示(為了讓模型顯示更加可控,再實際項目中都會用這種方式)1: Matrix[] transforms = new Matrix[model.Bones.Count];
2: model.CopyAbsoluteBoneTransformsTo(transforms);
4: foreach (ModelMesh mesh in model.Meshes)
5: {
6: foreach (BasicEffect effect in mesh.Effects)
7: {
8: effect.View = view;
9: effect.Projection = projection;
10: effect.World = transforms[mesh.ParentBone.Index] * world;
11: }
12: mesh.Draw();
13: }
上面這一堆等同于之前的一句“model.Draw(world, view, projection); ”,仔細分析這個代碼其實就是将FBX中模型的每個面(Mesh)都分别進行BasicEffect進行渲染。
現在要添加貼圖了。
其實很簡單,設定下BasicEffect的屬性就OK
添加設定後的代碼如下:
1: protected override void Draw(GameTime gameTime)
2: {
3: GraphicsDevice.Clear(Color.CornflowerBlue);
5: // TODO: Add your drawing code here
6: Matrix world = Matrix.Identity; //定義一個機關矩陣,就是模型的基準是世界的原點
7: Matrix view = Matrix.CreateLookAt(new Vector3(0,0,50), Vector3.Zero, Vector3.Up); //從(0,0,50)這個坐标向(0,0,0)這個角度看去,預設向上和世界坐标的上是一個方向
8: Matrix projection = Matrix.CreatePerspectiveFieldOfView(
9: MathHelper.ToRadians(45), //視角
10: GraphicsDevice.Viewport.AspectRatio, //螢幕長寬比
11: 0.1f, //最近拍攝範圍
12: 100f //最遠拍攝範圍
13: );
14: Matrix[] transforms = new Matrix[model.Bones.Count];
15: model.CopyAbsoluteBoneTransformsTo(transforms);
17: foreach (ModelMesh mesh in model.Meshes)
18: {
19: foreach (BasicEffect effect in mesh.Effects)
20: {
21: effect.TextureEnabled = true; // 設定為使用貼圖屬性指向的資源作為目前模型的貼圖
22: effect.Texture = texture;//設定貼圖屬性為之前導入的資源
23: effect.View = view;
24: effect.Projection = projection;
25: effect.World = transforms[mesh.ParentBone.Index] * world;
26: }
27: mesh.Draw();
28: }
31: base.Draw(gameTime);
32: }
再次運作結果如下:(為了更好的觀察模型 将視圖矩陣的位置設定的為30,想象下把攝像頭往前放點給模型來個特寫╮(╯▽╰)╭)![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 坑爹啊,看起來和貼圖顔色不一樣有木有!
别怕 這個是因為BasicEffect還有一個燈光屬性沒有設定,想象下舞台上的超級亮的探照燈。木有燈當然暗了。
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 這樣是不是就看起來和貼圖一緻了~~。![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
好了 ,BasicEffect就介紹到這裡,看了文章開頭的E文資料的童鞋會發現,那個外國大牛介紹了更多BasicEffect的特性,比如BasicEffect可以添加3個燈光等等 ,本文不作贅述,感興趣的去啃E文吧。因為目前這樣在我目前的項目裡夠用了。。。是以我沒有深究。。
DualTexturesEffect
看完BasicEffect的使用,和示例是不是感覺總是少了點什麼。對了,陰影效果。DaulTexturesEffect就是XNA中解決這個問題的。
玩多大型遊戲的童鞋都應該有體會,實時陰影效果一開,遊戲對機器的要求馬上就加大了,但是又希望再XNA中做出光照投影的效果,WindowsPhone作為手機平台,是無法實時處理那麼多的光影效果的。
這個時候就可以使用DaulTexturesEffect作為一個折中的辦法。
DaulTexturesEffect原理就是一共兩個貼圖,一個管顔色一個管陰影效果(切換光影效果可以直接替換投影那個貼圖就OK了,着色貼圖就不用換了~~)
Color = Texture1.rgb * Texture2.rgb * 2 (Texture1 就是色彩貼圖 Texture2是光影貼圖, 光陰貼圖在沒有任何光陰效果的情況下預設是顔色為(128,128,128),原理自己想。。。。)
内啥 。。 因為茶壺模型再烘焙後出現的LightMap貼圖會有點詭異(不知道原因。。因為我3DMAX是菜鳥 )。估計是因為茶壺模型的面比較複雜吧,是以這裡不再使用茶壺模型進行示範了。重建立一個方塊的模型。類似于遊戲中的建築模型吧。
模型如下,很簡單 一個平面然後放上3個長方體(當是建築物吧。。為了貼圖友善 我再擺放完後把他們合成了一個模型)
将模型導出,就叫dualModel.FBX吧
然後展開UV貼圖 (注意儲存貼圖坐标)![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 然後建立一個貼圖通道,導入剛剛展開的貼圖坐标(就是通道1和通道2展開的貼圖坐标一緻(實際項目中可以按需調整,這裡使用一緻的貼圖坐标是為了友善。。))![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 然後就是制作貼圖了,這裡要制作兩個貼圖,一個是漫反射貼圖,也就是着色用的貼圖。
為了展現色彩,是以就直接搞成彩色的好了,當然 注意 千萬不要用sRGB顔色空間,用adobe RGB就好了
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 然後,是渲染陰影貼圖
3步走
1、制作一個顔色為(128,128,128)的底色材質并付給模型
2、給模型來點光照,并渲染下看看效果![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 3、渲染一個lightingMap貼圖出來![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 資源準備完成,大概包括如下這些![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 好了,這些準備好 然後再VS中建立一個項目,叫DualTexturesEffectTest吧
先将資源導入,程式中需要用到的就是一個模型兩個貼圖。
這裡要注意一點,要讓模型使用DualTexturesEffect需要修改模型的預設效果屬性![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) ![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect) 這一切搞定後,可以打開Game1.cs修改代碼了
還是3步走
1、添加類屬性用來保管資源
1: Model model;
2: Texture2D colorTexture;
3: Texture2D lightingTexture;
2、在LoadContent方法中将資源載入1: protected override void LoadContent()
2: {
3: // Create a new SpriteBatch, which can be used to draw textures.
4: spriteBatch = new SpriteBatch(GraphicsDevice);
6: // TODO: use this.Content to load your game content here
7: model = Content.Load<Model>(@"dualModel");
8: lightingTexture = Content.Load<Texture2D>(@"buildingLighting");
9: colorTexture = Content.Load<Texture2D>(@"buildingColor");
10: }
3、在draw方法中加入模型顯示代碼,使用DaulTexturesEffect展示模型(這裡顯示方法參考前面BasicEffect代碼稍作修改就可以)
需要說明的是DaulTexturesEffect效果有兩個texture屬性 一個是effect.Texture另一個是effect.Texture2 前者用來設定着色貼圖後者用來設定光照貼圖(有且隻有兩個。。這個一定要明确)。另外DaulTexturesEffect沒有設定燈光的屬性。
1: protected override void Draw(GameTime gameTime)
2: {
3: GraphicsDevice.Clear(Color.CornflowerBlue);
5: // TODO: Add your drawing code here
6: Matrix world = Matrix.Identity;
7: Matrix view = Matrix.CreateLookAt(new Vector3(0, 200, 300), Vector3.Zero, Vector3.Up); //為了更好地觀察模型 錄影機位置坐标進行了調整
8: Matrix projection = Matrix.CreatePerspectiveFieldOfView(
9: MathHelper.ToRadians(45),
10: GraphicsDevice.Viewport.AspectRatio,
11: 0.1f,
12: 1000f //為了能看到模型 投影範圍也擴大鳥
13: );
14: Matrix[] transforms = new Matrix[model.Bones.Count];
15: model.CopyAbsoluteBoneTransformsTo(transforms);
17: foreach (ModelMesh mesh in model.Meshes)
18: {
19: foreach (DualTextureEffect effect in mesh.Effects) //使用DualTextureEffect效果
20: {
21: effect.Texture = colorTexture;//設定Texture貼圖屬性為之前導入的着色貼圖資源
22: effect.Texture2 = lightingTexture;//設定Texture2貼圖屬性為之前導入的光照貼圖資源
24: effect.View = view;
25: effect.Projection = projection;
26: effect.World = transforms[mesh.ParentBone.Index] * world;
27: }
28: mesh.Draw();
29: }
31: base.Draw(gameTime);
好了 然後就是顯示效果。(額。。可能我色彩高的太豔了 光照又太強了。。效果不是很明顯 但是能看出來 這個是又陰影效果的 對吧 ╮(╯▽╰)╭)32: }
![]()
WP7-XNA 3D開發 顯示3D模型(BasicEffect、DualTexturesEffect)
搞定收工。。~~!╮(╯▽╰)╭!~~