立方体にテクスチャを貼り付ける

XNA で Shader を使って立方体にテクスチャを貼り付けます。

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

プログラムの説明

  1. プロジェクトは Shader を使って立方体を描画 を元に作成しています。
    説明の足らない部分は「Shader を使って立方体を描画」を参照して下さい。
    プログラムで使用する制御領域を定義します。
        GraphicsDeviceManager graphics; 
    
        VertexDeclaration       cubeVertexDeclaration; 
        VertexPositionColor[]   cubeVertices; 
        VertexBuffer            vertexBuffer; 
        short[]                 cubeIndices; 
        IndexBuffer             indexBuffer;
        Effect                  effect; 
        Matrix                  worldViewProjection; 
        Matrix                  worldMatrix;
        Matrix                  viewMatrix;
        Matrix                  projectionMatrix; 
        float                   modelRotation = 0.0f; 
        
  2. LoadContent() メソッドで、3D描画の初期化を行います。
        protected override void LoadContent() 
        { 
            InitializeTransform(); 
            InitializeEffect(); 
            InitializeCube(); 
        } 
        
  3. 描画環境を設定する InitializeTransform() メソッドです。
        private void InitializeTransform() 
        { 
            viewMatrix = Matrix.CreateLookAt(new Vector3(0, 2, 5), Vector3.Zero, Vector3.Up);
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView( 
                (float)Math.PI / 4.0f,  // 2 π ラジアンは 360 度なので、これは 45 度になります。 
                (float)graphics.GraphicsDevice.Viewport.Width / 
                (float)graphics.GraphicsDevice.Viewport.Height, 
                1.0f, 100.0f ); 
        } 
        
  4. エフェクトを設定する InitializeEffect() メソッドです。
    Content に格納したエフェクト(ReallySimpleTexture.fx)を呼び出します。
    ReallySimpleTexture.fx はテクスチャを貼り付けるエフェクトで、このページの後部に掲載しています。
    テクスチャに使用する画像(xna.png)を入力します。
    テストするときは、256 ピクセル程度の画像を xna.png の名前で Content に格納して下さい。
    "TransformAndTexture" は ReallySimpleTexture.fx の中で定義されている名前です。
        private void InitializeEffect() 
        {
            effect = Content.Load<Effect>("ReallySimpleTexture"); 
            Texture2D texture = Content.Load<Texture2D>( "xna" ); 
            effect.Parameters["UserTexture"].SetValue( texture ); 
            effect.CurrentTechnique = effect.Techniques["TransformAndTexture"]; 
        } 
        
  5. InitializeCube() メソッドで IndexBuffer を使って立方体を定義します。
        public VertexPositionTexture[] InitializeCube() 
        { 
            // VertexPositionTexture タイプの頂点宣言を作成します。 
            cubeVertexDeclaration = new VertexDeclaration( 
            graphics.GraphicsDevice, VertexPositionTexture.VertexElements ); 
     
            // 立方体の各面を描画するためのポイントを初期化します。 
                    :
    
            // テクスチャ座標を初期化します。 
            Vector2 textureTopLeft = new Vector2( 0.0f, 0.0f ); 
            Vector2 textureTopRight = new Vector2( 1.0f, 0.0f ); 
            Vector2 textureBottomLeft = new Vector2( 0.0f, 1.0f ); 
            Vector2 textureBottomRight = new Vector2( 1.0f, 1.0f ); 
    
            // 頂点のリストを保持するための配列を作成します。   
            // この配列は、頂点バッファにデータを割り当てるときに使用します。 
            cubeVertices = new VertexPositionTexture[36]; 
     
            // 立方体の正面の頂点 
                    :
     
            // 立方体の背面の頂点 
                    :
     
            // 立方体の上面の頂点 
                    :
     
            // 立方体の底面の頂点 
                    :
     
            // 立方体の左面の頂点 
                    :
     
            // 頂点データを保持する頂点バッファを作成します。 
            vertexBuffer = new VertexBuffer( graphics.GraphicsDevice, 
                VertexPositionTexture.SizeInBytes * cubeVertices.Length, 
                BufferUsage.None); 
    
            // 頂点バッファにデータを追加します。 
            vertexBuffer.SetData<VertexPositionTexture>( cubeVertices ); 
     
            cubeIndices = new short[]
            {
                // 正面,    背面,    上面,    底面,    左面,    右面 
                    :
            }; 
     
            // インデックス データを保持するためのインデックス バッファを作成します。 
            indexBuffer = new IndexBuffer( graphics.GraphicsDevice, 
                sizeof( short ) * cubeIndices.Length, 
                BufferUsage.None,
                IndexElementSize.SixteenBits ); 
     
            // インデックス バッファにデータを追加します。 
            indexBuffer.SetData<short>( cubeIndices ); 
     
            return cubeVertices; 
        } 
        
  6. Update() ではタイマーを取得して、モデルの回転に使用する係数(modelRotation)を設定します。
        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 ); 
        } 
        
  7. 立方体を描画する Draw() メソッドです。
    Y軸を基点に modelRotation で回転しながら描画します。
        protected override void Draw( GameTime gameTime ) 
        { 
            graphics.GraphicsDevice.Clear( Color.CornflowerBlue ); 
     
            graphics.GraphicsDevice.RenderState.CullMode = 
            CullMode.CullClockwiseFace; 
     
            graphics.GraphicsDevice.VertexDeclaration = cubeVertexDeclaration; 
            graphics.GraphicsDevice.Indices = indexBuffer; 
            graphics.GraphicsDevice.Vertices[0].SetSource( 
                vertexBuffer, 0, VertexPositionTexture.SizeInBytes ); 
     
            // このコードはデバイスの BeginScene-EndScene ブロック内に記述します。 
            effect.Begin(); 
            foreach (EffectPass pass in effect.CurrentTechnique.Passes) 
            { 
                pass.Begin(); 
                worldMatrix = Matrix.CreateRotationY(modelRotation);
                worldViewProjection = worldMatrix * viewMatrix * projectionMatrix; 
                effect.Parameters["WorldViewProj"].SetValue( worldViewProjection ); 
    
                graphics.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType.TriangleList, 
                    0, 0, cubeVertices.Length, 0, 12 ); 
                pass.End(); 
            } 
            effect.End(); 
            base.Draw( gameTime ); 
        } 
        
  8. Content のフォルダーに格納されている ReallySimpleTexture.fx です。
    画像の時と同じようにプロジェクトに加えて下さい。
    シェーダの説明は DirectX のページを参照して下さい。
    uniform extern float4x4 WorldViewProj :WORLDVIEWPROJECTION; 
    uniform extern texture UserTexture; 
     
    struct VS_OUTPUT 
    { 
    float4 position :POSITION; 
    float4 textureCoordinate :TEXCOORD0; 
    }; 
     
    sampler textureSampler = sampler_state 
    { 
    Texture = <UserTexture>; 
    mipfilter = LINEAR;  
    }; 
      
    VS_OUTPUT Transform( 
    float4 Position  :POSITION,  
    float4 TextureCoordinate :TEXCOORD0 ) 
    { 
    VS_OUTPUT Out = (VS_OUTPUT)0; 
     
    Out.position = mul(Position, WorldViewProj); 
    Out.textureCoordinate = TextureCoordinate; 
     
    return Out; 
    } 
     
    float4 ApplyTexture(VS_OUTPUT vsout) :COLOR 
    { 
    return tex2D(textureSampler, vsout.textureCoordinate).rgba; 
    } 
     
    technique TransformAndTexture 
    { 
    pass P0 
        { 
    vertexShader = compile vs_2_0 Transform(); 
    pixelShader  = compile ps_2_0 ApplyTexture(); 
        } 
    } 
    

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

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