忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

かんたんXNA その6 3D三角形の表示

このページは古いです
最新版はこちら

ここでは3Dの三角形を表示します。
ここから、物を立体的に表示できるようになります。

物を立体的にウィンドウに表示するためには、
3次元の座標データだけでは足りません。
物はどこからどのように眺めるかによって
見え方が変わる
からです。

そのため、視点、見ている位置、視野などの情報が必要になります。
それらの情報から、3Dの座標データを2Dのウィンドウに表示できるように変換してやります。
この変換に使うのが、行列(マトリックス)です。

マトリックスというのは「データの変換の仕方を表すデータ」のことで、
物理学では例えばアインシュタインの特殊相対性理論の
「光速に近い速度を持った物体は縮み、時間はゆっくり進む」(ローレンツ変換)
というのを数式で表すのに使ったりします。
つまり、日常の、歪んでいないデータをマトリックスにかけて、
縮んだ、時間のゆっくり進むデータに変換しているということです。

XNAをやるのに特殊相対性理論など全く知らなくてかまいませんが、
どちらともデータの変換を行います。
XNAでは物体を縮ませる代わりに、3Dデータを
ウィンドウの2Dデータに変換するのにマトリックスを使います。
(他にも3Dモデルを回転させたり、平行移動させたり、拡大したりするのにも使います)

コードは次のようになります。


   
using Microsoft.Xna.Framework;   
using Microsoft.Xna.Framework.Graphics;
 
   
public class MyGame : Microsoft.Xna.Framework.Game   
{   
    GraphicsDeviceManager graphics;   
    BasicEffect effect;   
   
    VertexPositionColor[] vertices = new VertexPositionColor[3];
    public MyGame()   
    {   
        graphics = new GraphicsDeviceManager(this);
        vertices[0] = new VertexPositionColor(new Vector3(1, 1, 0), Color.Navy);   
        vertices[1] = new VertexPositionColor(new Vector3(0, 0, 0), Color.White);   
        vertices[2] = new VertexPositionColor(new Vector3(-1, 1, 0), Color.Red);   
    }
    protected override void LoadGraphicsContent(bool loadAllContent)   
    {   
        if (loadAllContent)   
        {   
            effect = new BasicEffect(graphics.GraphicsDevice, null);   
            effect.VertexColorEnabled = true;

            effect.View = Matrix.CreateLookAt(   
                new Vector3(0, 0, 3),   //カメラの位置
                new Vector3(0, 0, 0),   //カメラのターゲット
                new Vector3(0, 1, 0)    //カメラの上向きベクトル。(0, -1, 0)にすると画面が上下逆になる   
                );   
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(   
                MathHelper.ToRadians(45),   //視野の角度。ここでは45度
                Window.ClientBounds.Width / (float)Window.ClientBounds.Height,//画面のアスペクト比(横 / 縦)  
                1,  //nearPlaneDistance:カメラからこれより近い物体は画面に映らない   
                100 //farPlaneDistance:カメラからこれより遠い物体は画面に映らない   
                );

        }   
    }
    protected override void Draw(GameTime gameTime)   
    {   
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
        graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(   
            graphics.GraphicsDevice,   
            VertexPositionColor.VertexElements   
            );
        effect.Begin();
        foreach (EffectPass pass in effect.CurrentTechnique.Passes)   
        {   
            pass.Begin();
            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(   
                PrimitiveType.TriangleList,   
                vertices,   
                0,  //vertexOffset   
                1   //primitiveCount   
                );
            pass.End();   
        }
        effect.End();   
    }   
}



xnaSimplestTriangle3D.JPG

ここでやっているのは、BasicEffect.ViewプロパティとBasicEffect.Projectionプロパティの設定です。
このそれぞれに、3Dデータから2Dスクリーンデータへの変換の仕方を指定するのです。
何で2つのプロパティを設定しているのかというと、3Dから2Dへの変換は複雑なので
2回に変換を分けているというだけのことです(ですから原理上は1回にすることも出来ます)

public Matrix View { get; set; }

絶対的な座標データを視点(カメラ)に対する
相対的な座標系に変換するマトリックスを設定または取得します。

public Matrix Projection { get; set; }

「Viewプロパティのマトリックスで変換した3D座標データを
さらに2D画面に映す(プロジェクション)変換」
を表すマトリックスを設定または取得します。

ここにセットするマトリックスによって、
遠近法の効果がある映し方にしたり、
あるいはどんなに遠くになっても物が小さくならない映し方(図面を描くときにいいでしょう)
にすることにすることも出来ます。
ゲームを作るなら遠近法があったほうがいいですね。


さて、この変換を表すマトリックスを作るのには、別に難しい知識は必要なくて、
ただ単にMatrixクラスのクリエーション・メソッドを呼び出すだけでかまいません。
ここではMatrix.CreateLookAtメソッドと
Matrix.CreatePerspectiveFieldOfView(遠近法になります)メソッドを使って生成しています。
この2つに視点の位置や視野の広さなどを引数にしてマトリックスをつくり、
3Dデータを2Dに変換します。(実際に変換しているのはBasicEffectの内部ですが)

詳しく見ていきましょう。

public static Matrix CreateLookAt (
         Vector3 cameraPosition,
         Vector3 cameraTarget,
         Vector3 cameraUpVector
)


CreateLookAtメソッドは、最初の座標データをカメラに対する相対的な座標系に変換するマトリックスを作り出します。

cameraPosition視点(カメラ)の位置です。これを変えると物体を違う方向から眺めることが出来ます。
xnaSimplestTriangle3DWithCameraMoved.JPG※cameraPositionが(2, 0, 3)のとき

cameraTargetカメラのターゲットの位置です。ここを見ます。

cameraUpVectorカメラの上方向のベクトルです。
普通は(0, 1, 0)です(y軸方向が上)が、
これを逆さま(0, -1, 0)にすると、画面も逆さまになります。
xnaSimplestTriangleWithCameraUpDirectionInverted.JPG
もちろんこれを横(1, 0, 0)にすると、画面も横に傾きます。
xnaSimplestTriangleWithCameraUpDirectionX.JPG



次はMatrix.CreatePerspectiveFieldOfViewメソッドです。

public static Matrix CreatePerspectiveFieldOfView (
         float fieldOfView,
         float aspectRatio,
         float nearPlaneDistance,
         float farPlaneDistance
)

(MSDNより)

fieldOfView視野の角度です。人間が両目で見えるのは140°位
(実際はもっと広いのですが、目の端ではたいしたことはわかりません)
と言われていますが、そんなに広くしない方がいいでしょう。
広くすると迫力が出る一方、画面が歪んで3D酔いしやすくなるという意見があるからです。
このサンプルでは45°にしています。

なお、これは360が一回転の「度(°)」ではなくて
(6.28...)が一回転の「ラジアン」という単位を使います。
「ラジアンなんて使いたくない!」という方は
度→ラジアンへの変換を行うMathHelper.ToRadiansメソッドがありますので御安心を。

aspectRatioは表示する画面の四角形の形を表します。
具体的には
画面の横幅 / 縦幅
です。

nearPlaneDistancefarPlaneDistanceは一緒に解説した方がいいでしょう。
これらは、3Dモデルが表示されるカメラからの距離の範囲を表します。
逆に言うと、この2つにはさまれた領域の外では、物体は表示されません。
カメラに近すぎると表示されませんし、遠すぎても表示されなくなります。
この2つの引数は、その距離を表します。
このサンプルでは1と100に設定しています。
つまり、カメラとの距離が1以下のものは表示されず
100以上のものも表示されないということです。

 

拍手[0回]

PR