トーラスとコーンを親子関係で描画する

DirectX10 でトーラスがY軸で回転し、その回りを逆方向にコーンが回ります。
D3DXMatrixTranslation, D3DXMatrixMultiply などの使い方を説明します。
真っ黒にならないように環境光を設定します。

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

プロジェクトの説明

  1. DirectX Sample Browser で EmptyProject10 のプロジェクトを作成して下さい。
    EmptyProject10 のプロジェクトをコンパイルして、空のウインドウが表示される事を確かめて下さい。
    エラーが発生するときや、正常に実行出来ないときは、残念ながら現在の構成は相性が悪いようです。
    [プロジェクト][既存項目の追加] から \DXUT\Optional の DXUTShapes.h, DXUTShapes.cpp を追加して下さい。
  2. EmptyProject10.cpp を修正してトーラスとコーンを親子関係で回転します。
    g_pMesh1 がトーラスのメッシュで g_pMesh2 がコーンのメッシュです。
    トーラスを黄色で、コーンを赤で描画するために g_pColorVariable と g_Colors[2] を定義します。
    #include "DXUT.h"
    #include "SDKmisc.h"
    #include "DXUTShapes.h"
    
    ID3D10Effect*               g_pEffect = NULL;
    ID3D10InputLayout*          g_pLayout = NULL;
    ID3D10EffectTechnique*      g_pRender = NULL;
    ID3DX10Mesh*                g_pMesh1 = NULL;
    ID3DX10Mesh*                g_pMesh2 = NULL;
    ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
    ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
    ID3D10EffectVectorVariable* g_pColorVariable = NULL;
    D3DXMATRIX                  g_World;
    D3DXMATRIX                  g_View;
    D3DXMATRIX                  g_Projection;
    D3DXVECTOR4 g_Colors[2] = 
    {
        D3DXVECTOR4( 1.0f, 1.0f, 0.2f, 1.0f ),
        D3DXVECTOR4( 1.0f, 0.3f, 0.3f, 1.0f ),
    };
    
  3. D3DX10CreateEffectFromFile() で Model2.fx を入力して Shader を作成します。
    頂点データは、三次元座標と法線ベクトルを定義しています。
    DXUTCreateTorus() などでメッシュを生成すると、この形式になります。
    トーラスとコーンに異なる色を設定するために g_pColorVariable を設定します。
    "Color" は Main.fx の中で定義しなければなりません。
    DXUTCreateTorus() でトーラスのメッシュを生成します。
    DXUTCreateCylinder() でコーンのメッシュを生成します。
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,
                                          void* pUserContext )
    {
        HRESULT hr = S_OK;
    
        DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
        #if defined( DEBUG ) || defined( _DEBUG )
        dwShaderFlags |= D3D10_SHADER_DEBUG;
        #endif
        V_RETURN( D3DX10CreateEffectFromFile( L"Model2.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) );
    
        // Obtain the techniques
        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();
        g_pColorVariable = g_pEffect->GetVariableByName( "Color" )->AsVector();
    
        // Create an input layout
        const D3D10_INPUT_ELEMENT_DESC layout[] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        };
    
        D3D10_PASS_DESC PassDesc;
        g_pRender->GetPassByIndex( 0 )->GetDesc( &PassDesc );
        V_RETURN( pd3dDevice->CreateInputLayout( layout, sizeof(layout)/sizeof(layout[0]), 
                              PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pLayout ) );
        DXUTCreateCylinder( pd3dDevice, 0.6f, 0.0f, 1.2f, 30, 30, &g_pMesh2 );
        DXUTCreateTorus( pd3dDevice, 0.4f, 1.0f, 32, 32, &g_pMesh1 );
    
        // Initialize the world matrices
        D3DXMatrixIdentity( &g_World );
        // Initialize the view matrix
        D3DXVECTOR3 Eye( 0.0f, 1.0f, -8.0f );
        D3DXVECTOR3 At( 0.0f, 0.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.25f, 640.0f/480.0f, 0.1f, 100.0f );
    
        return S_OK;
    }
    
  4. OnD3D10FrameRender() は Rendering を行う CALLBACK 関数です。
    トーラスをY軸で回転しながら描画します。
    次にトーラスの回りをコーンが逆方向に回転しながら描画します。
    トーラスは黄色(g_Colors[0])で、コーンは赤色(g_Colors[1])で描画します。
    コーンの g_World の計算に注目して下さい。
    Y軸で回転した値(matY)と水平方向に移動した値(matX)を掛け合わせます。
    行列演算では matY*matX と matX*matY では結果が異なるので試してみて下さい。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        // Update our time
        D3DXMatrixRotationY( &g_World, (float)fTime/2.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 );
        g_pColorVariable->SetFloatVector( (float*)&g_Colors[0] );
    
        D3D10_TECHNIQUE_DESC techDesc;
        g_pRender->GetDesc( &techDesc );
    
        // Torus を描画
        UINT NumSubsets;
        g_pMesh1->GetAttributeTable( NULL, &NumSubsets );
        pd3dDevice->IASetInputLayout( g_pLayout );
    
        for( UINT p=0; p<techDesc.Passes; p++ )
        {
            g_pRender->GetPassByIndex(p)->Apply(0);
    
            for( UINT s=0; s<NumSubsets; s++ )
            {
                g_pMesh1->DrawSubset(s);
            }
        }
    
        // Cone を描画
        D3DXMATRIX      matX,matY;
        D3DXMatrixRotationY( &matY, 0.0f-(float)fTime/2.0f );
        D3DXMatrixTranslation( &matX,3.0f,0.0f,0.0f );
        D3DXMatrixMultiply( &g_World,&matX,&matY );
        g_pWorldVariable->SetMatrix( (float*)&g_World );
     
        g_pColorVariable->SetFloatVector( (float*)&g_Colors[1] );
        g_pMesh2->GetAttributeTable( NULL, &NumSubsets );
        pd3dDevice->IASetInputLayout( g_pLayout );
    
        for( UINT p=0; p<techDesc.Passes; p++ )
        {
            g_pRender->GetPassByIndex(p)->Apply(0);
    
            for( UINT s=0; s<NumSubsets; s++ )
            {
                g_pMesh2->DrawSubset(s);
            }
        }
    }
    
  5. OnD3D10DestroyDevice() では取得した Object を開放して下さい。
    void CALLBACK OnD3D10DestroyDevice( void* pUserContext )
    {
        if( g_pLayout ) g_pLayout->Release();
        if( g_pEffect ) g_pEffect->Release();
        if( g_pMesh1 ) g_pMesh1->Release();
        if( g_pMesh2 ) g_pMesh2->Release();
    }
    
  6. Color にモデルの色を設定するソースコードです。
    ID3D10EffectVectorVariable* g_pColorVariable = NULL;
    D3DXVECTOR4 g_Colors[2] = 
    {
        D3DXVECTOR4( 1.0f, 1.0f, 0.2f, 1.0f ),
        D3DXVECTOR4( 1.0f, 0.3f, 0.3f, 1.0f ),
    };
    g_pColorVariable = g_pEffect->GetVariableByName( "Color" )->AsVector();
    g_pColorVariable->SetFloatVector( (float*)&g_Colors[0] );
    g_pColorVariable->SetFloatVector( (float*)&g_Colors[1] );
    
  7. 真っ黒にならないように環境光を設定します。
    0.3f が環境光の設定で、ライトが当たらない部分の最低限の明るさです。
    float4 Color;
    float4 PS( PS_INPUT input ) : SV_Target
    {
        return Color * ( saturate(dot(normalize(input.Norm),g_vLightDir)) * 0.7f + 0.3f);
    }
    
  8. Shader のプログラム(Model2.fx) です。
    //--------------------------------------------------------------------------------------
    // File: Main.fx    頂点座標+法線ベクトル+モデルの色 & 光源    前田 稔
    //--------------------------------------------------------------------------------------
    
    //--------------------------------------------------------------------------------------
    // Constant Buffer Variables
    //--------------------------------------------------------------------------------------
    matrix World;
    matrix View;
    matrix Projection;
    float4 Color;
    
    //--------------------------------------------------------------------------------------
    // Global variables
    //--------------------------------------------------------------------------------------
    cbuffer cb0
    {
    //    float3 g_vLightDir = float3(-0.707,0.707,0);    // 光源の座標
        float3 g_vLightDir = float3(-0.707,0.707,-0.5); // 光源の座標
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex shader output structure
    //--------------------------------------------------------------------------------------
    struct VS_INPUT
    {
        float4 Pos : POSITION;
        float3 Norm : NORMAL;
    };
    
    struct PS_INPUT
    {
        float4 Pos : SV_POSITION;
        float3 Norm : NORMAL;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex Shader
    //--------------------------------------------------------------------------------------
    PS_INPUT VS( VS_INPUT input )
    {
        PS_INPUT output = (PS_INPUT)0;
        output.Pos = mul( input.Pos, World );
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Norm = mul( input.Norm, World );
        
        return output;
    }
    
    //--------------------------------------------------------------------------------------
    float4 PS( PS_INPUT input ) : SV_Target
    { 
        //return Color * saturate( dot( normalize(input.Norm), g_vLightDir ) );
        return Color * ( saturate(dot(normalize(input.Norm),g_vLightDir)) * 0.7f + 0.3f);
    }
    
    //--------------------------------------------------------------------------------------
    technique10 Render
    {
        pass P0
        {
            SetVertexShader( CompileShader( vs_4_0, VS() ) );
            SetGeometryShader( NULL );
            SetPixelShader( CompileShader( ps_4_0, PS() ) );
        }
    }
    

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