显示三角形多边形

更新页 :
页面创建日期 :

总结

它在 3D 空间中显示三角形多边形。

3角形ポリゴンの表示

经营环境

先决条件

支持的 XNA 版本
  • 4.0
支持的平台
  • Windows(XP SP2 或更高版本、Vista、7)
  • Xbox 360 的
  • Windows Phone 7 系列
Windows 所需的顶点着色器版本 2.0
Windows 所需的像素着色器版本 2.0

经营环境

平台
  • 视窗 7
  • Xbox 360 的
  • Windows Phone 7 模拟器

物质

什么是多边形?

多边形是由多个顶点定义生成的面。 通常,多边形是由三个顶点组成的三角形面。 三角体是多边形的最小单位。 某些建模软件可能会将多边形显示为四边形或多边形,但这些多边形最终会分解为三角形多边形。

游戏中显示的模型是由多个这些三角形多边形组合而成的。

最小単位のポリゴン

多边形由顶点组成。 顶点可以包含位置和颜色等数据。 此示例也是由 “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);
        }
    }
}