立方体に色を設定して描画

立方体の各面に異なる色を設定して回転しながら描画します。

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

プログラムの説明

  1. Triangle(三角形)を組み合わせて立方体を定義します。
    vertex(頂点座標の定義)には三次元座標だけで無く、色や法線ベクトルやテクスチャ座標を含めることが出来ます。
    今回は立方体の各面に異なる色を設定して回転しながら描画してみましょう。
  2. Game1.cs を編集して、次の領域を宣言して下さい。
    worldMatrix はワールド座標を設定する領域で、今回はY軸を中心に回転しながら描画します。
    Vertices[] は三次元座標と色を定義する配列です。
    modelRotation はモデルの回転係数を格納する領域です。
    他の領域の説明は「ポイントプリミティブの描画」を参照して下さい。
        GraphicsDeviceManager   graphics;
    
        BasicEffect             basicEffect;            // 基本エフェクト
        Matrix                  worldMatrix;            // ワールド座標
        Matrix                  viewMatrix;             // ビュー座標
        Matrix                  projectionMatrix;       // プロジェクション
        VertexDeclaration       vertexDeclaration;      // 頂点データの形式
        VertexPositionColor[]   Vertices;               // 頂点の定義
        VertexBuffer            vertexBuffer;           // 頂点バッファ
        float                   modelRotation = 0.0f;   // 回転係数
        
  3. LoadContent() から初期化を行うメソッドを呼び出します。
        protected override void LoadContent( ) 
        { 
            InitializeTransform(); 
            InitializeEffect(); 
            InitializeCube(); 
        } 
        
  4. InitializeTransform() で viewMatrix と projectionMatrix を設定します。
        private void InitializeTransform() 
        {
            viewMatrix = Matrix.CreateLookAt(new Vector3(0, 3, 10), Vector3.Zero, Vector3.Up);
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),  // 45 度 
                (float)graphics.GraphicsDevice.Viewport.Width /
                (float)graphics.GraphicsDevice.Viewport.Height,
                1.0f, 100.0f);
        } 
        
  5. InitializeEffect() でエフェクトを作成します。
    エフェクトで頂点カラーを有効に設定して下さい。
    モデルを回転しながら描画するので、World, View, Projection は Draw() メソッドで設定しています。
        private void InitializeEffect() 
        { 
            // 頂点定義データを作成
            vertexDeclaration = new VertexDeclaration(
                GraphicsDevice, VertexPositionColor.VertexElements);
            // エフェクトを作成
            basicEffect = new BasicEffect(GraphicsDevice, null);
            // エフェクトで頂点カラーを有効にする
            basicEffect.VertexColorEnabled = true;
        } 
        
  6. 最も面倒な頂点座標と面の色を定義する InitializeCube() メソッドです。
    立方体の各面は三角形を二個組み合わせた TriangleList を使っています。
    TriangleStrip を使った方が行数が少なくて済むのですが、あえて TriangleList を使ってみました。 (^_^;)
    「6面×6頂点=36個」の頂点データを確保して、反時計周りに立方体を定義します。
    Draw() メソッドで裏ポリゴンを描画するようにカリングを設定して下さい。
    Vertices[] の定義が終わると、頂点バッファを作成して頂点データをバッファに書き込みます。
        private void InitializeCube()
        {
            Vertices = new VertexPositionColor[36]; 
            // 正面 
            Vertices[0] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 1.0f), Color.Red);
            Vertices[1] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 1.0f), Color.Red);
            Vertices[2] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 1.0f), Color.Red);
            Vertices[3] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 1.0f), Color.Red);
            Vertices[4] = new VertexPositionColor(new Vector3(1.0f, -1.0f, 1.0f), Color.Red);
            Vertices[5] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 1.0f), Color.Red); 
    
            // 背面 
            Vertices[6] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, -1.0f), Color.Blue);
            Vertices[7] = new VertexPositionColor(new Vector3(1.0f, 1.0f, -1.0f), Color.Blue);
            Vertices[8] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, -1.0f), Color.Blue);
            Vertices[9] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, -1.0f), Color.Blue);
            Vertices[10] = new VertexPositionColor(new Vector3(1.0f, 1.0f, -1.0f), Color.Blue);
            Vertices[11] = new VertexPositionColor(new Vector3(1.0f, -1.0f, -1.0f), Color.Blue); 
     
            // 上面 
            Vertices[12] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 1.0f), Color.White);
            Vertices[13] = new VertexPositionColor(new Vector3(1.0f, 1.0f, -1.0f), Color.White);
            Vertices[14] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, -1.0f), Color.White);
            Vertices[15] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 1.0f), Color.White);
            Vertices[16] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 1.0f), Color.White);
            Vertices[17] = new VertexPositionColor(new Vector3(1.0f, 1.0f, -1.0f), Color.White); 
     
            // 底面  
            Vertices[18] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 1.0f), Color.Yellow);
            Vertices[19] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, -1.0f), Color.Yellow);
            Vertices[20] = new VertexPositionColor(new Vector3(1.0f, -1.0f, -1.0f), Color.Yellow);
            Vertices[21] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 1.0f), Color.Yellow);
            Vertices[22] = new VertexPositionColor(new Vector3(1.0f, -1.0f, -1.0f), Color.Yellow);
            Vertices[23] = new VertexPositionColor(new Vector3(1.0f, -1.0f, 1.0f), Color.Yellow); 
      
            // 左面 
            Vertices[24] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 1.0f), Color.Green);
            Vertices[25] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, -1.0f), Color.Green);
            Vertices[26] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 1.0f), Color.Green);
            Vertices[27] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, -1.0f), Color.Green);
            Vertices[28] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, -1.0f), Color.Green);
            Vertices[29] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 1.0f), Color.Green); 
    
            // 右面  
            Vertices[30] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 1.0f), Color.Cyan);
            Vertices[31] = new VertexPositionColor(new Vector3(1.0f, -1.0f, 1.0f), Color.Cyan);
            Vertices[32] = new VertexPositionColor(new Vector3(1.0f, -1.0f, -1.0f), Color.Cyan);
            Vertices[33] = new VertexPositionColor(new Vector3(1.0f, 1.0f, -1.0f), Color.Cyan);
            Vertices[34] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 1.0f), Color.Cyan);
            Vertices[35] = new VertexPositionColor(new Vector3(1.0f, -1.0f, -1.0f), Color.Cyan); 
    
            // 頂点バッファ作成
            vertexBuffer = new VertexBuffer(GraphicsDevice,
                VertexPositionColor.SizeInBytes * 36, BufferUsage.None);
            // 頂点データを頂点バッファに書き込む
            vertexBuffer.SetData<VertexPositionColor>(Vertices);
        } 
        
  7. Update() メソッドで、modelRotation に回転係数を設定します。
    回転速度は MathHelper.ToRadians(0.05f) で調整して下さい。
        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();
    
            // Timer で回転係数を設定
            modelRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.05f);
    
            base.Update( gameTime );    // GameComponent を更新する
        }
        
  8. Draw() メソッドで、TriangleList を使って立方体を描画します。
    graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace はポリゴンの裏側を描画する設定です。
    この行をコメントアウトするとポリゴンの表側が描画される?ので試して下さい。 (^_^;)
    GraphicsDevice.VertexDeclaration に頂点データの形式を設定します。
    GraphicsDevice.Vertices[0].SetSource() で vertexBuffer を設定します。
    Matrix.CreateRotationY() でY軸を基点にして回転しながら描画します。
    GraphicsDevice.DrawPrimitives() で TriangleList で立方体(12個の三角形で構成)を描画します。
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            // 裏ポリゴンを描画
            graphics.GraphicsDevice.RenderState.CullMode = 
                CullMode.CullClockwiseFace; 
    
            // 描画する頂点データの定義を設定
            GraphicsDevice.VertexDeclaration = vertexDeclaration;
    
            // 頂点バッファをセットします
            GraphicsDevice.Vertices[0].SetSource( vertexBuffer, 0,
                VertexPositionColor.SizeInBytes );
    
            // エフェクトの使用を開始します
            basicEffect.Begin();
            worldMatrix = Matrix.CreateRotationY(modelRotation);
            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix; 
    
            // パスの数だけ繰り替えし描画
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                // パスの開始
                pass.Begin();
    
                // ポリゴン描画する
                GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
    
                // パスの終了
                pass.End();
            }
    
            // エフェクトの使用を終了する
            basicEffect.End();
    
            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
        

【演習】

  1. 立方体の面の色を変えて描画して下さい。
  2. TriangleStrip を使って同じように描画して下さい。

【NOTE】

カメラをまわしてポリゴンを裏側から描画して見ると解りますが、ポリゴンが描画されません。
これは不要な処理を省くために「ポリゴンの裏側を描画しない」ようにカリングモードが設定されているからです。
カリングモードの設定は、次のとおりで規定値は「反時計回りをカリング」に設定されています。
反時計回りをカリング GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
時計回りをカリング GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace;
カリングなし GraphicsDevice.RenderState.CullMode = CullMode.None;

詳しい説明は Windows Guid を参照して下さい。

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

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