カウンタ

  SDK の標準メッシュを作成

Google
▲探し物はこちら

 今までオリジナルのモデルデータを使用していましたが、データがかさばるので、SDKの「Mesh」クラスで簡単に作成できるメッシュを使用してみることにします。モデルデータを用意しなくてもそれなりの形のメッシュが作成できるので便利です。各メッシュは自動的に回転させています。

SDK の標準メッシュを作成

 下のリンクから今回のプロジェクトをダウンロードできます。

ファイル名 言語 サイズ バージョン
sdkmesh_cs_1_1.zip C# 26KB 1.1
sdkmesh_vb_1_1.zip VB.NET 32KB 1.1
sdkmesh_cpp_1_1.zip C++/CLI 14KB 1.1

 今回のメインコードファイルを載せます。重要なコードを赤色で表示させています

MainSample.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXSample
{
    /// <summary>
    /// メインサンプルクラス
    /// </summary>
    public partial class MainSample : IDisposable
    {
        /// <summary>
        /// ボックスメッシュ
        /// </summary>
        private Mesh _boxMesh = null;

        /// <summary>
        /// 円柱メッシュ
        /// </summary>
        private Mesh _cylinderMesh = null;

        /// <summary>
        /// ポリゴンメッシュ
        /// </summary>
        private Mesh _polygonMesh = null;

        /// <summary>
        /// 球メッシュ
        /// </summary>
        private Mesh _sphereMesh = null;

        /// <summary>
        /// ティーポットメッシュ
        /// </summary>
        private Mesh _teapotMesh = null;

        /// <summary>
        /// テキストメッシュ
        /// </summary>
        private Mesh _textMesh = null;

        /// <summary>
        /// トーラスメッシュ
        /// </summary>
        private Mesh _torusMesh = null;


        /// <summary>
        /// アプリケーションの初期化
        /// </summary>
        /// <param name="topLevelForm">トップレベルウインドウ</param>
        /// <returns>全ての初期化がOKなら true, ひとつでも失敗したら false を返すようにする</returns>
        /// <remarks>
        /// false を返した場合は、自動的にアプリケーションが終了するようになっている
        /// </remarks>
        public bool InitializeApplication(MainForm topLevelForm)
        {
            // フォームの参照を保持
            this._form = topLevelForm;

            // 入力イベント作成
            this.CreateInputEvent(topLevelForm);


            try
            {
                // Direct3D デバイス作成
                this.CreateDevice(topLevelForm);

                // フォントの作成
                this.CreateFont();
            }
            catch (DirectXException ex)
            {
                // 例外発生
                MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            // XYZライン作成
            this.CreateXYZLine();


            // ボックス
            this._boxMesh = Mesh.Box(this._device, 2.0f, 1.0f, 0.5f);

            // 円柱
            this._cylinderMesh = Mesh.Cylinder(this._device, 0.5f, 0.8f, 1.5f, 8, 1);

            // ポリゴン
            this._polygonMesh = Mesh.Polygon(this._device, 1.0f, 5);

            // 球
            this._sphereMesh = Mesh.Sphere(this._device, 0.8f, 8, 6);

            // ティーポット
            this._teapotMesh = Mesh.Teapot(this._device);

            // テキスト
            System.Drawing.Font fnt = new System.Drawing.Font("Impact", 1);
            this._textMesh = Mesh.TextFromFont(this._device, fnt, "Text", 5.0f, 0.4f);

            // トーラス
            this._torusMesh = Mesh.Torus(this._device, 0.1f, 0.6f, 6, 12);


            // ライトを設定
            this.SettingLight();

            // ポリゴンの両面を描画するようにカリングを無効にする
            //this._device.RenderState.CullMode = Cull.None;

            return true;
        }

        /// <summary>
        /// メインループ処理
        /// </summary>
        public void MainLoop()
        {
            // カメ�����設���
            this.SettingCamera();


            // 描画内容を単色でクリアし、Zバッファもクリア
            this._device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0);

            // 「BeginScene」と「EndScene」の間に描画内容を記述する
            this._device.BeginScene();


            // ライトを無効
            this._device.RenderState.Lighting = false;

            // 原点に配置
            this._device.SetTransform(TransformType.World, Matrix.Identity);

            // XYZラインを描画
            this.RenderXYZLine();


            // ライト有効
            this._device.RenderState.Lighting = true;

            // すべて白のマテリアル使用
            Material mtrl = new Material();
            mtrl.Diffuse = Color.White;
            mtrl.Ambient = Color.FromArgb(255, 128, 128, 128);
            this._device.Material = mtrl;

            // すべてのメッシュを回転させるためのY軸回転
            Matrix rotateMatrix = Matrix.RotationY(Environment.TickCount / 1000.0f);

            // ボックス
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(0.0f, 2.0f, 0.0f)));
            this._boxMesh.DrawSubset(0);

            // 円柱
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(-2.5f, 0.8f, 0.0f)));
            this._cylinderMesh.DrawSubset(0);

            // ポリゴン
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(-2.5f, -0.8f, 0.0f)));
            this._polygonMesh.DrawSubset(0);

            // 球
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(0.0f, -2.0f, 0.0f)));
            this._sphereMesh.DrawSubset(0);

            // ティーポット
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(0.0f, 0.0f, 0.0f)));
            this._teapotMesh.DrawSubset(0);

            // テキスト
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(2.5f, -0.8f, 0.0f)));
            this._textMesh.DrawSubset(0);

            // トーラス
            this._device.SetTransform(TransformType.World,
                rotateMatrix * Matrix.Translation(new Vector3(2.5f, 0.8f, 0.0f)));
            this._torusMesh.DrawSubset(0);


            // 文字列の描画
            this._font.DrawText(null, "[Escape]終了", 0, 0, Color.White);
            this._font.DrawText(null, "θ:" + this._lensPosTheta, 0, 12, Color.White);
            this._font.DrawText(null, "φ:" + this._lensPosPhi, 0, 24, Color.White);

            // 描画はここまで
            this._device.EndScene();

            // 実際のディスプレイに描画
            this._device.Present();

            // アプリケーションの終了操作
            if (this._keys[(int)Keys.Escape])
            {
                this._form.Close();
            }
        }

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void Dispose()
        {
            // メッシュの破棄
            if (this._boxMesh != null)
            {
                this._boxMesh.Dispose();
            }
            if (this._cylinderMesh != null)
            {
                this._cylinderMesh.Dispose();
            }
            if (this._polygonMesh != null)
            {
                this._polygonMesh.Dispose();
            }
            if (this._sphereMesh != null)
            {
                this._sphereMesh.Dispose();
            }
            if (this._teapotMesh != null)
            {
                this._teapotMesh.Dispose();
            }
            if (this._textMesh != null)
            {
                this._textMesh.Dispose();
            }
            if (this._torusMesh != null)
            {
                this._torusMesh.Dispose();
            }

            // XYZラインの破棄
            this.DisposeXYZLine();

            // フォントのリソースを解放
            if (this._font != null)
            {
                this._font.Dispose();
            }

            // Direct3D デバイスのリソース解放
            if (this._device != null)
            {
                this._device.Dispose();
            }
        }
    }
}

 では、赤文字の部分を説明していきます。MainSamplePartial.cs ファイルのコードはこちらです。


/// <summary>
/// ボックスメッシュ
/// </summary>
private Mesh _boxMesh = null;

/// <summary>
/// 円柱メッシュ
/// </summary>
private Mesh _cylinderMesh = null;

/// <summary>
/// ポリゴンメッシュ
/// </summary>
private Mesh _polygonMesh = null;

/// <summary>
/// 球メッシュ
/// </summary>
private Mesh _sphereMesh = null;

/// <summary>
/// ティーポットメッシュ
/// </summary>
private Mesh _teapotMesh = null;

/// <summary>
//// テキストメッシュ
/// </summary>
private Mesh _textMesh = null;

/// <summary>
/// トーラスメッシュ
/// </summary>
private Mesh _torusMesh = null;

 SDK の「Mesh」クラスには上記の7種類のメッシュを簡単に作成できるメソッドがあります。これらを表示するために「Mesh」クラスのフィールドを宣言しておきます。


// ボックス
this._boxMesh = Mesh.Box(this._device, 2.0f, 1.0f, 0.5f);

 メッシュの作成部分に移りますが、一気に載せるとごちゃごちゃするのでひとつずつ説明します。

 まずボックスの作成には「Mesh.Box」メソッドを使用します。

 第1引数は Direct3D デバイスを渡してください。他のメッシュを作成するときも同じです。

 第2、第3、第4引数はそれぞれ「X」「Y」「Z」方向のボックスの辺の長さになります。下のような感じになります。メッシュの原点はボックスの中心になります。

ボックス

 ちなみにこのメソッドで面は細かく分割することは出来ません。かならず12枚の三角ポリゴンから構成されます。

Mesh.Box メソッド

ボックスメッシュ作成
device Direct3D デバイス
width X軸方向の長さ
height Y軸方向の長さ
depth Z軸方向の長さ

// 円柱
this._cylinderMesh = Mesh.Cylinder(this._device, 0.5f, 0.8f, 1.5f, 8, 1);

 まず円柱の作成には「Mesh.Cylinder」メソッドを使用します。

 第2引数は Z 軸の負の方向に向いている面の円の半径です。
 第3引数は Z 軸の正の方向に向いている面の円の半径です。
 第4引数は円柱の長さです。円と円の間の辺の長さではないので注意してください。
 第5引数は円以外の棒の部分にあたる Z 軸に平行な分割数です。
 第6引数は円以外の棒の部分にあたる Z 軸に垂直な分割数です。

円柱
番号は引数の順番と同じにしています

Mesh.Cylinder メソッド

円柱メッシュ作成
device Direct3D デバイス
radius1 Z 軸の負の側の面の半径
radius2 Z 軸の正の側の面の半径
length Z 軸方向の円柱の長さ
slices 主軸を回転軸としたスライスの数
stacks 主軸に沿ったスタックの数

// ポリゴン
this._polygonMesh = Mesh.Polygon(this._device, 1.0f, 5);

 「Mesh.Polygon」メソッドでは「n 角形」の平面ポリゴンを作成します。

 第2引数は外側の一辺の長さです。
 第3引数は n 角形の n の値です。

 また面は Z 軸の正の方向を向いています

ポリゴン
Z 軸は手前に伸びている

Mesh.Polygon メソッド

Nポリゴンメ������������シュ���成
device Direct3D デバイス
length 各辺の長さ
sides ポリゴンの辺の数

 また、これで作成されたポリゴンは頂点インデックスが右回りで作成されるので通常片面しかレンダリングしません。両面レンダリングする場合は「Device.RenderState.CullMode」を「Cull.None」に設定します。


// 球
this._sphereMesh = Mesh.Sphere(this._device, 0.8f, 8, 6);

 球は「Mesh.Sphere」メソッドで作成します。

 第2引数は球の半径です。
 第3引数は Z 軸に平行な分割数です。
 第4引数は Z 軸に垂直な分割数です。

球

Mesh.Sphere メソッド

球メッシュ作成
device Direct3D デバイス
radius 球の半径
slices 主軸を回転軸としたスライスの数
stacks 主軸に沿ったスタックの数

// ティーポット
this._teapotMesh = Mesh.Teapot(this._device);

 ティーポットは「Mesh.Teapot」メソッドで作成します。この作成で特別設定するものはありません。大きさを変えたい場合は、直接頂点データを書き換えるか、描画前の座標変換でスケーリングする必要があります。

Mesh.Teapot メソッド

ティーポットメッシュ作成
device Direct3D デバイス

// テキスト
System.Drawing.Font fnt = new System.Drawing.Font("Impact", 1);
this._textMesh = Mesh.TextFromFont(this._device, fnt, "Text", 5.0f, 0.4f);

 任意のテキストを簡単に3D化することが出来ます。「Mesh.TextFromFont」メソッドで作成できますが、この引数で「System.Drawing.Font」を渡さないといけないのであらかじめ作成しておきます。

 ここではフォント名を「Impact」にしていますが、日本語を使うなら「MS ゴシック」とかでもかまいません。「System.Drawing.Font」に関して詳しい説明は省きます。太文字やイタリックなんかも出来るので各自やってみてください。

 作成したフォントクラスを「Mesh.TextFromFont」メソッドの第2引数に渡します。

 第3引数に任意の文字列を渡してください。
 第4引数は「フォントアウトラインからの最大コード偏差」とヘ���プに書かれてい��������すが、私にはよくわからないので適当に渡しています。
 第5引数は Z 軸の負の方向に押し出す量です。文字の奥行きになります。

 作成されたメッシュの原点ですが、文字列の中央ではなく、一番最初の文字の左下の Z 軸の正方向が原点になります。

テキスト
このあたり (頂点位置ではありません)

Mesh.TextFromFont メソッド

テキストメッシュ作成
device Direct3D デバイス
font フォントオブジェクト
text 生成するテキストを指定する文字列
deviation フォント アウトラインからの最大コード偏差
extrusion テキストを z 軸の負の方向に押し出す量

// トーラス
this._torusMesh = Mesh.Torus(this._device, 0.1f, 0.6f, 6, 12);

 トーラストはドーナッツみたいな形をしたもののことをいいます。

 渡すパラメータですが、ヘルプを見ると読み方によって以外と勘違いする人もいるかと思うので、直接図で説明します。(特に第2、第3引数は間違えやすい

 第2引数はトーラスの内部の半径
 第3引数はトーラスの外部の半径
 第4引数は横断面の辺の数
 第5引数はトーラスの環の数

トーラス1 トーラス2

Mesh.Torus メソッド

トーラスメッシュ作成
device Direct3D デバイス
innerRadius トーラスの内部の半径
outerRadius トーラスの外部の半径
sides 横断面の辺の数
rings トーラスの環の数

// ライト有効
this._device.RenderState.Lighting = true;

// すべて白のマテリアル使用
Material mtrl = new Material();
mtrl.Diffuse = Color.White;
mtrl.Ambient = Color.FromArgb(255, 128, 128, 128);
this._device.Material = mtrl;

 マテリアルはすべてのメッシュを白に塗りつぶすように設定しています。
 もし、メッシュごとに色を変えたいのなら、各メッシュの描画前にマテリアルを変更して「Device.Material」に渡してください。


// すべてのメッシュを回転させるためのY軸回転
Matrix rotateMatrix = Matrix.RotationY(Environment.TickCount / 1000.0f);

 メッシュが止まっているのも面白くないので経過時間で回転させるようにしています。すべてのメッシュを同じように回転させるので、ここで回転マトリックスを作成してしまいます。


// ボックス
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(0.0f, 2.0f, 0.0f)));
this._boxMesh.DrawSubset(0);

// 円柱
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(-2.5f, 0.8f, 0.0f)));
this._cylinderMesh.DrawSubset(0);

// ポリゴン
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(-2.5f, -0.8f, 0.0f)));
this._polygonMesh.DrawSubset(0);

// 球
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(0.0f, -2.0f, 0.0f)));
this._sphereMesh.DrawSubset(0);

// ティーポット
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(0.0f, 0.0f, 0.0f)));
this._teapotMesh.DrawSubset(0);

// テキスト
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(2.5f, -0.8f, 0.0f)));
this._textMesh.DrawSubset(0);

// トーラス
this._device.SetTransform(TransformType.World,
    rotateMatrix * Matrix.Translation(new Vector3(2.5f, 0.8f, 0.0f)));
this._torusMesh.DrawSubset(0);

 後は各メッシュを指定位置に配置して、その場で回転するように座標変換し、描画しています。

 ���ッ��ュをその場で回転させ��場合は「���転」×���移����」の����番で掛け�����く���さい���
 これを「移動」×「回転」の順番にすると、ワールド座標の原点のY軸を中心にメッシュが回転移動するようになります。(これはこれで面白いです

 描画するときに「Mesh.DrawSubset」メソッドを使用しますが引数には 0 を渡してください。SDK のメッシュは基本的にサブセットはひとつなので、これだけでメッシュの全体を表示できます。


// メッシュの破棄
if (this._boxMesh != null)
{
    this._boxMesh.Dispose();
}
if (this._cylinderMesh != null)
{
    this._cylinderMesh.Dispose();
}
if (this._polygonMesh != null)
{
    this._polygonMesh.Dispose();
}
if (this._sphereMesh != null)
{
    this._sphereMesh.Dispose();
}
if (this._teapotMesh != null)
{
    this._teapotMesh.Dispose();
}
if (this._textMesh != null)
{
    this._textMesh.Dispose();
}
if (this._torusMesh != null)
{
    this._torusMesh.Dispose();
}

 いつものように使い終わったメッシュは解放します。

その他の関連情報です▼