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

下のリンクから今回のプロジェクトをダウンロードできます。
今回のメインコードファイルを載せます。重要なコードを赤色で表示させています。
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></returns>
/// <remarks>
///
/// </remarks>
public bool InitializeApplication(MainForm topLevelForm)
{
this._form = topLevelForm;
this.CreateInputEvent(topLevelForm);
try
{
this.CreateDevice(topLevelForm);
this.CreateFont();
}
catch (DirectXException ex)
{
MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
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();
return true;
}
/// <summary>
///
/// </summary>
public void MainLoop()
{
this.SettingCamera();
this._device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0);
this._device.BeginScene();
this._device.RenderState.Lighting = false;
this._device.SetTransform(TransformType.World, Matrix.Identity);
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();
}
this.DisposeXYZLine();
if (this._font != null)
{
this._font.Dispose();
}
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引数はトーラスの環の数

|
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」に渡してください。
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();
}
|
いつものように使い終わったメッシュは解放します。
|