立方体を回転しながら描画

立方体を回転しながら描画する

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

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

プロジェクトの説明

  1. DirectX Sample Browser で EmptyProject10 のプロジェクトを作成して下さい。
    EmptyProject10 のプロジェクトをコンパイルして、空のウインドウが表示される事を確かめて下さい。
    エラーが発生するときや、正常に実行出来ないときは、残念ながら現在の構成は相性が悪いようです。
  2. EmptyProject10.cpp を修正して立方体の各面に色を設定して回転しながら描画します。
    VER_N は頂点フォーマットを定義する配列 vertices[] の大きさです。
    IDX_N は頂点フォーマットの index を定義する配列 indices[] の大きさです。
    SimpleVertex は頂点フォーマットの形式で、三次元座標と色(RGBA)を定義します。
    vertices[] に座標の中心を 0,0,0 として、立方体の6個の面(矩形)を定義します。
    立方体の各面に異なる色を設定しています。
    「下面 紫」などは、定義するときのメモ書きで、レンダリングの上下関係は D3DXMatrixLookAtLH() で決まります。
    indices[] に vertices[] の頂点番号を設定して、立方体を定義します。
    各面は二個の三角形(TRIANGLELIST)を組み合わせて定義します。
    頂点の順番が変わるとポリゴンが裏向けになって正常に描画されません。
    g_pEffect は Shader の Object で、DirectX10 からは Shader が必須になったようです。 (^_^;)
    次の領域は、Shader にアクセスするためのポインタです。
    g_pLayout は頂点座標の Layout を設定する領域です。
    g_pVertexBuffer は頂点データを格納する VertexBuffer です。
    g_pIndexBuffer は頂点データの Index を格納する VertexBuffer です。
    g_World はワールド座標の変換行列です。
    g_View はビュー座標の変換行列です。
    g_Projection はプロジェクションの変換行列です。
    #include "DXUT.h"
    
    // Vertex(頂点座標) の定義
    #define VER_N   24
    #define IDX_N   36
    
    struct SimpleVertex
    {
        D3DXVECTOR3 Pos;  
        D3DXVECTOR4 Color; 
    };
    SimpleVertex vertices[VER_N] =
    {
        { D3DXVECTOR3( -1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },  //下面 紫
        { D3DXVECTOR3(  1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },
    
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },  //上面 白
        { D3DXVECTOR3(  1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },
    
        { D3DXVECTOR3( -1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },  //左面 黄
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },
    
        { D3DXVECTOR3( -1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },  //前面 赤
        { D3DXVECTOR3(  1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },
    
        { D3DXVECTOR3(  1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },  //右面 青
        { D3DXVECTOR3(  1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },
    
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },  //奥面 緑
        { D3DXVECTOR3(  1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },
    
    };
    DWORD indices[IDX_N] =
    {
        3,1,0,
        2,1,3,
    
        23,21,20,
        22,21,23,
    
        11,9,8,
        10,9,11,
    
        18,16,17,
        19,16,18,
    
        14,12,13,
        15,12,14,
    
        6,4,5,
        7,4,6,
    };
    
    ID3D10Effect*               g_pEffect = NULL;
    ID3D10InputLayout*          g_pLayout = NULL;
    ID3D10EffectTechnique*      g_pRender = NULL;
    ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
    ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
    ID3D10Buffer*               g_pVertexBuffer = NULL;
    ID3D10Buffer*               g_pIndexBuffer = NULL;
    D3DXMATRIX                  g_World;
    D3DXMATRIX                  g_View;
    D3DXMATRIX                  g_Projection;
    
  3. DirectX の主要な処理は CALLBACK 関数で行います。
    OnD3D10CreateDevice() はデバイスを生成するときに呼ばれます。
    D3DX10CreateEffectFromFile() で Box.fx を入力して Shader を作成します。
    Shader のプログラムも Main Program と同様にアプリケーションに応じて作成します。
    とは言っても一般的にはサンプルの中から用途に合うものを選んでコピーしてくるだけでしょうか。 (^◇^;)
    Box.fx のソースは、このページの後に掲載します。
    g_pRender, g_pWorldVariable, g_pViewVariable, g_pProjectionVariable を設定します。
    "Render","World","View","Projection" は Box.fx の中で定義されています。
    今回使っている Box.fx は、頂点座標と頂点に設定された色をそのまま描画する Shader です。
    続いて input layout を設定します。
    今回の頂点データは、三次元座標と頂点の色を定義しています。
    vertices[VER_N] で定義した頂点座標を VertexBuffer を取得して格納します。
    indices[IDX_N] で定義した index を VertexBuffer に格納します。
    各面は二個の三角形(TRIANGLELIST)を組み合わせて定義しています。
    &g_World, &g_View, &g_Projection を設定して、描画の準備を整えます。
    Shader の基礎は「超初心者のプログラム入門(DirectX9)」を参照して下さい。
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice,
            const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
    {
        HRESULT hr = S_OK;
    
        // Create the effect
        DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
        #if defined( DEBUG ) || defined( _DEBUG )
        dwShaderFlags |= D3D10_SHADER_DEBUG;
        #endif
        hr = D3DX10CreateEffectFromFile( L"Box.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL );
        if( FAILED( hr ) )
        {
            MessageBox( NULL, L"The FX file cannot be located.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
            return hr;
        }
    
        // Obtain the render
        g_pRender = g_pEffect->GetTechniqueByName( "Render" );
    
        // Obtain the variables
        g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
        g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
        g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();
    
        // Define the input layout
        D3D10_INPUT_ELEMENT_DESC layout[] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },  
            { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 
        };
        UINT numElements = sizeof(layout)/sizeof(layout[0]);
    
        // Create the input layout
        D3D10_PASS_DESC PassDesc;
        g_pRender->GetPassByIndex( 0 )->GetDesc( &PassDesc );
        hr = pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pLayout );
        if( FAILED(hr) )    return hr;
    
        // Set the input layout
        pd3dDevice->IASetInputLayout( g_pLayout );
    
        // Create vertex buffer
        D3D10_BUFFER_DESC bd;
        bd.Usage = D3D10_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( SimpleVertex ) * VER_N;
        bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
        bd.CPUAccessFlags = 0;
        bd.MiscFlags = 0;
        D3D10_SUBRESOURCE_DATA InitData;
        InitData.pSysMem = vertices;
        hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
        if( FAILED(hr) )    return hr;
    
        // Set vertex buffer
        UINT stride = sizeof( SimpleVertex );
        UINT offset = 0;
        pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
    
        // Create index buffer
        bd.Usage = D3D10_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( DWORD ) * IDX_N;        // vertices needed
        bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
        bd.CPUAccessFlags = 0;
        bd.MiscFlags = 0;
        InitData.pSysMem = indices;
        hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
        if( FAILED(hr) )    return hr;
    
        // Set index buffer
        pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
    
        // Set primitive topology
        pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
    
        // Initialize the world matrix
        D3DXMatrixIdentity(&g_World);
    
        // Initialize the view matrix
        D3DXVECTOR3 Eye( 0.0f, -2.0f, -5.0f );
        D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f );
        D3DXVECTOR3 Up( 0.0f, -1.0f, 0.0f );
        D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );
    
        // Initialize the projection matrix
        D3DXMatrixPerspectiveFovLH(&g_Projection, (float)D3DX_PI * 0.5f, 640.0f/480.0f, 0.1f, 100.0f);
    
        return S_OK;
    }
    
  4. OnD3D10FrameRender() は Rendering を行う CALLBACK 関数です。
    fTime の値でY軸を中心に World 座標を回転しながら描画します。
    回転が速い(遅い)ときは 3.0f の値で調整して下さい。
    Shader に g_pWorldVariable, g_pViewVariable, g_pProjectionVariable を設定して描画します。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        // Update our time
        D3DXMatrixRotationY( &g_World, (float)fTime/3.0f );
    
        // Clear render target and the depth stencil 
        float ClearColor[4] = { 0.176f, 0.196f, 0.667f, 0.0f };
        pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), ClearColor );
        pd3dDevice->ClearDepthStencilView( DXUTGetD3D10DepthStencilView(), D3D10_CLEAR_DEPTH, 1.0, 0 );
    
        // Update variables
        g_pWorldVariable->SetMatrix( (float*)&g_World );
        g_pViewVariable->SetMatrix( (float*)&g_View );
        g_pProjectionVariable->SetMatrix( (float*)&g_Projection );
    
        // Renders a triangle
        D3D10_TECHNIQUE_DESC techDesc;
        g_pRender->GetDesc( &techDesc );
        for( UINT p = 0; p < techDesc.Passes; ++p )
        {
            g_pRender->GetPassByIndex( p )->Apply(0);
            pd3dDevice->DrawIndexed( IDX_N, 0, 0 );        // vertices needed
        }
    }
    
  5. OnD3D10DestroyDevice() では取得した Object を開放して下さい。
    void CALLBACK OnD3D10DestroyDevice( void* pUserContext )
    {
        if( g_pVertexBuffer ) g_pVertexBuffer->Release();
        if( g_pIndexBuffer ) g_pIndexBuffer->Release();
        if( g_pLayout ) g_pLayout->Release();
        if( g_pEffect ) g_pEffect->Release();
    }
    
  6. モデルの回転は g_World で計算して g_pWorldVariable-> で Shader の "World" に設定します。
        ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
        D3DXMATRIX                  g_World;
    
        g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
        D3DXMatrixRotationY( &g_World, (float)fTime/10.0f );
        g_pWorldVariable->SetMatrix( (float*)&g_World );
        
  7. Shader のプログラム(Box.fx) です。
    Box.fx は Tutorial04 に格納されていた シェーダーです。
    Vertex Shader では Pos と World を掛け合わせて回転座標を求めます。
    //--------------------------------------------------------------------------------------
    // File: Tutorial04.fx
    //
    // Copyright (c) Microsoft Corporation. All rights reserved.
    //--------------------------------------------------------------------------------------
    
    //--------------------------------------------------------------------------------------
    // Constant Buffer Variables
    //--------------------------------------------------------------------------------------
    matrix World;
    matrix View;
    matrix Projection;
    
    
    //--------------------------------------------------------------------------------------
    struct VS_OUTPUT
    {
        float4 Pos : SV_POSITION;
        float4 Color : COLOR0;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex Shader
    //--------------------------------------------------------------------------------------
    VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
    {
        VS_OUTPUT output = (VS_OUTPUT)0;
        output.Pos = mul( Pos, World );
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Color = Color;
        return output;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Pixel Shader
    //--------------------------------------------------------------------------------------
    float4 PS( VS_OUTPUT input ) : SV_Target
    {
        return input.Color;
    }
    
    
    //--------------------------------------------------------------------------------------
    technique10 Render
    {
        pass P0
        {
            SetVertexShader( CompileShader( vs_4_0, VS() ) );
            SetGeometryShader( NULL );
            SetPixelShader( CompileShader( ps_4_0, PS() ) );
        }
    }
    

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