ラインが引ければ3D表示

ラインさえひければ、3D表示はなんとかできそうなのでチャレンジ。
3Dの機能がないとはいえ「Matrix」や「Vector3」のクラスはちゃんと3D計算できる仕様のままでよかったです。

namespace Line3D
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private Texture2D linePoint;
        private Rectangle lineDrawArea = new Rectangle();
        private Rectangle lineSrcArea = new Rectangle();
        private Vector2 lineCenter = new Vector2(0, 0);
        private SpriteEffects lineSpEffect = new SpriteEffects();

        private float angX = 0.0f;
        private float angZ = 0.0f;
        private ModelPoint[] modelPoint ={
			new ModelPoint( new Vector3(  0.500000f, 1.000000f,-0.500000f)),
			new ModelPoint( new Vector3(  0.500000f, 0.500000f,-1.000000f)),
			new ModelPoint( new Vector3(  1.000000f, 0.500000f,-0.500000f)),
			new ModelPoint( new Vector3(  1.000000f, 0.500000f, 0.500000f)),
			new ModelPoint( new Vector3(  0.500000f, 1.000000f, 0.500000f)),
			new ModelPoint( new Vector3( -0.500000f, 1.000000f,-0.500000f)),
			new ModelPoint( new Vector3( -0.500000f, 0.500000f,-1.000000f)),
			new ModelPoint( new Vector3( -1.000000f, 0.500000f,-0.500000f)),
			new ModelPoint( new Vector3( -0.500000f, 1.000000f, 0.500000f)),
			new ModelPoint( new Vector3(  0.500000f,-0.500000f,-1.000000f)),
			new ModelPoint( new Vector3(  1.000000f,-0.500000f,-0.500000f)),
			new ModelPoint( new Vector3( -0.500000f,-0.500000f,-1.000000f)),
			new ModelPoint( new Vector3(  1.000000f,-0.500000f, 0.500000f)),
			new ModelPoint( new Vector3( -1.000000f, 0.500000f, 0.500000f)),
			new ModelPoint( new Vector3( -1.000000f,-0.500000f,-0.500000f)),
			new ModelPoint( new Vector3( -1.000000f,-0.500000f, 0.500000f)),
			new ModelPoint( new Vector3(  0.500000f, 0.500000f, 1.000000f)),
			new ModelPoint( new Vector3( -0.500000f, 0.500000f, 1.000000f)),
			new ModelPoint( new Vector3(  0.500000f,-0.500000f, 1.000000f)),
			new ModelPoint( new Vector3( -0.500000f,-0.500000f, 1.000000f)),
			new ModelPoint( new Vector3(  0.500000f,-1.000000f,-0.500000f)),
			new ModelPoint( new Vector3(  0.500000f,-1.000000f, 0.500000f)),
			new ModelPoint( new Vector3( -0.500000f,-1.000000f,-0.500000f)),
			new ModelPoint( new Vector3( -0.500000f,-1.000000f, 0.500000f))
        };
        private ModelLine[] modelLine ={
			new ModelLine( 0, 1),new ModelLine( 0, 2),new ModelLine( 0, 4),new ModelLine( 0, 5),
			new ModelLine( 1, 2),new ModelLine( 1, 6),new ModelLine( 1, 9),new ModelLine( 2, 3),
			new ModelLine( 2,10),new ModelLine( 3, 4),new ModelLine( 3,12),new ModelLine( 3,16),
			new ModelLine( 4, 8),new ModelLine( 4,16),new ModelLine( 5, 6),new ModelLine( 5, 7),
			new ModelLine( 5, 8),new ModelLine( 6, 7),new ModelLine( 6,11),new ModelLine( 7,13),
			new ModelLine( 7,14),new ModelLine( 8,13),new ModelLine( 8,17),new ModelLine( 9,10),
			new ModelLine( 9,11),new ModelLine( 9,20),new ModelLine(10,12),new ModelLine(10,20),
			new ModelLine(11,14),new ModelLine(11,22),new ModelLine(12,18),new ModelLine(12,21),
			new ModelLine(13,15),new ModelLine(13,17),new ModelLine(14,15),new ModelLine(14,22),
			new ModelLine(15,19),new ModelLine(15,23),new ModelLine(16,17),new ModelLine(16,18),
			new ModelLine(17,19),new ModelLine(18,21),new ModelLine(18,19),new ModelLine(19,23),
			new ModelLine(20,22),new ModelLine(20,21),new ModelLine(21,23),new ModelLine(22,23)
        };

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 240;
            graphics.PreferredBackBufferHeight = 320;
            // Frame rate is 30 fps by default for Zune.
            TargetElapsedTime = TimeSpan.FromSeconds(1 / 30.0);
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            linePoint = Content.Load<Texture2D>("Point");

            lineSrcArea.X = 0;
            lineSrcArea.Y = 0;
            lineSrcArea.Width = 1;
            lineSrcArea.Height = 1;
            lineDrawArea.Height = 1;
        }

        protected override void Update(GameTime gameTime)
        {
            float cenX, cenY;
            Vector3 tPoint;

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            angX += 0.02f;
            angZ += 0.03f;
            //画面中央を求める
            cenX = graphics.PreferredBackBufferWidth / 2;
            cenY = graphics.PreferredBackBufferHeight / 2;
            //回転させたマトリックを求める
            Matrix tMat = Matrix.CreateRotationX(angX) * Matrix.CreateRotationZ(angZ);
            foreach (ModelPoint poi in modelPoint)
            {
                //座標変換
                tPoint = Vector3.Transform(poi.Point, tMat);
                //適当な透視変換(良い子はまねしないでね)
                tPoint.Z += 4;
                poi.Trans.X = tPoint.X * 256 / tPoint.Z + cenX;
                poi.Trans.Y = tPoint.Y * 256 / tPoint.Z + cenY;
            }
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            Color defColor = Color.White;
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
            foreach (ModelLine lData in modelLine)
                drawLine(modelPoint[lData.Point[0]].Trans, modelPoint[lData.Point[1]].Trans, defColor);
            spriteBatch.End();
            base.Draw(gameTime);
        }

        //-------------------------------------------------------------------------------
        //ラインを引く
        //-------------------------------------------------------------------------------
        private void drawLine(Vector2 iPoint0, Vector2 iPoint1, Color lineColor)
        {
            double r, ra;
            float x, y;

            x = iPoint1.X - iPoint0.X;
            y = iPoint1.Y - iPoint0.Y;
            r = Math.Sqrt(x * x + y * y);
            ra = (x > 0) ? Math.Asin(y / r) : Math.PI - Math.Asin(y / r);
            lineDrawArea.X = (int)iPoint0.X;
            lineDrawArea.Y = (int)iPoint0.Y;
            lineDrawArea.Width = (int)r;
            spriteBatch.Draw(linePoint, lineDrawArea, lineSrcArea, lineColor, (float)ra, lineCenter, lineSpEffect, 0);
        }
    }

    //-------------------------------------------------------------------------------
    //  モデルのPoint構造体
    public class ModelPoint
    {
        public Vector3 Point;   //  座標データ
        public Vector2 Trans;   //  透視変換後の座標
        public ModelPoint(Vector3 iV3)
        {
            Point = iV3;
            Trans = new Vector2(0, 0);
        }
    }

    //-------------------------------------------------------------------------------
    //  モデルのLine構造体
    public class ModelLine
    {
        public int[] Point = { 0, 0 };   //  頂点情報
        public ModelLine(int p0, int p1)
        {
            Point[0] = p0;
            Point[1] = p1;
        }
    }
}

これを実行すると、こんな感じです。

Zuneでも動いたので、ワイヤーフレームの3Dゲームは作れそうな気がしてきました。