zoukankan      html  css  js  c++  java
  • 梦想成真 XNA (8) 3D 基础

    [索引页]
    [源码下载] 


    梦想成真 XNA (8) - 3D 基础



    作者:webabcd


    介绍
    XNA: 3D 基础

    • 在 3D 坐标中绘制一个三角形
    • 让一个图片纹理在 3D 世界中动起来



    示例
    1、在一个 3D 坐标中绘制一个三角形(按键盘 P 键加载此 Demo)
    3D/Basic/Demo.cs

    /*
     * XNA 的 3D 坐标采用右手坐标系
     * 区分左手坐标系还是右手坐标系的方法:伸出手,掌心向上,四指指向 X 轴正方向的同时向 Y 轴正方向卷起,大拇指所指向的方向就是 Z 轴正方向
     * 
     * 本例演示:在一个 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.Basic
    {
        public class Demo : Microsoft.Xna.Framework.DrawableGameComponent
        {
            // View 矩阵,用于设置摄像机的位置和方向
            private Matrix _view;
            // Projection 矩阵,即摄像机的视野,其由摄影角度、屏幕宽高比、近截面和远截面组成,用于将 3D 物体投影到 2D 屏幕上
            private Matrix _projection;
    
            // 顶点信息数组,VertexPositionColor 对象包含了顶点的位置信息和颜色信息
            private VertexPositionColor[] _vertices;
            // 顶点缓冲器,可以将顶点信息以流的方式输出到图形设备中
            private VertexBuffer _vertexBuffer;
    
            // 基础效果,可以通过简单的属性设置来实现包含光照、纹理、变换等效果的物体的呈现
            private BasicEffect _effect;
    
            public Demo(Game game)
                : base(game)
            {
    
            }
    
            public override void Initialize()
            {
                // 创建摄像机
                CreateCamera();
    
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                // 创建顶点信息
                CreateVertices();
    
                // 创建顶点缓冲器
                CreateVertexBuffer();
    
                _effect = new BasicEffect(GraphicsDevice);
            }
    
            public override void Update(GameTime gameTime)
            {
                base.Update(gameTime);
            }
    
            public override void Draw(GameTime gameTime)
            {
                GraphicsDevice.Clear(Color.CornflowerBlue);
    
                DrawIt();
    
                base.Update(gameTime);
            }
    
            // 创建摄像机
            // 摄像机由两部分组成,视图矩阵和投影矩阵
            private void CreateCamera()
            {
                /*
                 * Matrix CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) - 实例化视图矩阵
                 *     Vector3 cameraPosition - 摄像机的位置坐标
                 *     Vector3 cameraTarget - 摄像机镜头的朝向向量
                 *     Vector3 cameraUpVector - 摄像机机身的顶部的上方的向量
                 */
                _view = Matrix.CreateLookAt(
                    new Vector3(0, 0, 5),
                    Vector3.Zero,
                    Vector3.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,
                    100
                );
            }
    
            // 创建顶点信息
            private void CreateVertices()
            {
                // 保存三角形的三个顶点的位置和颜色信息
                _vertices = new VertexPositionColor[3];
                _vertices[0] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Blue);
                _vertices[1] = new VertexPositionColor(new Vector3(1, -1, 0), Color.Red);
                _vertices[2] = new VertexPositionColor(new Vector3(-1, -1, 0), Color.Green);
            }
    
            // 创建顶点缓冲器
            private void CreateVertexBuffer()
            {
                // 实例化顶点缓冲器
                _vertexBuffer = new VertexBuffer(
                    GraphicsDevice,                 // 图形设备对象
                    typeof(VertexPositionColor),    // 顶点信息的数据类型
                    _vertices.Length,               // 顶点的总数
                    BufferUsage.None                // 缓冲器的使用方式:BufferUsage.None - 可读可写;BufferUsage.WriteOnly - 只可写
                );
    
                // VertexBuffer.SetData() - 为顶点缓冲器设置顶点信息数据
                _vertexBuffer.SetData(_vertices);
            }
    
            private void DrawIt()
            {
                // 绑定顶点缓冲器到图形设备中
                GraphicsDevice.SetVertexBuffer(_vertexBuffer);
    
                /*
                 * BasicEffect - 基础效果,可以通过简单的属性设置来实现包含光照、纹理、变换等效果的物体的呈现
                 *     BasicEffect.View - 视图矩阵(View 矩阵)
                 *     BasicEffect.Projection - 投影矩阵(Projection 矩阵)
                 *     BasicEffect.VertexColorEnabled - 是否允许在此效果中启用顶点信息中的颜色数据
                 */
                _effect.View = _view;
                _effect.Projection = _projection;
                _effect.VertexColorEnabled = true;
    
                /*
                 * EffectPass - 用于绘制一个效果,一个 BasicEffect 中可以包含多个 
                 *     EffectPass.Apply() - 绘制此效果
                 */
                foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
                {
                    pass.Apply();
    
                    // GraphicsDevice.DrawUserPrimitives() - 绘制基元
                    GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                        PrimitiveType.TriangleStrip,    // 基元类型
                        _vertices,                      // 顶点信息集合
                        0,                              // 在顶点缓冲器中的偏移量
                        1                               // 基元的个数,因为本例是三个顶点组成一个三角形,而一个三角形就是一个基元,所以此处为 1
                    );
                }
            }
        }
    }
    



    2、在一个 3D 坐标中绘制一个图片纹理,并且不断地移动它、旋转它、缩放它(按键盘 Q 键加载此 Demo)
    3D/Basic/Animation.cs

    /*
     * 本例演示:在一个 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.Basic
    {
        public class Animation : Microsoft.Xna.Framework.DrawableGameComponent
        {
            private Matrix _view;
            private Matrix _projection;
    
            // 顶点信息数组,VertexPositionTexture 对象包含了顶点的位置信息和顶点对应到纹理的位置信息
            private VertexPositionTexture[] _vertices;
            private VertexBuffer _vertexBuffer;
    
            private BasicEffect _effect;
    
            // 位移矩阵(Matrix.Identity 代表单位矩阵,任何矩阵与单位矩阵相乘后还是其自身)
            Matrix _translation = Matrix.Identity;
            // 旋转矩阵
            Matrix _rotation = Matrix.Identity;
            // 缩放矩阵
            Matrix _scale = Matrix.Identity;
    
            // 纹理对象
            Texture2D _texture;
    
            public Animation(Game game)
                : base(game)
            {
    
            }
    
            public override void Initialize()
            {
                CreateCamera();
    
                base.Initialize();
            }
    
            protected override void LoadContent()
            {
                CreateVertices();
                CreateVertexBuffer();
                _effect = new BasicEffect(GraphicsDevice);
    
                _texture = Game.Content.Load<Texture2D>("Image/Son");
    
                // 默认情况下,每个基元(primitive)的背面(back face)是不可见的,因为 3D 物体都是由若干个基元(三角形)组成,而实际 render 的时候是不需要 render 物体内部的
                // 如果需要显示基元的背面,可以使用以下设置
                RasterizerState rs = new RasterizerState();
                rs.CullMode = CullMode.None;
                GraphicsDevice.RasterizerState = rs;
            }
    
            float _xPosition = -0.01f;
            float _scaleValue = 0.99f;
            public override void Update(GameTime gameTime)
            {
                if (_translation.Translation.X > 2)
                    _xPosition = -0.01f;
                else if (_translation.Translation.X < -2)
                    _xPosition = 0.01f;
                // 计算当前的位移矩阵
                _translation *= Matrix.CreateTranslation(_xPosition, 0, 0);
    
                if (_scale.Up.Length() < 0.5)
                    _scaleValue = 1.01f;
                else if (_scale.Up.Length() > 2)
                    _scaleValue = 0.99f;
                // 计算当前的缩放矩阵
                _scale *= Matrix.CreateScale(_scaleValue);
    
                // 计算当前的旋转矩阵
                _rotation *= Matrix.CreateFromYawPitchRoll(MathHelper.PiOver4 / 60, 0, 0);
    
                base.Update(gameTime);
            }
    
            public override void Draw(GameTime gameTime)
            {
                GraphicsDevice.Clear(Color.CornflowerBlue);
    
                DrawIt();
    
                base.Update(gameTime);
            }
    
            private void CreateCamera()
            {
                _view = Matrix.CreateLookAt(
                    new Vector3(0, 0, 5),
                    Vector3.Zero,
                    Vector3.Up
                );
    
                _projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.PiOver4,
                    (float)Game.Window.ClientBounds.Width / (float)Game.Window.ClientBounds.Height,
                    1,
                    100
                );
            }
    
            private void CreateVertices()
            {
                // 顶点信息描述的是一个 2 * 2 的矩形框
                _vertices = new VertexPositionTexture[4];
    
                // 第二个参数 new Vector2(0, 0) 描述的是:顶点对应纹理的左上角
                // (1, 0)对应纹理的右上角,(0, 1)对应纹理的左下角,(1, 1)对应纹理的右下角
                // 注:不要把顶点的坐标系与第二个参数的坐标系相混淆,顶点坐标系是 3D 右手坐标系,而第二个参数的坐标系是以左上角为原点的 2D 坐标系
                _vertices[0] = new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0, 0)); 
                _vertices[1] = new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0)); 
                _vertices[2] = new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1));
                _vertices[3] = new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1));
    
                /*
                 * VertexPositionTexture 类的构造函数的第一个参数是顶点坐标,第二个参数是纹理坐标
                 * 纹理坐标是一个 UV 坐标,本例中 UV 坐标描述了如何将纹理映射到矩形上,即所谓的贴图
                 * 可以把 U 和 V 当作贴图时,被贴的纹理所需显示的百分比,值的范围是 0 - 1(可以修改一下本例中 4 个纹理坐标后看效果,以方便理解)
                 */
            }
    
            private void CreateVertexBuffer()
            {
                _vertexBuffer = new VertexBuffer(
                    GraphicsDevice,
                    typeof(VertexPositionTexture),
                    _vertices.Length,
                    BufferUsage.None
                );
                _vertexBuffer.SetData(_vertices);
            }
    
            private void DrawIt()
            {
                GraphicsDevice.SetVertexBuffer(_vertexBuffer);
    
                /*
                 * BasicEffect.World - World 矩阵,图像的旋转、缩放和平移的实质就是矩阵相乘,World 矩阵就是把矩阵相乘后的 3D 坐标系转化为世界坐标系
                 * BasicEffect.Texture - 指定需要绘制的纹理
                 * BasicEffect.TextureEnabled - 指定是否可以绘制纹理
                 */
                _effect.World = _rotation * _translation * _scale;
                _effect.Texture = _texture;
                _effect.TextureEnabled = true;
                _effect.View = _view;
                _effect.Projection = _projection;
                
                foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
                {
                    pass.Apply();
    
                    GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(
                        /*
                         * PrimitiveType - 基元类型
                         *     PrimitiveType.TriangleList - 每三个独立的顶点构成一个独立的三角形(见本目录下的图片 TriangleList.png)
                         *     PrimitiveType.TriangleStrip - 一个新的独立的顶点与已存在的三角形的两个顶点构成一个三角形(见本目录下的图片 TriangleStrip.png)
                         *     PrimitiveType.LineList - 每两个独立的顶点构成一条独立的直线(见本目录下的图片 LineList.png)
                         *     PrimitiveType.LineStrip - 一个新的独立的顶点与已存在的直线的一个顶点构成一条直线(见本目录下的图片 LineStrip.png)
                         */
                        PrimitiveType.TriangleStrip, 
                        _vertices, 
                        0,
                        2 // 本例中通过 4 个顶点构成矩形,本质是由两个三角形基元构成,其基元类型为 PrimitiveType.TriangleStrip
                    );
                }
            }
        }
    }
    



    OK 
    [源码下载]

  • 相关阅读:
    物联网相关期刊会议
    Java O O第十一天
    mac下安装伪分布hadoop2.6.0和hbase1.0.1.1
    Ubuntu下使用openssl为apache2配置ssl
    ubuntu下安装hadoop
    ubuntu 添加应用到Dash启动器
    Ubuntu12.04中安装Oracle JDK和NetBeans的方法
    Ubuntu12.04中在桌面建立指向网页的链接文件的方法
    Ubuntu12.04中Gvim无法固定到启动器的解决办法
    Ubuntu中apt-get安装或更新软件错误的解决办法
  • 原文地址:https://www.cnblogs.com/webabcd/p/2143979.html
Copyright © 2011-2022 走看看