梦想成真 XNA (9) - 3D 模型
梦想成真 XNA (9) - 3D 模型
作者:webabcd
介绍
XNA: 3D 模型。通过键盘的“上下左右”键旋转 3D 模型
示例
绘制一个 3D 模型,并通过“上下左右”键控制它的旋转(按键盘 R 键加载此 Demo)
3D/3DModel/RotationDirection.cs
namespace XNA.Component._3D._3DModel { /// <summary> /// 旋转方向 /// </summary> public enum RotationDirection { Up, Down, Left, Right } }
3D/3DModel/MyCamera.cs
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace XNA.Component._3D._3DModel { /// <summary> /// 自定义摄像机类 /// </summary> public class MyCamera : Microsoft.Xna.Framework.GameComponent { // View 矩阵,用于设置摄像机的位置和方向 public Matrix View { get; protected set; } // Projection 矩阵,用于将 3D 物体投影到 2D 屏幕上 public Matrix Projection { get; protected set; } public MyCamera(Game game, Vector3 pos, Vector3 target, Vector3 up) : base(game) { /* * Matrix CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) - 实例化视图矩阵 * Vector3 cameraPosition - 摄像机的位置坐标 * Vector3 cameraTarget - 摄像机镜头的朝向向量 * Vector3 cameraUpVector - 摄像机机身的顶部的上方的向量 */ View = Matrix.CreateLookAt(pos, target, up); /* * CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) - 实例化投影矩阵 * float fieldOfView - Y 轴方向上的视角弧度,一般是四分之一个 PI * float aspectRatio - 可视区的长宽比,一般就是游戏窗口的宽除以游戏窗口的高 * float nearPlaneDistance - 当物体离摄像机多近时无法看清 * float farPlaneDistance - 当物体离摄像机多远时无法看清 */ Projection = Matrix.CreatePerspectiveFieldOfView( MathHelper.PiOver4, // 四分之一个 PI(MathHelper 里有很多实用的功能) (float)Game.Window.ClientBounds.Width / (float)Game.Window.ClientBounds.Height, 1, 3000 ); } public override void Initialize() { base.Initialize(); } public override void Update(GameTime gameTime) { base.Update(gameTime); } } }
3D/3DModel/MyModel.cs
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace XNA.Component._3D._3DModel { /// <summary> /// 自定义 3D 模型类 /// </summary> public class MyModel { // Model - 代表 3D 模型。代表 2D 对象的是 Texture2D private Model _model; // 旋转矩阵 private Matrix _rotation = Matrix.Identity; // 初始矩阵 private Matrix _world = Matrix.Identity; public MyModel(Model model, Matrix world) { _model = model; _world = world; } /// <summary> /// 绘制 3D 模型 /// </summary> public void Draw(MyCamera camera) { /* * 一个 Model 对象里有多个 ModelMesh 对象,每个 ModelMesh 对象包含了此网格的纹理、颜色等信息 */ foreach (ModelMesh mesh in _model.Meshes) { /* * 一个 ModelMesh 对象里有多个用于绘制 ModelMesh 的 Effect */ foreach (BasicEffect effect in mesh.Effects) { // 使用默认光源效果 effect.EnableDefaultLighting(); effect.Projection = camera.Projection; effect.View = camera.View; effect.World = GetWorld(); } // 绘制 ModelMesh mesh.Draw(); } } /// <summary> /// 根据方向(上下左右)计算旋转矩阵 /// </summary> public void Rotate(RotationDirection direction) { switch (direction) { case RotationDirection.Up: _rotation *= Matrix.CreateRotationX(-MathHelper.Pi / 180); // 绕 X 轴旋转的弧度 break; case RotationDirection.Down: _rotation *= Matrix.CreateRotationX(MathHelper.Pi / 180); break; case RotationDirection.Left: _rotation *= Matrix.CreateRotationY(-MathHelper.Pi / 180); // 绕 Y 轴旋转的弧度 break; case RotationDirection.Right: _rotation *= Matrix.CreateRotationY(MathHelper.Pi / 180); break; } } /// <summary> /// 获取世界矩阵,即初始矩阵乘以旋转矩阵 /// </summary> public Matrix GetWorld() { return _world * _rotation; } } }
3D/3DModel/Demo.cs
/* * XNA 只支持 .x 和 .fbx 格式的 3D 模型文件 * 本例所用 3D 模型的位置在:XNAContent/3DModel/Spaceship.x * * 本例演示:通过键盘的“上下左右”键旋转 3D 模型 */ using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace XNA.Component._3D._3DModel { public class Demo : Microsoft.Xna.Framework.DrawableGameComponent { private MyCamera _camera; private List<MyModel> _models = new List<MyModel>(); public Demo(Game game) : base(game) { } public override void Initialize() { // 添加摄像机组件 _camera = new MyCamera(Game, new Vector3(0, 0, 50), Vector3.Zero, Vector3.Up); Game.Components.Add(_camera); base.Initialize(); } protected override void LoadContent() { // 添加两个不同位置的 3D 模型 _models.Add(new MyModel(Game.Content.Load<Model>(@"3DModel\Spaceship"), Matrix.Identity * Matrix.CreateTranslation(-10, -5, -20))); _models.Add(new MyModel(Game.Content.Load<Model>(@"3DModel\Spaceship"), Matrix.Identity * Matrix.CreateTranslation(10, 5, 0))); base.LoadContent(); } public override void Update(GameTime gameTime) { // 根据用户的按键(上下左右),旋转 3D 模型 KeyboardState keyboardState = Keyboard.GetState(); foreach (MyModel model in _models) { if (keyboardState.IsKeyDown(Keys.Up)) model.Rotate(RotationDirection.Up); else if (keyboardState.IsKeyDown(Keys.Down)) model.Rotate(RotationDirection.Down); else if (keyboardState.IsKeyDown(Keys.Left)) model.Rotate(RotationDirection.Left); else if (keyboardState.IsKeyDown(Keys.Right)) model.Rotate(RotationDirection.Right); } base.Update(gameTime); } public override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // 绘制 3D 模型 foreach (MyModel model in _models) { model.Draw(_camera); } base.Update(gameTime); } } }
OK
[源码下载]