zoukankan      html  css  js  c++  java
  • XNA 3D模型入门讲解(一)

    我又开始了,接下来开始我的 XNA 3D 模型入门讲解:

    创建XNA Game项目(此步骤自行操作),然后添加一个 Game Component,命名为Camera,修改默认代码如下:

    public class Camera : Microsoft.Xna.Framework.GameComponent
    {
    //Camera matrices
    public Matrix view { get; protected set; }
    public Matrix projection { get; protected set; }
    public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
    : base(game)
    {
      view = Matrix.CreateLookAt(pos, target, up);
      projection = Matrix.CreatePerspectiveFieldOfView(
      MathHelper.PiOver4,
      (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);
    }
    }
    }

    在Game类添加代码:

    public Camera camera { get; protected set; }

    在Initialize中添加代码(实例化摄像机对象,同时将组件添加到组件集合):

    camera = new Camera(this, new Vector3(0, 0, 50),Vector3.Zero, Vector3.Up);
    Components.Add(camera);

    添加模型到项目:
    在Content项目中添加一个Models文件夹,然后添加一个3D模型,如果你没有模型,可以下载源码,然后找到后缀名为.x的文件.

    添加绘制3D模型的类:

    class BasicModel
        {
            public Model model { get; protected set; }
            protected Matrix world = Matrix.Identity;
    
            public BasicModel(Model m)
            {
                model = m;
            }
    
            public virtual void Update()
            {
            }
    
            public void Draw(Camera camera)
            {
                Matrix[] transforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(transforms);
                //遍历模型中的每个ModelMesh
                foreach (ModelMesh mesh in model.Meshes)
                {
                    //遍历ModelMesh有对应该关系的BasicEffect对象
                    foreach (BasicEffect be in mesh.Effects)
                    {
                        be.EnableDefaultLighting();
                        be.Projection = camera.projection;
                        be.View = camera.view;
                        be.World = GetWorld() * mesh.ParentBone.Transform;
                    }
                    mesh.Draw();
                }
            }
    
            public virtual Matrix GetWorld()
            {
                return world;
            }
        }

    代码讲解:
    第一个变量是Model类型的。Model类用来代表内存中的3D模型,这就好比你之前用Texture2D类来代表内存中的2D图像。
    第二个变量是Matrix,代表该特定模型的世界(world)。该矩阵代表在哪绘制,如何旋转和缩放模型等。
    给BasicModel类添加一个构造方法。该构造方法只需要一个Model类型的参数,并把该参数赋给模型成员。
    创建一个空的虚方法Update,它能够被BasicModel派生类重载,用于定制更新过程中应该执行的动作。

    然后需要绘制3D模型,有点麻烦哦,看我慢慢道来:

        这些场景,以.X为后缀名,每一个都包含不止一个物体。这些物体,也称之为网格(meshes),存放在模型中。在XNA中,Model类用ModelMesh对象来表示这些网格。Model类的Meshes属性包含有一系列ModelMesh对象。
        网格包含有用于绘制该网格所需的材质、颜色和纹理等信息。网格的各个部分没有必要使用同样的颜色和纹理,你可以让一个网格包含多种材质。为了存放这些数据,网格由好几部分构成。ModelMesh类在一个名为MeshParts的
      属性里面存放了一系列的ModelMeshParts。每个MeshParts均包含绘制MeshPart所需的材质和绘制MeshPart所需的Effect对象。     默认情况下,Model的MeshPart所用到的Effect是BasicEffect类型的。BasicEffect派生自Effect,它给你提供一种不需要独自创建HLSL效果文件就能在3D绘制物体的一种方法。     最后,每一个ModelMesh都有一个变换(transformation),能移动网格到模型内合适的位置。     为了搞清这一切是怎么工作的,想象一辆带方向盘的汽车模型。用一个Model来代表整个场景(汽车和方向盘一起)。Model的Meshes属性可能有两个不同的ModelMesh对象,一个是汽车的、一个是方向盘的。每一个Meshes都有
     一个变换能把物体放在正确的位置,汽车有可能摆放在某个地方(比如说原点),方向盘相应地摆在某个合适的位置。除此之外,每个Meshes含有一种改变网格样子的材质(比如说汽车可能用到那些使它看起来呈现闪红的材质,方向盘可
    能用到那些暗黑色的材质),也含有绘制ModelMesh所需的Effect。

    绘制的代码见Draw方法中:

      前两行代码处理一些叫做骨骼(bones)的东西。骨骼用来把物体放置在模型空间内合适的位置。通常情况下,你的代码不会受到这些变换的影响,除非你的模型含有多个网格(飞船模型没有)。只是为了防止给定的模型有多个部分,你需要添加
    前两行代码。   接着,代码遍历模型中的每个ModelMesh以及每个与ModelMesh有对应该关系的BasicEffect对象,应用默认的光照,设置被绘制的对象的Projection、View和World属性。摄像机使用投影和视图矩阵,世界矩阵设置对象的World属性。世界
    矩阵乘以这里的变换(the transform),来确保ModelMesh放置在模型内合适的位置。

     添加模型管理器:

     public class ModelManager : DrawableGameComponent
        {
            //存放一系列BasicModel
            List<BasicModel> models = new List<BasicModel>();
    
            public ModelManager(Game game)
                : base(game)
            {
                // TODO: Construct any child components here
            }
    
            public override void Initialize()
            {
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                models.Add(new SpinningEnemy(Game.Content.Load<Model>(@"models\spaceship")));
                base.LoadContent();
            }
    
            public override void Update(GameTime gameTime)
            {
                foreach (BasicModel model in models)
                {
                    model.Update();
                }
                base.Update(gameTime);
            }
    
            public override void Draw(GameTime gameTime)
            {
                foreach (BasicModel bm in models)
                {
                    bm.Draw(((Game1)Game).camera);
                }
                base.Draw(gameTime);
            }
        }

    这里主要有两个重要部分:
    一个是在LoadContent中加载刚才添加的模型,一个是在Update中遍历更新模型.

    让模型转起来:
    现在的模型似乎没有什么效果,和之前的二维图片没什么区别,接下来实现模型的转动.
    添加一个新的类SpinningEnemy:

    class SpinningEnemy : BasicModel
        {
            Matrix rotation = Matrix.Identity;
            public SpinningEnemy(Model m)
                : base(m)
            {
            }
    
            public override void Update()
            {
                rotation *= Matrix.CreateRotationY(MathHelper.Pi / 180);
            }
    
            public override Matrix GetWorld()
            {
                return world * rotation;
            }
        }

    该类实现了BasicModel,这样就免去了重写Draw方法,该类的有了一个rotation旋转的变量;同时在Update中你将看到rotation变量在每一帧中以围绕Y轴多旋转1度的速度更新
    (请记住角度是用弧度来表示的,π就是180°,所以π/ 180等于1度);类中还重写GetWorld方法,返回世界坐标和旋转的角度的乘积,也就是旋转后的位置.
    最后在ModelManager中的LoadContent中修改创建BasicModel的代码为如下:

    models.Add(new SpinningEnemy(Game.Content.Load<Model>(@"models\spaceship")));


    这一部分主要讲解了在XNA中加载一个3D模型,同时实现了模型的旋转效果,在下一章节中将会讲解"3D中摄像机"的功能.

  • 相关阅读:
    linux上的工具或软件
    百度分享插件怎么取消鼠标放在图片上出现的分享条
    常用的Lambda表达式
    IDEA安装使用Lombok插件
    Spring cloud Eureka错误锦集(二)
    Spring cloud Eureka错误锦集(一)
    Navicat破解
    手动添加jar包到本地仓库
    Markdown常用语法
    Java中的位运算符
  • 原文地址:https://www.cnblogs.com/ListenFly/p/2805425.html
Copyright © 2011-2022 走看看