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

posted @ 2011-08-23 08:51  webabcd  阅读(4131)  评论(6编辑  收藏  举报