チューブを生成して光源で照らす

チューブを生成して、光源で照らしながら描画します。

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

プログラムの説明

  1. プログラムでチューブ状の頂点座標を生成して、光源で照らしながら描画します。
    光源で照らして描画するときには、法線ベクトルを設定しなければなりません。
    法線ベクトルとは、光が最も強く反射する方向で通常は面と直角の方向です。
  2. Game1.cs を編集して、次の領域を宣言して下さい。
    pointList[] が頂点座標の配列で、今回はインデックスを使わずに描画します。
    points がチューブの角数で、20以上にするとほぼ円柱になります。
    modelXRotation と modelYRotation はモデルの回転係数を格納する領域です。
    XとYの周期を変えて回転しながら描画します。
    他の領域の説明は ポイントプリミティブの描画 を参照して下さい。
        BasicEffect             basicEffect;        // 基本エフェクト
        VertexBuffer            vertexBuffer;       // 頂点バッファ
        VertexDeclaration       vertexDeclaration;  // 頂点データの形式
        VertexPositionNormalTexture[] pointList;    // 頂点データの配列
        int                     points = 10;        // 頂点の個数
        float                   modelXRotation = 0.0f; // 回転係数
        float                   modelYRotation = 0.0f; // 回転係数
        
  3. LoadContent() で描画の準備を整えます。
    basicEffect を生成して LightingEnabled を true に設定します。
    basicEffect.EnableDefaultLighting() でデフォルトのライトに設定します。
    スペキュラーと2番目と3番目のライトを無効にします。
    DiffuseColor で物質の基本色を設定します。
    basicEffect.View に View 座標を設定します。
    basicEffect.Projection に Projection を設定します。
    InitializeTube() メソッドでチューブ状のモデルを生成します。
        protected override void LoadContent()
        {
            // エフェクトを作成
            basicEffect = new BasicEffect(GraphicsDevice, null);
    
            // エフェクトでライトを有効にする
            basicEffect.LightingEnabled = true;
    
            // デフォルトのライトの設定を使用する
            basicEffect.EnableDefaultLighting();
    
            // スペキュラーを無効
            basicEffect.SpecularColor = Vector3.Zero;
    
            // 2番目と3番目のライトを無効
            basicEffect.DirectionalLight1.Enabled = false;
            basicEffect.DirectionalLight2.Enabled = false;
    
            // 物質の基本色を設定
            basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 0.0f); 
     
            // ビューマトリックスをあらかじめ設定 
            basicEffect.View = Matrix.CreateLookAt(
                    new Vector3(0.0f, 5.0f, 10.0f), Vector3.Zero, Vector3.Up);
    
            // プロジェクションマトリックスをあらかじめ設定
            basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),
                    (float)GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height,
                    1.0f, 100.0f);
            InitializeTube(); 
        }
        
  4. チューブ状のモデルを生成する InitializeTube() メソッドです。
    vertexDeclaration に頂点データの形式(VertexPositionNormalTexture)を設定します。
    points*2 個の pointList を生成してチューブ状の頂点座標を設定します。
    今回は Texture は使いませんが、一応座標だけは設定しています。
    vertexBuffer を生成して pointList[] に設定された頂点データを書き込みます。
        private void InitializeTube()
        {
            // 頂点定義データを作成
            vertexDeclaration = new VertexDeclaration(
                GraphicsDevice, VertexPositionNormalTexture.VertexElements);
            pointList = new VertexPositionNormalTexture[points*2]; 
    
            for (int i= 0; i<points; i++) 
            {
                float theta = MathHelper.TwoPi*i / (points-1); 
                pointList[2*i+0] = new VertexPositionNormalTexture( 
                    new Vector3(
                        (float)Math.Sin(theta), -1.0f, (float)Math.Cos(theta)), 
                    new Vector3(
                        (float)Math.Sin(theta), 0.0f, (float)Math.Cos(theta)),
                    new Vector2((float)i/(points-1), 1.0f )); 
                pointList[2*i+1] = new VertexPositionNormalTexture( 
                    new Vector3(
                        (float)Math.Sin(theta), 1.0f, (float)Math.Cos(theta)), 
                    new Vector3(
                        (float)Math.Sin(theta), 0.0f, (float)Math.Cos(theta)),
                    new Vector2((float)i/(points-1), 0.0f )); 
            } 
    
            // 頂点バッファを初期化し、各頂点についてメモリを割り当てます。 
            vertexBuffer = new VertexBuffer(graphics.GraphicsDevice,
                VertexPositionNormalTexture.SizeInBytes * (pointList.Length),
                BufferUsage.None); 
    
            // 頂点の配列に頂点バッファのデータを設定します。 
            vertexBuffer.SetData<VertexPositionNormalTexture>( pointList ); 
        }
        
  5. Update() メソッドで、modelXRotation と modelYRotation の周期を変えて回転します。
    回転速度は MathHelper.ToRadians() の 0.05f と 0.045f で調整して下さい。
        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();
    
            // TODO: ここに更新処理を記述してください
            // Timer で回転係数を設定
            modelXRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.05f);
            modelYRotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.045f);
    
            base.Update( gameTime );    // GameComponent を更新する
        }
        
  6. Draw() メソッドで TriangleList を使ってチューブを描画します。
    GraphicsDevice.VertexDeclaration に頂点データの形式を設定します。
    GraphicsDevice.Vertices[0].SetSource() で vertexBuffer を設定します。
    CullMode を CullMode.None に設定してポリゴンの両面を描画しています。
    カリングと座標系の説明は 前田稔の超初心者のプログラム入門 から DirectX9 講座を参照して下さい。
    Matrix.CreateRotationX(modelXRotation) * Matrix.CreateRotationY(modelYRotation) で座標を回転しながら描画します。
    GraphicsDevice.DrawPrimitives() でチューブを描画します。
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            // 描画する頂点データの定義を設定
            GraphicsDevice.VertexDeclaration = vertexDeclaration;
    
            // 頂点バッファをセットします
            GraphicsDevice.Vertices[0].SetSource( vertexBuffer, 0,
                  VertexPositionNormalTexture.SizeInBytes );
    
            // カリングをしない(両面を描画)
            GraphicsDevice.RenderState.CullMode = CullMode.None;
    
            // エフェクトの使用を開始します
            basicEffect.World = 
                Matrix.CreateRotationX(modelXRotation) * Matrix.CreateRotationY(modelYRotation);
            basicEffect.Begin();
    
            // パスの数だけ繰り替えし描画
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                // パスの開始
                pass.Begin();
    
                // ポリゴン描画する
                GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2*points-2);
    
                // パスの終了
                pass.End();
            }
    
            // エフェクトの使用を終了する
            basicEffect.End();
    
            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
        

【演習】

  1. チューブの色を変えて描画して下さい。
  2. チューブの角数を変えて描画して下さい。
  3. カリングを変更して描画して下さい。

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

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