頂点フォーマットの変更と頂点データの設定
メッシュは作成した後でも、頂点フォーマットの変更や頂点データの設定、取得を行うことが出来ます。今回は、「位置」「法線」しか持たないメッシュに「ディフューズ色」を追加して、各頂点に色を設定していきます。

下のリンクから今回のプロジェクトをダウンロードできます。
今回のメインコードファイルを載せます。重要なコードを赤色で表示させています。
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 _mesh = null;
/// <summary>
/// 変更前の頂点フォーマット
/// </summary>
private VertexFormats _beforeVertexFormats = VertexFormats.None;
/// <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();
this.CreateXYZLine();
}
catch (DirectXException ex)
{
MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
this.SetCameraPosition(5.0f, 270.0f, 0.0f);
// ティーポットメッシュ作成
this._mesh = Mesh.Teapot(this._device);
// 変更前の頂点フォーマットを取得
this._beforeVertexFormats = this._mesh.VertexFormat;
// 頂点色を追加した新しいフォーマットでメッシュを複製
Mesh tempMesh = this._mesh.Clone(this._mesh.Options.Value,
CustomVertex.PositionNormalColored.Format, this._device);
// メッシュの頂点データをロックして取得
CustomVertex.PositionNormalColored[] source =
(CustomVertex.PositionNormalColored[])tempMesh.LockVertexBuffer(
typeof(CustomVertex.PositionNormalColored), LockFlags.None,
tempMesh.NumberVertices);
// 頂点の数取得
int len = source.Length;
// ディフューズ色を設定
for (int i = 0; i < len; i++)
{
// 適当に色を設定
source[i].Color = Color.FromArgb(
(int)(i * 255.0f / len), (int)(i * 255.0f / len), 255).ToArgb();
}
// メッシュの頂点データをアンロック
tempMesh.UnlockVertexBuffer();
// 最初のメッシュは破棄
this._mesh.Dispose();
// 新しいメッシュを参照
this._mesh = tempMesh;
this.SettingLight();
return true;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void device_DeviceLost(object sender, EventArgs e)
{
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void device_DeviceReset(object sender, EventArgs e)
{
}
/// <summary>
///
/// </summary>
public void Update()
{
if (this._keys[(int)Keys.Escape])
{
this._form.Close();
return;
}
this.SettingCamera();
}
/// <summary>
///
/// </summary>
public void Draw()
{
if (!this.EnsureDevice())
{
return;
}
this._device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, Color.DarkBlue, 1.0f, 0);
this._device.BeginScene();
this.RenderXYZLine();
// マテリアルセット
Material mtrl = new Material();
mtrl.Diffuse = Color.White;
mtrl.Ambient = Color.FromArgb(255, 128, 128, 128);
this._device.Material = mtrl;
// 回転させる
this._device.SetTransform(TransformType.World,
Matrix.RotationY((float)(Environment.TickCount / 1000.0f)));
// 描画
this._mesh.DrawSubset(0);
this.RenderText();
this._device.EndScene();
this._device.Present();
}
/// <summary>
///
/// </summary>
private void RenderText()
{
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._font.DrawText(null, "変更前頂点フォーマット:" + this._beforeVertexFormats,
0, 36, Color.Yellow);
this._font.DrawText(null, "変更後頂点フォーマット:" + this._mesh.VertexFormat,
0, 48, Color.Yellow);
}
/// <summary>
///
/// </summary>
public void Dispose()
{
this.SafeDispose(this._mesh);
this.DisposeResource();
}
}
}
|
では、赤文字の部分を説明していきます。そのほかのファイルのコードはこちらです。
/// <summary>
///
/// </summary>
private Mesh _mesh = null;
/// <summary>
///
/// </summary>
private VertexFormats _beforeVertexFormats = VertexFormats.None;
|
ティーポットを描画するために Mesh を宣言しておきます。
また、本来は必要ないのですが、頂点情報変更前のメッシュの頂点フォーマットも表示させたいので VertexFormats を持っておきます。
this._mesh = Mesh.Teapot(this._device);
this._beforeVertexFormats = this._mesh.VertexFormat;
|
ティーポットメッシュを作成し、その時点での頂点フォーマットを取得しています。ちなみに「Mesh.Teapot」で作成したメッシュの頂点情報は「位置」と「法線」です。
Mesh tempMesh = this._mesh.Clone(this._mesh.Options.Value,
CustomVertex.PositionNormalColored.Format, this._device);
|
まず最初に頂点フォーマットを変更します。実は作成したメッシュの頂点フォーマットは直接変更できないので、新しく複製したときに新しい頂点フォーマットで作成するようにします。
複製するには、Mesh.Clone
メソッドを使用します。頂点フォーマット以外は基本的に以前のメッシュのデータを引き継ぐようにするので、第1引数にはオプションをそのまま渡します。
第2引数に新しい頂点フォーマットを渡すようにします。ここでは「位置」「法線」「ディフューズ色」の頂点フォーマットを指定します。
CustomVertex.PositionNormalColored[] source =
(CustomVertex.PositionNormalColored[])tempMesh.LockVertexBuffer(
typeof(CustomVertex.PositionNormalColored), LockFlags.None,
tempMesh.NumberVertices);
|
複製したメッシュに対して「Mesh.LockVertexBuffer」メソッドを使用することにより、頂点バッファのデータにアクセスできるようになります。
まず、第1引数に頂点データの構造体の型(タイプ)を渡します。「typeof」を使用すると、「Type」に変換されるので、これを使用します。
第2引数はロックフラグですが、特になければ LockFlags.None でいいです。
第3引数に頂点の数を渡します。「Mesh.NumberVertices」プロパティで取得できるのでこれを使用します。
このメソッドを使用すると、頂点バッファの頂点データの配列を取得できますが、ただの「Array」クラスで返されるので、「CustomVertex.PositionNormalColored[]」にキャストして受け取ります。
int len = source.Length;
for (int i = 0; i < len; i++)
{
source[i].Color = Color.FromArgb(
(int)(i * 255.0f / len), (int)(i * 255.0f / len), 255).ToArgb();
}
|
頂点データを受け取ったら、ディフューズ色を設定します。今回は色の違いが分かるように適当に色を設定しています。
tempMesh.UnlockVertexBuffer();
this._mesh.Dispose();
this._mesh = tempMesh;
|
ロックしたメッシュは必ずロックを解除してください。
その後、最初に作成したメッシュは破棄し、新しいメッシュに置き換えるようにします。
Material mtrl = new Material();
mtrl.Diffuse = Color.White;
mtrl.Ambient = Color.FromArgb(255, 128, 128, 128);
this._device.Material = mtrl;
this._device.SetTransform(TransformType.World,
Matrix.RotationY((float)(Environment.TickCount / 1000.0f)));
this._mesh.DrawSubset(0);
|
頂点フォーマットを変更しても、基本的に描画部分に変更点はありません。
this._font.DrawText(null, "変更前頂点フォーマット:" + this._beforeVertexFormats,
0, 36, Color.Yellow);
this._font.DrawText(null, "変更後頂点フォーマット:" + this._mesh.VertexFormat,
0, 48, Color.Yellow);
|
頂点フォーマットがきちんと変更されているか確認するために、変更前と変更後の頂点フォーマットを表示しています。
ちなみに「Texture0」と表示されるかもしれませんが、これはテクスチャーUVを使用していないことと同じで���。少���煩わ����いの���注意����て���ださい。
|