显示三角形多边形
总结
它在 3D 空间中显示三角形多边形。
经营环境
先决条件
支持的 XNA 版本 |
|
支持的平台 |
|
Windows 所需的顶点着色器版本 | 2.0 |
Windows 所需的像素着色器版本 | 2.0 |
经营环境
平台 |
|
物质
什么是多边形?
多边形是由多个顶点定义生成的面。 通常,多边形是由三个顶点组成的三角形面。 三角体是多边形的最小单位。 某些建模软件可能会将多边形显示为四边形或多边形,但这些多边形最终会分解为三角形多边形。
游戏中显示的模型是由多个这些三角形多边形组合而成的。
多边形由顶点组成。 顶点可以包含位置和颜色等数据。 此示例也是由 “position” 和 “color” 数据组成的。
在此示例中,面的颜色由为每个顶点设置的颜色和距离整齐地插值,但您可以使用自己的着色器程序自由更改它(下次将详细介绍着色器程序)。
顶点数据定义
为了显示多边形,需要 “顶点数据”,程序员必须决定该顶点中要包含哪些元素。 在绘制多边形时,您必须告诉设备(哪个绘制引擎)要使用哪些顶点数据绘制多边形。 为此,请创建一个 “VertexDeclaration” 类并设置 “Vertex Data Definition”。
但是,从 XNA Game Studio 4.0 开始,此设置已得到简化,您无需为此提示准备 VertexDeclaration 类。 (这是因为定义信息已经嵌入到框架提供的顶点数据中。
顶点数据
我写过绘制多边形需要顶点数据,但首先我们必须决定我们想要什么样的数据。 在这种情况下,我们将使用 “position” 和 “color” 数据。 确定要拥有的数据后,您需要创建一个结构来保存该数据。 您可以自由地决定什么是顶点数据,但常用的顶点数据已在 XNA 框架中定义,因此该示例使用它。
具有 “position” 和 “color” 的顶点数据被定义为 “VertexPositionColor” 结构。 由于形成多边形需要多个顶点,因此我们将其声明为数组。
<summary>
頂点データリスト
</summary>
private VertexPositionColor[] vertices = null;
影响
在 XNA 中,当您绘制多边形时,您必须编写一个单独的着色器程序来决定如何绘制它。 为此,请创建一个单独的效果文件,编写一个程序,将其作为效果类加载,然后运行着色器程序。
但是,如果您不需要绘制像这样的简单三角形多边形或复杂的绘图效果,则这可能是一项非常繁琐的任务。
因此,XNA 定义了扩展效果,允许您将所需的项设置为属性,这样就不必为基本绘图编写着色器程序。 这就是 “BasicEffect” 类。 由于本文的目的是绘制多边形,因此我们将使用不需要太多努力绘制的 “BasicEffect”。
<summary>
基本エフェクト
</summary>
private BasicEffect basicEffect = null;
我将在下次详细讨论 Effects 和 BasicEffects。
顺便说一句,Windows Phone 7 不允许您使用自己的效果,只允许使用内置于 BasicEffect 等框架中的效果。
创建顶点数据定义
在 XNA 框架 3.1 之前,您必须以编程方式显式创建它们,但从 4.0 开始,框架的内置顶点信息已作为“IVertexType.VertexDeclaration”包含在顶点信息中,因此我们将使用它。
创建效果
创建一个 BasicEffect 类。 将 BasicEffect.VertexColorEnabled 属性设置为 true 以保留顶点颜色。
// エフェクトを作成
this.basicEffect = new BasicEffect(this.GraphicsDevice);
// エフェクトで頂点カラーを有効にする
this.basicEffect.VertexColorEnabled = true;
BasicEffect
构造 函数
创建效果类“BasicEffect”的实例,该实例使用 Shader Model 2.0 执行顶点颜色、纹理和照明。
装置 | 图形设备 | 指定用于创建效果的 GraphicsDevice |
视图矩阵和投影矩阵
将 BasicEffect 设置为视图矩阵和投影矩阵。 有关每个概念性解释,请参阅下面的链接。
// ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
this.basicEffect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 15.0f),
Vector3.Zero,
Vector3.Up
);
// プロジェクションマトリックスをあらかじめ設定
this.basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
若要生成视图矩阵,请使用 “Matrix.CreateLookAt” 方法。
第一个参数指定相机的位置,第二个参数指定相机的目标点,第三个参数指定相机的向上方向。
在这种情况下,它被设置为从位置 (0, 0, 15) 查看原点。
Matrix.CreateLookAt
方法
创建视图矩阵。
cameraPosition | 矢量 3 | 相机位置 |
cameraTarget 相机目标 | 矢量 3 | 相机目标点 |
cameraUpVector | 矢量 3 | 相机的向上方向 |
若要生成投影矩阵,请使用 “Matrix.CreatePerspectiveFieldOfView” 方法。
第一个参数是以弧度为单位的视角。 在示例中,度数单位使用 “MathHelper.ToRadians” 方法转换为弧度。 有关 Radian 和 Degree 的更多信息,请参阅 Radian 和 Degree。
第二个参数指定纵横比 (aspect ratio)。 通常,您可以为 View Width ÷ Height 指定一个值。 在示例中,它是根据为设备的视区设置的宽度和高度计算的。
第三个参数指定前向剪辑位置,第四个参数指定后向剪辑位置。
Matrix.CreatePerspectiveFieldOfView
方法
根据视图字段的设置创建透视投影矩阵。
fieldOfView 视图 | 浮 | 视角。 以弧度单位指定。 |
aspectRatio | 浮 | 纵横比 (aspect ratio)。 通常,您可以为“View Width ÷ Height”(视图宽度高度)指定一个值 |
nearPlaneDistance (近平面距离) | 浮 | 前向剪辑位置。 不会绘制此位置前面的对象。 |
farPlaneDistance (远平面距离) | 浮 | 后扣位置。 不会绘制超出此位置的对象。 |
创建顶点数据
创建 3 个顶点数据。 首先,我们将创建一个数组并创建每个顶点。
// 頂点データを作成する
this.vertices = new VertexPositionColor[3];
this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
Color.Red);
this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
Color.Blue);
this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
Color.Green);
要创建顶点数据,请在 “VertexPositionColor” 的构造函数中指定 “顶点位置” 和 “顶点颜色”。
VertexPositionColor
构造 函数
使用位置和颜色顶点数据创建结构 “VertexPositionColor” 的实例。
位置 | 矢量 3 | 顶点位置 |
颜色 | 颜色 | 顶点颜色 |
将顶点的位置设置为可从摄像机看到的范围。 另外,将顶点排列设置为 “clockwise (clockwise)”。 如果将其设置为 “counterclockwise”,则多边形将不可见。 有关此内容的说明,请参见指定要绘制的多边形的面。
绘制多边形
// パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
// パスの開始
pass.Apply();
// ポリゴンを描画する
this.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList,
this.vertices,
0,
1
);
}
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
有两种类型的效果,称为“技术”和“路径”,通过它们运行实际的绘图程序。 由于单个 effect 中可以有多个路径,因此我尝试在 foreach 中重复调用它们。 但是,在 BasicEffect 中,有一个技术和一个 path,所以你可以直接指定 path 的索引,但是上面的描述会更简洁,因为你可以用它来替换其他 effect。
在开始实际绘制之前,请调用 “EffectPass.Apply” 方法来启动通道。 通过调用该方法,将本次使用的效果参数应用到图形设备中。
启动路径后,使用“GraphicsDevice.DrawUserPrimitives”方法绘制多边形。
第一个参数指定要绘制的基元类型。 在本例中,我们将绘制一个三角形多边形,因此请指定 “PrimitiveType.TriangleList”。
第二个参数指定创建的顶点数据。
第三个参数指定要从中绘制的顶点。 通常,此值为 0。
第四个参数指定要绘制的基元数。 在这种情况下,只有一个三角形多边形,因此请指定 1。 请注意,它不是顶点数。
GraphicsDevice.DrawUserPrimitives
方法
根据用户提供的顶点数据绘制基元。
T | 无限制 | 顶点数据结构 |
primitiveType (原始类型) | PrimitiveType (基元类型) | 要绘制的基元类型 |
顶点数据 | T[] | 要绘制的顶点数据数组 |
vertexOffset (顶点偏移) | int | 指定要用于绘制的顶点数据的数量 |
primitiveCount | int | 要绘制的基元数。 |
这就是绘图程序的全部内容。 如果您实际运行它并显示一个三角形,则您已完成。
所有代码
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;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif
namespace DrawTriangle
{
<summary>
ゲームメインクラス
</summary>
public class GameMain : Microsoft.Xna.Framework.Game
{
<summary>
グラフィックデバイス管理クラス
</summary>
private GraphicsDeviceManager graphics = null;
<summary>
スプライトのバッチ化クラス
</summary>
private SpriteBatch spriteBatch = null;
<summary>
頂点データリスト
</summary>
private VertexPositionColor[] vertices = null;
<summary>
基本エフェクト
</summary>
private BasicEffect basicEffect = null;
<summary>
GameMain コンストラクタ
</summary>
public GameMain()
{
// グラフィックデバイス管理クラスの作成
this.graphics = new GraphicsDeviceManager(this);
// ゲームコンテンツのルートディレクトリを設定
this.Content.RootDirectory = "Content";
#if WINDOWS_PHONE
// Windows Phone のデフォルトのフレームレートは 30 FPS
this.TargetElapsedTime = TimeSpan.FromTicks(333333);
// バックバッファサイズの設定
this.graphics.PreferredBackBufferWidth = 480;
this.graphics.PreferredBackBufferHeight = 800;
// フルスクリーン表示
this.graphics.IsFullScreen = true;
#endif
}
<summary>
ゲームが始まる前の初期化処理を行うメソッド
グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
</summary>
protected override void Initialize()
{
// TODO: ここに初期化ロジックを書いてください
// コンポーネントの初期化などを行います
base.Initialize();
}
<summary>
ゲームが始まるときに一回だけ呼ばれ
すべてのゲームコンテンツを読み込みます
</summary>
protected override void LoadContent()
{
// テクスチャーを描画するためのスプライトバッチクラスを作成します
this.spriteBatch = new SpriteBatch(this.GraphicsDevice);
// エフェクトを作成
this.basicEffect = new BasicEffect(this.GraphicsDevice);
// エフェクトで頂点カラーを有効にする
this.basicEffect.VertexColorEnabled = true;
// ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
this.basicEffect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 15.0f),
Vector3.Zero,
Vector3.Up
);
// プロジェクションマトリックスをあらかじめ設定
this.basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
// 頂点データを作成する
this.vertices = new VertexPositionColor[3];
this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
Color.Red);
this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
Color.Blue);
this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
Color.Green);
}
<summary>
ゲームが終了するときに一回だけ呼ばれ
すべてのゲームコンテンツをアンロードします
</summary>
protected override void UnloadContent()
{
// TODO: ContentManager で管理されていないコンテンツを
// ここでアンロードしてください
}
<summary>
描画以外のデータ更新等の処理を行うメソッド
主に入力処理、衝突判定などの物理計算、オーディオの再生など
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Update(GameTime gameTime)
{
// Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
// ゲームを終了させます
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
// TODO: ここに更新処理を記述してください
// 登録された GameComponent を更新する
base.Update(gameTime);
}
<summary>
描画処理を行うメソッド
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Draw(GameTime gameTime)
{
// 画面を指定した色でクリアします
this.GraphicsDevice.Clear(Color.CornflowerBlue);
// パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
// パスの開始
pass.Apply();
// ポリゴンを描画する
this.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList,
this.vertices,
0,
1
);
}
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
}
}
}