ラインプリミティブの描画

XNA の Direct3D でラインプリミティブを使って直線を描画します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. XNA では三次元座標を定義して、ポイントやラインやポリゴンを描画することが出来ます。
    今回は PointList と LineList と LineStrip をキーの操作で切り替えて描画します。
    座標を設定する基本的なプログラムは ポイントプリミティブの描画 を参照して下さい。
  2. Game1.cs を編集して、次の領域を宣言して下さい。
    PrimitiveType はプリミティブのタイプで、キーの操作で切り替えます。
    lineListIndexBuffer は LineList で描画するために頂点データの並びを設定する領域です。
    lineStripIndexBuffer は LineStrip で描画するために頂点データの並びを設定する領域です。
    他の領域の説明は「ポイントプリミティブの描画」を参照して下さい。
        GraphicsDeviceManager graphics; 
    
        Matrix              viewMatrix; 
        Matrix              projectionMatrix; 
        BasicEffect         basicEffect; 
     
        VertexDeclaration   vertexDeclaration; 
        VertexPositionNormalTexture[] pointList; 
        VertexBuffer        vertexBuffer; 
        PrimitiveType       typeToDraw = PrimitiveType.PointList; 
        //int points =        5; 
        int points =        8; 
     
        IndexBuffer         lineListIndexBuffer; 
        IndexBuffer         lineStripIndexBuffer; 
        
  3. LoadContent() から初期化を行うメソッドを呼び出します。
        protected override void LoadContent() 
        { 
            InitializeTransform(); 
            InitializeEffect(); 
            InitializePointList(); 
            InitializeLineList(); 
            InitializeLineStrip(); 
        } 
        
  4. InitializeLineList() メソッドでは LineList で描画する座標のインデックス番号を設定します。
    pointList[] に設定された多角形の頂点座標を、ライン毎に開始点と終了点を設定します。
    lineListIndices[] が設定できたら、vertexBuffer に格納します。
        private void InitializeLineList() 
        { 
            // short 型のインデックスの配列を初期化します。 
            short[] lineListIndices = new short[(points * 2)]; 
     
            // 配列に、頂点バッファ内のインデックスへの参照を入力します。 
            for (int i = 0; i < points; i++) 
            { 
                lineListIndices[i * 2] = (short)(i + 1); 
                lineListIndices[(i * 2) + 1] = (short)(i + 2); 
            } 
     
            lineListIndices[(points * 2) - 1] = 1; 
     
            // インデックス バッファを初期化し、各インデックスについてメモリを割り当てます。 
            lineListIndexBuffer = new IndexBuffer( 
                graphics.GraphicsDevice, 
                sizeof( short ) * lineListIndices.Length,
                BufferUsage.None,
                IndexElementSize.SixteenBits ); 
     
            // インデックス バッファのデータを配列に設定します。 
            lineListIndexBuffer.SetData<short>( lineListIndices );
        } 
        
  5. InitializeLineStrip() メソッドでは LineStrip で描画する座標のインデックス番号を設定します。
    pointList[] に設定された多角形の頂点座標を、描画する順番に並べて行きます。
    LineList ではライン毎に開始と終了を設定しましたが、LineStrip では頂点座標を順番に並べます。
    lineStripIndices[] が設定できたら、vertexBuffer に格納します。
        private void InitializeLineStrip() 
        { 
            // short 型のインデックスの配列を初期化します。 
            short[] lineStripIndices = new short[points + 1]; 
     
            // 配列に、頂点バッファ内のインデックスへの参照を入力します。 
            for (int i = 0; i < points; i++) 
            { 
                lineStripIndices[i] = (short)(i + 1); 
            } 
            lineStripIndices[points] = 1; 
     
            // インデックス バッファを初期化し、各インデックスについてメモリを割り当てます。 
            lineStripIndexBuffer = new IndexBuffer( 
                graphics.GraphicsDevice, 
                sizeof( short ) * lineStripIndices.Length,
                BufferUsage.None, 
                IndexElementSize.SixteenBits ); 
     
            // インデックス バッファのデータを配列に設定します。 
            lineStripIndexBuffer.SetData<short>( lineStripIndices ); 
        } 
        
  6. Update() メソッドで、キーダウンを検出して PointList と LineList と LineStrip を切り替えます。
        protected override void Update( GameTime gameTime ) 
        { 
            // Xbox 360 および Windows でゲームの終了を許可します。 
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                Keyboard.GetState().IsKeyDown(Keys.Escape)) this.Exit();
     
            //CheckInput(); 
            KeyboardState newState = Keyboard.GetState(); 
            if (newState.IsKeyDown( Keys.NumPad0 ))         typeToDraw = PrimitiveType.PointList;
            else if (newState.IsKeyDown( Keys.NumPad1 ))    typeToDraw = PrimitiveType.LineList;
            else if (newState.IsKeyDown( Keys.NumPad2 ))    typeToDraw = PrimitiveType.LineStrip;
            base.Update( gameTime ); 
        } 
        
  7. Draw() メソッドでは、typeToDraw に従ってそれぞれの描画メソッドを呼び出します。
        protected override void Draw( GameTime gameTime ) 
        { 
            graphics.GraphicsDevice.Clear( Color.CornflowerBlue ); 
            graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration; 
     
            basicEffect.Begin(); 
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) 
            { 
                pass.Begin(); 
                switch (typeToDraw) 
                { 
                    case PrimitiveType.PointList: 
                        DrawPoints(); 
                        break; 
                    case PrimitiveType.LineList: 
                        DrawLineList(); 
                        break; 
                    case PrimitiveType.LineStrip: 
                        DrawLineStrip(); 
                        break; 
                } 
                pass.End(); 
            } 
            basicEffect.End(); 
     
            base.Draw( gameTime ); 
        } 
        
  8. DrawPoints() メソッドでは DrawPrimitives() で PointList を描画します。
    頂点座標を参照するときに IndexBuffer を使う方法と使わない方法があります。
    PointList では IndexBuffer を使わずに頂点座標を直接参照して描画します。
        private void DrawPoints() 
        {
            graphics.GraphicsDevice.RenderState.PointSize = 10;
            //graphics.GraphicsDevice.RenderState.PointSize = 4;
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, 
                VertexPositionNormalTexture.SizeInBytes );
    
            graphics.GraphicsDevice.DrawPrimitives(
                PrimitiveType.PointList,
                0,          // 最初に描画する頂点のインデックス 
                points+1);  // プリミティブの数
            base.Window.Title = "DrawPoints";
        } 
        
  9. DrawLineList() メソッドでは DrawPrimitives() で LineList を描画します。
    LineList では lineListIndexBuffer を使って頂点座標を参照しながら描画します。
        private void DrawLineList() 
        { 
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, 
                VertexPositionNormalTexture.SizeInBytes ); 
    
            graphics.GraphicsDevice.Indices = lineListIndexBuffer; 
     
            graphics.GraphicsDevice.DrawIndexedPrimitives( 
                PrimitiveType.LineList, 
                0,          // インデックス バッファの各要素に加算する頂点バッファ オフセット 
                0,          // 頂点インデックスの最小値 
                9,          // 頂点の数 
                0,          // 最初に読み取るインデックス要素 
                points);    // 描画するプリミティブの数 
            base.Window.Title = "DrawLineList";
        } 
        
  10. DrawLineStrip() メソッドでは DrawPrimitives() で LineStrip を描画します。
    LineStrip では lineStripIndexBuffer を使って頂点座標を参照しながら描画します。
        private void DrawLineStrip() 
        { 
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, 
                VertexPositionNormalTexture.SizeInBytes ); 
     
            graphics.GraphicsDevice.Indices = lineStripIndexBuffer; 
     
            graphics.GraphicsDevice.DrawIndexedPrimitives( 
                PrimitiveType.LineStrip, 
                0,          // インデックス バッファの各要素に加算する頂点バッファ オフセット 
                0,          // 頂点インデックスの最小値 
                9,          // 頂点の数 
                0,          // 最初に読み取るインデックス要素 
                points);    // 描画するプリミティブの数 
            base.Window.Title = "DrawLineStrip";
        } 
        
  11. 座標を設定する基本的なプログラムは ポイントプリミティブの描画 を参照して下さい。
    NumPad0 キーで PointList で描画します。
    NumPad1 キーで LineList で描画します。
    NumPad2 キーで LineStrip で描画します。
    LineList と LineStrip は同じように描画されますが、タイトルバーにタイプを表示しているので確認して下さい。

【演習】

  1. 五角形, 六角形, 八角形, 十二角形, 三十六角形を描画して下さい。
  2. 点の色を変えて描画して下さい。
  3. カメラを近づけて(引いて)、大きく(小さく)描画して下さい。

前田稔(Maeda Minoru)の超初心者のプログラム入門

超初心者のプログラム入門(XNA(C#) game program)