カウンタ

  様々な 2D ラインの描画

Google
▲探し物はこちら

 スクリーン座標(2D)でラインを表示させるようにしています。
 座標変換済み頂点を使用してもラインは描画できるのですが、SDK の「Line」クラスを使用することにより、いくつかのパターンでラインを描画することが出来ます。

様々な 2D ラインの描画

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

ファイル名 言語 サイズ バージョン
line2d_cs_1_1.zip C# 25KB 1.1
line2d_vb_1_1.zip VB.NET 31KB 1.1
line2d_cpp_1_1.zip C++/CLI 32KB 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 Line _line = 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._line = new Line(this._device);

            return true;
        }

        /// <summary>
        /// メインループ処理
        /// </summary>
        public void MainLoop()
        {
            // アプリケーションの終了操作
            if (this._keys[(int)Keys.Escape])
            {
                this._form.Close();
                return;
            }

            // カメラの設定
            this.SettingCamera();


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

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


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

            // テクスチャー無効
            this._device.SetTexture(0, null);

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

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


            // ラインの描画
            // 本来は「Line.Begin」メソッドと「LineEnd」メソッドの間に
            // ��イン����画���ード��入��るが
            // ラインクラスのパラメータを常に変更しているので使わない
            //this._line.Begin();

            // ラインの位置を保持するためのベクトル配列
            Vector2[] positions = new Vector2[3];

            // 初期化
            this._line.Width = 1.0f;
            this._line.Antialias = false;
            this._line.Pattern = -1;
            this._line.PatternScale = 1.0f;

            // 通常のライン
            this._font.DrawText(null, "通常のライン", 20, 120, Color.White);
            positions[0] = new Vector2(50.0f, 150.0f);
            positions[1] = new Vector2(250.0f, 150.0f);
            positions[2] = new Vector2(450.0f, 100.0f);
            this._line.Draw(positions, Color.White);

            // 太いライン
            this._font.DrawText(null, "太いライン", 20, 170, Color.White);
            positions[0] = new Vector2(50.0f, 200.0f);
            positions[1] = new Vector2(250.0f, 200.0f);
            positions[2] = new Vector2(450.0f, 150.0f);
            this._line.Width = 10.0f;
            this._line.Draw(positions, Color.Yellow);

            // アンチエイリアス
            this._font.DrawText(null, "アンチエイリアス", 20, 220, Color.White);
            positions[0] = new Vector2(50.0f, 250.0f);
            positions[1] = new Vector2(250.0f, 250.0f);
            positions[2] = new Vector2(450.0f, 200.0f);
            this._line.Antialias = true;
            this._line.Draw(positions, Color.Yellow);

            // パターン通常
            this._font.DrawText(null, "パターン通常", 20, 270, Color.White);
            positions[0] = new Vector2(50.0f, 300.0f);
            positions[1] = new Vector2(250.0f, 300.0f);
            positions[2] = new Vector2(450.0f, 250.0f);
            this._line.Pattern = 1;
            this._line.PatternScale = 1.0f;
            this._line.Draw(positions, Color.LightBlue);

            // パターン間隔0.5倍
            this._font.DrawText(null, "パターン間隔 0.5 倍", 20, 320, Color.White);
            positions[0] = new Vector2(50.0f, 350.0f);
            positions[1] = new Vector2(250.0f, 350.0f);
            positions[2] = new Vector2(450.0f, 300.0f);
            this._line.PatternScale = 0.5f;
            this._line.Draw(positions, Color.LightPink);

            // 「Line.Begin」を使用していないのでコメントアウト
            //this._line.End();


            // 文字列の描画
            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();
        }

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void Dispose()
        {
            // ラインクラスの解放
            this.SafeDispose(this._line);
            
            // リソースの破棄
            this.DisposeResource();
        }
    }
}

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


/// <summary>
/// ラインクラス
/// </summary>
private Line _line = null;

 今回2Dラインを描画するのに「Line」クラスを使用します。座標変換済み頂点をライン描画に置き換えてしまうことも出来るのですが、描画パターンが限られています。Line クラスを使用することにより、線を太くしたり、アンチエイリアスを掛けたりするのが非常に簡単なので、こちらを使ってみたいと思います。


// ラインクラスの作成
this._line = new Line(this._device);

 Direct3D デバイスを渡せば Line クラスを作成することが出来ます。今回メインループでパラメータを変更させているので、初期化メソッドで設定するものは特にありません。


// ラインの描画
// 本来は「Line.Begin」メソッドと「LineEnd」メソッドの間に
// ライン描画コードを入れるが
// ラインクラスのパラメータを常に変更しているので使わない
//this._line.Begin();

 ラインを描画する場合は「Line.Begin」メソッドと「Line.End」メソッドの間に記述しないといけないのですが、その2つのメソッドの間で Line クラスのプロパティを変更するとエラーが発生するようなので今回は使用しないことにします。

 「LineBegin」と「Line.End」を使用しなくでもライン描画時に内部で呼んでいるので実際には問題ありません。ただ、複数のライン描画を行う場合は「LineBegin」と「Line.End」を使用しないと処理速度が低下する場合があります。(今回はサンプルなので処理速度にはこだわっていません


// ラインの位置を保持するためのベクトル配列
Vector2[] positions = new Vector2[3];

 ライン描画時には各頂点の位置の配列を渡す必要があるので、「Vector2」の配列を作成します。別なラインを描画するたびに配列を作成するのも面倒なので、一律下のようなラインを描画することにします。

3つの頂点によるライン描画


// 初期化
this._line.Width = 1.0f;
this._line.Antialias = false;
this._line.Pattern = -1;
this._line.PatternScale = 1.0f;

 描画毎に違う設定をしているので最初に初期化するようにしています。各パラメータに関しては後のセクションで説明します。


// 通常のライン
this._font.DrawText(null, "通常のライン", 20, 120, Color.White);
positions[0] = new Vector2(50.0f, 150.0f);
positions[1] = new Vector2(250.0f, 150.0f);
positions[2] = new Vector2(450.0f, 100.0f);
this._line.Draw(positions, Color.White);

 設定を何も変更していない状態のラインを描画しています。描画するには「Line.Draw」メソッドにスクリーン座標での頂点位置の配列線の色を渡します。
 頂点の配列の数に応じて繋がった(折れ曲がった)線を描画することが出来ます。

通常のライン


// 太いライン
this._font.DrawText(null, "太いライン", 20, 170, Color.White);
positions[0] = new Vector2(50.0f, 200.0f);
positions[1] = new Vector2(250.0f, 200.0f);
positions[2] = new Vector2(450.0f, 150.0f);
this._line.Width = 10.0f;
this._line.Draw(positions, Color.Yellow);

 「Line.Width」プロパティを変更することにより、線の太さを変更することが出来ます。float で設定しますが、スクリーン座標での設定なので 1.0f が太さ1ドットになります。

太いライン

 よく見ると線が曲がっているところで微妙に切れていることが分かります。実はこの Line クラスは線を描画しているのではなく、四角形ポリゴンを変換させて描画しているのです。そのため、下の図のように描画しているのでこのようになってしまうのです。

隙間ができる

 太いラインを曲げるときは、繋げて描画するのではなく、個別に描画したほうがいいかもしれません。


// アンチエイリアス
this._font.DrawText(null, "アンチエイリアス", 20, 220, Color.White);
positions[0] = new Vector2(50.0f, 250.0f);
positions[1] = new Vector2(250.0f, 250.0f);
positions[2] = new Vector2(450.0f, 200.0f);
this._line.Antialias = true;
this._line.Draw(positions, Color.Yellow);

 「Line.Antialias」プロパティを true にすることにより、アンチエイリアスが掛かり、線のギザギザが滑らかに見えるようになります。

 下の図では直線はギザギザが無いのであまり分からないですが、斜めの線が滑らかになっていることが分かります。

アンチエイリアス

// パターン通常
this._font.DrawText(null, "パターン通常", 20, 270, Color.White);
positions[0] = new Vector2(50.0f, 300.0f);
positions[1] = new Vector2(250.0f, 300.0f);
positions[2] = new Vector2(450.0f, 250.0f);
this._line.Pattern = 1;
this._line.PatternScale = 1.0f;
this._line.Draw(positions, Color.LightBlue);

 「Line.Pattern」プロパティを 1 に設定するとラインが点描みたいに描画されます。1 以上も設定できるようですが、どのような法則で描画されているかは不明です。(ヘルプにも 0 と 1 のことしか書かれていません
 わかりやすいように線を太くしています。

パターン通常

// パターン間隔0.5倍
this._font.DrawText(null, "パターン間隔 0.5 倍", 20, 320, Color.White);
positions[0] = new Vector2(50.0f, 350.0f);
positions[1] = new Vector2(250.0f, 350.0f);
positions[2] = new Vector2(450.0f, 300.0f);
this._line.PatternScale = 0.5f;
this._line.Draw(positions, Color.LightPink);

 「Line.PatternScale」プロパティを変更すると点描の間隔を変更することが出来ます。1.0 を標準として、1.0 以下を指定すると間隔が短くなり、1.0 以上の場合は間隔が広くなります。

パターン通常

// 「Line.Begin」を使用していないのでコメントアウト
//this._line.End();

 「Line.Begin」を使用している場合はライン描画後に「Line.End」を使用する必要がありますが、今回は使用していません。


// ラインクラスの解放
this.SafeDispose(this._line);

 Line クラスを使用し終わったら解放します。

その他の関連情報です▼