カウンタ

  頂点フォーマットの変更と頂点データの設定

Google
▲探し物はこちら

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

頂点フォーマットの変更と頂点データの設定

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

ファイル名 言語 サイズ バージョン
changemeshvertexdata_cs_1_1.zip C# 27KB 1.1
changemeshvertexdata_vb_1_1.zip VB.NET 33KB 1.1
changemeshvertexdata_cpp_1_1.zip C++/CLI 33KB 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 _mesh = null;

        /// <summary>
        /// 変更前の頂点フォーマット
        /// </summary>
        private VertexFormats _beforeVertexFormats = VertexFormats.None;


        /// <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();

                // XYZライン作成
                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;
            }

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

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


            // XYZライン描画
            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を使用していないことと同じで���。少���煩わ����いの���注意����て���ださい。

その他の関連情報です▼