梦想成真 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
[源码下载]