ポリゴンの描画

XNA の Direct3D でトライアングルを使ってポリゴンを描画します。

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

プログラムの説明

  1. XNA では三次元座標を定義して、ポイントやラインやポリゴンを描画することが出来ます。
    今回は TriangleList と TriangleFan を使ってポリゴンを描画します。
    DirectX ではポリゴンの描画は Triangle で行います。
    三次元空間で三角形ポリゴンは平面状に描画出来るのに対して、四角形以上のポリゴンは曲面計算が必要で 処理に時間がかかるからです。
    座標を設定する基本的なプログラムは ポイントプリミティブの描画 を参照して下さい。
  2. Game1.cs を編集して、次の領域を宣言して下さい。
    PrimitiveType はプリミティブのタイプで、キーの操作で切り替えます。
    triangleListIndexBuffer は TriangleList で描画するために頂点データの並びを設定する領域です。
    triangleFanIndexBuffer は TriangleFan で描画するために頂点データの並びを設定する領域です。
    他の領域の説明は「ポイントプリミティブの描画」を参照して下さい。
        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 triangleListIndexBuffer; 
        IndexBuffer triangleFanIndexBuffer; 
        
  3. LoadContent() から初期化を行うメソッドを呼び出します。
        protected override void LoadContent() 
        { 
            InitializeTransform(); 
            InitializeEffect(); 
            InitializePointList(); 
            InitializeTriangleList(); 
            InitializeTriangleFan(); 
        } 
        
  4. InitializeTriangleList() メソッドでは TriangleList で描画する座標のインデックス番号を設定します。
    pointList[] に設定された多角形の頂点座標を、三角形ポリゴンを組み合わせて多角形が描けるように設定します。
    三角形ポリゴンの説明は 前田稔の超初心者のプログラム入門 から DirectX9 講座を参照して下さい。
    triangleListIndices[] が設定できたら、vertexBuffer に格納します。
        private void InitializeTriangleList() 
        { 
            // short 型のインデックスの配列を初期化します。 
            short[] triangleListIndices = new short[points * 3]; 
            // 配列に、頂点バッファ内のインデックスへの参照を入力します。 
            for (int i = 0; i < points; i++) 
            { 
                triangleListIndices[i * 3] = 0; 
                triangleListIndices[(i * 3) + 1] = (short)(i + 1); 
                triangleListIndices[(i * 3) +2] = (short)(i +2); 
            } 
     
            triangleListIndices[(points * 3) - 1] = 1; 
            // インデックス バッファを初期化し、各インデックスについてメモリを割り当てます。 
            triangleListIndexBuffer = new IndexBuffer( 
                graphics.GraphicsDevice, 
                sizeof( short ) * triangleListIndices.Length,
                BufferUsage.None, 
                IndexElementSize.SixteenBits ); 
     
            // インデックス バッファのデータを配列に設定します。 
            triangleListIndexBuffer.SetData<short>( triangleListIndices ); 
        } 
        
  5. InitializeTriangleFan() メソッドでは TriangleFan で描画する座標のインデックス番号を設定します。
    TriangleList では三角形ポリゴン毎に座標を設定しましたが、TriangleFan では多角形の中心を基点にして、 扇型が広がるように各頂点座標を順番に並べます。
    triangleFanIndices[] が設定できたら、vertexBuffer に格納します。
        // TriangleFan で描画する座標のインデックスを設定する
        private void InitializeTriangleFan() 
        { 
            // short 型のインデックスの配列を初期化します。 
            short[] triangleFanIndices = new short[points + 2]; 
     
            // 配列に、頂点バッファ内のインデックスへの参照を入力します。 
            for (int i = 0; i < points + 1; i++) 
            { 
                triangleFanIndices[i] = (short)i; 
            } 
     
            triangleFanIndices[points + 1] = 1; 
     
            // インデックス バッファを初期化し、各インデックスについてメモリを割り当てます。 
            triangleFanIndexBuffer = new IndexBuffer( 
                graphics.GraphicsDevice, 
                sizeof( short ) * triangleFanIndices.Length, // インデックス バッファのサイズ (バイト単位) 
                BufferUsage.None,
                IndexElementSize.SixteenBits ); 
    
            // インデックス バッファのデータを配列に設定します。 
            triangleFanIndexBuffer.SetData<short>( triangleFanIndices ); 
        } 
        
  6. Update() メソッドで、キーダウンを検出して PointList と TriangleList と TriangleFan を切り替えます。
        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.TriangleList;
            else if (newState.IsKeyDown( Keys.NumPad2 ))    typeToDraw = PrimitiveType.TriangleFan;
            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.TriangleList: 
                        DrawTriangleList(); 
                        break; 
                    case PrimitiveType.TriangleFan: 
                        DrawTriangleFan(); 
                        break; 
                } 
                pass.End(); 
            } 
            basicEffect.End(); 
     
            base.Draw( gameTime ); 
        } 
        
  8. DrawTriangleList() メソッドでは DrawIndexedPrimitives() で TriangleList を描画します。
        private void DrawTriangleList() 
        { 
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, 
                VertexPositionNormalTexture.SizeInBytes ); 
     
            graphics.GraphicsDevice.Indices = triangleListIndexBuffer; 
     
            graphics.GraphicsDevice.DrawIndexedPrimitives( 
                PrimitiveType.TriangleList, 
                0,   // インデックス バッファの各要素に加算する頂点バッファ オフセット 
                0,   // 頂点インデックスの最小値 
                9,   // 頂点の数 
                0,   // 最初に読み取るインデックス要素 
                8   // 描画するプリミティブの数 
            ); 
            base.Window.Title = "DrawTriangleList";
        } 
        
  9. DrawTriangleFan() メソッドでは DrawIndexedPrimitives() で TriangleFan を描画します。
        private void DrawTriangleFan() 
        { 
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, 
                VertexPositionNormalTexture.SizeInBytes ); 
     
            graphics.GraphicsDevice.Indices = triangleFanIndexBuffer; 
     
            graphics.GraphicsDevice.DrawIndexedPrimitives( 
                PrimitiveType.TriangleFan, 
                0,   // インデックス バッファの各要素に加算する頂点バッファ オフセット 
                0,   // 頂点インデックスの最小値 
                9,   // 頂点の数 
                0,   // 最初に読み取るインデックス要素 
                8   // 描画するプリミティブの数 
            ); 
            base.Window.Title = "DrawTriangleFan";
        } 
        
  10. 座標を設定する基本的なプログラムは ポイントプリミティブの描画 を参照して下さい。
    NumPad0 キーで PointList で描画します。
    NumPad1 キーで TriangleList で描画します。
    NumPad2 キーで TriangleFan で描画します。
    TriangleList と TriangleFan は同じように描画されますが、タイトルバーにタイプを表示しているので確認して下さい。

【演習】

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

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

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