モデルの拡大縮小
今回はモデルを各XZ方向に拡大してみたいと思います。これを使えば爆発などのエフェクトシーンなどに柔軟に対応することができます。
キーボードの「↑↓←→」で XZ 方向にそれぞれモデルが拡大縮小します。

下のリンクから今回のプロジェクトをダウンロードできます。
今回のメインコードファイルを載せます。重要なコードを赤色で表示させています。
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 Vector3 _scale = new Vector3(1.0f, 1.0f, 1.0f);
/// <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.LoadXFileMesh("Deruderu.x");
}
catch (DirectXException ex)
{
MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
this.CreateXYZLine();
this.SettingLight();
// カメラ空間にトランスフォームされた後で頂点法線の正規化
this._device.RenderState.NormalizeNormals = true;
return true;
}
/// <summary>
///
/// </summary>
public void MainLoop()
{
this.SettingCamera();
// キー操作で拡大縮小パラメータを変化
if (this._keys[(int)Keys.Left])
{
this._scale.X /= 1.01f;
}
if (this._keys[(int)Keys.Right])
{
this._scale.X *= 1.01f;
}
if (this._keys[(int)Keys.Down])
{
this._scale.Z /= 1.01f;
}
if (this._keys[(int)Keys.Up])
{
this._scale.Z *= 1.01f;
}
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;
// 拡大縮小のための座標変換
this._device.SetTransform(TransformType.World, Matrix.Scaling(this._scale));
// メッシュの描画
this.RenderMesh();
this._font.DrawText(null, "[←→]±X [↑↓]±Z", 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, "X :" + this._scale.X, 0, 36, Color.White);
this._font.DrawText(null, "Y :" + this._scale.Y, 0, 48, Color.White);
this._font.DrawText(null, "Z :" + this._scale.Z, 0, 60, Color.White);
this._device.EndScene();
this._device.Present();
}
/// <summary>
///
/// </summary>
public void Dispose()
{
this.DisposeMesh();
this.DisposeXYZLine();
if (this._font != null)
{
this._font.Dispose();
}
if (this._device != null)
{
this._device.Dispose();
}
}
}
}
|
では、赤文字の部分を説明していきます。MainSamplePartial.cs ファイルのコードはこちらです。
/// <summary>
///
/// </summary>
private Vector3 _scale = new Vector3(1.0f, 1.0f, 1.0f);
|
モデルを各XYZ方向に拡大するため「Vector3」のパラメータを用意します。拡大縮小の値は原型の「倍率」なので各値を「1.0」で初期化します。あやまって「Vector3.Empty」なんかを指定してしまうとモデルが表示されなくなってしまうので注意してください。
this._device.RenderState.NormalizeNormals = true;
|
モデルを拡大すると法線の計算が変わってしまうので、座標変換した後に法線を正規化するように指定します。
if (this._keys[(int)Keys.Left])
{
this._scale.X /= 1.01f;
}
if (this._keys[(int)Keys.Right])
{
this._scale.X *= 1.01f;
}
if (this._keys[(int)Keys.Down])
{
this._scale.Z /= 1.01f;
}
if (this._keys[(int)Keys.Up])
{
this._scale.Z *= 1.01f;
}
|
モデルの拡大縮小が自然に見えるように、元の値に「1.01」をかけたり割ったりしています。もちろん値は適当でかまいません(拡大縮小のスピードにもなります)。
さらにこうすることによって、モデルの拡大率がマイナスになったりすることを極力防ぐことができます。
this._device.RenderState.Lighting = true;
this._device.SetTransform(TransformType.World, Matrix.Scaling(this._scale));
this.RenderMesh();
|
今回拡大縮小に使用するメソッドはずばりそのまま「Matrix.Scaling」です。値をセットした「Vector3」を渡せばそのとおりに拡大縮小してくれます。
他は前と一緒なので説明はこれだけです。計算方法など詳しい説明を見たい方はこの続きを読んでください。
「Matrix.Scaling」メソッドは、渡された値を下のようなマトリックスに変換しています。

ではポリゴンを使って説明します。下の図はY軸方向(真上)から見た図だと思ってください。

今回はポリゴンの倍率を(1.5, 1.0, 2.0)とします。
まず最初に0番の頂点を計算して見ます。頂点の位置ベクトルは4次元ベクトルに変換します。

残りの頂点は下のような結果になります。
- 0番目 : (-1.5, 0, 2)
- 1番目 : (3, 0, 2)
- 2番目 : (-1.5, 0, -2)
- 3番目 : (3, 0, -2)
下が図で表した結果です。

|