您的位置:首页 > 其它

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

2011-08-18 09:00 267 查看
[索引页]
[源码下载]

[align=center]梦想成真 XNA (8) - 3D 基础[/align]

作者: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
[源码下载]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: