ティーポットを回転

ティーポットを回転しながら描画する

DirectX10 でティーポットを回転しながら描画します。
ティーポットは DXUTShapes.h(.cpp) で生成します。

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

プロジェクトの説明

  1. DirectX Sample Browser で EmptyProject10 のプロジェクトを作成して下さい。
    EmptyProject10 のプロジェクトをコンパイルして、空のウインドウが表示される事を確かめて下さい。
    エラーが発生するときや、正常に実行出来ないときは、残念ながら現在の構成は相性が悪いようです。
    ティーポットのモデルは、古くから DirectX に標準で組み込まれています。
    DirectX10 では DXUT のフォルダに格納されている DXUTShapes.h, DXUTShapes.cpp でモデルが定義されています。
    ところが、何故かプロジェクトにこれらのファイルが組み込まれていませんでした。
    プロジェクトに組み込む必要は無い? (^_^;)
    [プロジェクト][既存項目の追加] から \DXUT\Optional の DXUTShapes.h, DXUTShapes.cpp を追加して下さい。
  2. EmptyProject10.cpp を修正してティーポットを回転しながら描画します。
    g_pMesh にはティーポットのメッシュを格納します。
    g_pLayout は頂点座標の Layout を設定する領域です。
    g_pEffect は Shader を設定する領域です。
    Shader の説明は 立方体を光源で照らして描画する を参照して下さい。
    #include "DXUT.h"
    #include "SDKmisc.h"
    #include "DXUTShapes.h"
    
    ID3DX10Mesh*                g_pMesh = NULL;
    ID3D10InputLayout*          g_pLayout = NULL;
    ID3D10Effect*               g_pEffect = NULL;
    ID3D10EffectTechnique*      g_pRender = NULL;
    ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
    
  3. OnD3D10CreateDevice() はデバイスを生成するときに呼ばれます。
    DXUTFindDXSDKMediaFileCch() で "Teapot.fx" が格納されているパスを取得します。
    詳細は DXUT\Optional\ のフォルダーに格納されている SDKmisc.cpp を参照して下さい。
    D3DX10CreateEffectFromFile() で Teapot.fx を入力して Shader を作成します。
    GetTechniqueByName() で g_pRender, g_pProjectionVariable, g_pWorldVariable を設定します。
    "Render", "g_mWorldViewProjection", "g_mWorld" は Shader の中で定義されています。
    今までは World, View, Projection を分けていましたが、今回は WorldViewProjection と World の二個です。
    input layout の設定では、三次元座標と法線ベクトルが定義されています。
    DXUTCreateTeapot() で Teapot のメッシュを生成します。
    Windows のプログラムにも言えることですが、プログラミングの方法は一通りではありません。
    参考にしたテンプレートによって、見かけが変わります。
    要はソースコードや変数名に惑わされずに、その本質を理解することが重要です。
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,
                                          void* pUserContext )
    {
        HRESULT hr = S_OK;
    
        // Find the D3DX effect file
        WCHAR str[MAX_PATH];
        V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Teapot.fx" ) );
        DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
        #if defined( DEBUG ) || defined( _DEBUG )
        dwShaderFlags |= D3D10_SHADER_DEBUG;
        #endif
        V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) );
    
        // Obtain the technique
        g_pRender = g_pEffect->GetTechniqueByName( "Render" );
        g_pProjectionVariable = g_pEffect->GetVariableByName( "g_mWorldViewProjection" )->AsMatrix();
        g_pWorldVariable = g_pEffect->GetVariableByName( "g_mWorld" )->AsMatrix();
    
        // 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 ) );
        DXUTCreateTeapot( pd3dDevice, &g_pMesh );
    
        return S_OK;
    }
    
  4. OnD3D10FrameRender() は Rendering を行う CALLBACK 関数です。
    fTime の値で、Y軸を中心に World 座標を回転しながら描画します。
    回転が速い(遅い)ときは、この値で調整して下さい。
    D3DXMatrixLookAtLH() で View を設定します。
    D3DXMatrixPerspectiveFovLH() で描画環境を設定します。
    Shader に g_pProjectionVariable と g_pWorldVariable を設定して、g_pMesh->DrawSubset(s) でティーポットを描画します。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        // 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 );
    
        // Setup the effects
        D3DXMATRIX mWorld;
        D3DXMATRIX mView;
        D3DXMATRIX mProj;
        //D3DXMatrixRotationY( &mWorld, (float)fTime*D3DX_PI/2.0f );
        D3DXMatrixRotationY( &mWorld, (float)fTime/2.0f );
        D3DXVECTOR3 vEye(0,4,-4);
        D3DXVECTOR3 vLook(0,0,0);
        D3DXVECTOR3 vUp(0,1,0);
        D3DXMatrixLookAtLH( &mView, &vEye, &vLook, &vUp );
        D3DXMatrixPerspectiveFovLH( &mProj, D3DX_PI/3.0f, 640.0f/480.0f, 0.1f, 30.0f );
        D3DXMATRIX mWVP = mWorld * mView * mProj;
    
        // Update variables
        g_pProjectionVariable->SetMatrix( (float*)&mWVP );
        g_pWorldVariable->SetMatrix( (float*)&mWorld );
    
        D3D10_TECHNIQUE_DESC techDesc;
        g_pRender->GetDesc( &techDesc );
    
        UINT NumSubsets;
        g_pMesh->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_pMesh->DrawSubset(s);
            }
        }
    }
    
  5. OnD3D10DestroyDevice() では取得した Object を開放して下さい。
    void CALLBACK OnD3D10DestroyDevice( void* pUserContext )
    {
        if( g_pLayout ) g_pLayout->Release();
        if( g_pEffect ) g_pEffect->Release();
        if( g_pMesh ) g_pMesh->Release();
    }
    
  6. Shader のプログラム(Teapot.fx) です。
    Shader は法線ベクトルを持つモデルに光源を設定して描画するものを使って下さい。
    //--------------------------------------------------------------------------------------
    // File: SimpleSample.fx
    //
    // The effect file for the SimpleSample sample.  
    // 
    // Copyright (c) Microsoft Corporation. All rights reserved.
    //--------------------------------------------------------------------------------------
    
    
    //--------------------------------------------------------------------------------------
    // Global variables
    //--------------------------------------------------------------------------------------
    cbuffer cb0
    {
        float3 g_vLightDir = float3(-0.707,0.707,0);    // Light's direction in world space
    //    float4 g_vColor = float4(1,1,0.8,1);          // Object color
        float4 g_vColor = float4(1,1,0.4,1);            // Object color
    };
    
    cbuffer cb1
    {
        float4x4 g_mWorld;                  // World matrix for object
        float4x4 g_mWorldViewProjection;    // World * View * Projection matrix
    };
    
    BlendState NoBlending
    {
        AlphaToCoverageEnable = FALSE;
        BlendEnable[0] = FALSE;
    };
    
    //--------------------------------------------------------------------------------------
    // Vertex shader output structure
    //--------------------------------------------------------------------------------------
    struct VS_INPUT
    {
        float3 Position   : POSITION;
        float3 Normal     : NORMAL;
    };
    
    struct PS_INPUT
    {
        float4 Position   : SV_Position;   // vertex position 
        float3 Normal     : NORMAL;        // vertex diffuse color(note that COLOR0 is clamped from 0..1)
    };
    
    
    //--------------------------------------------------------------------------------------
    // This shader computes standard transform and lighting
    //--------------------------------------------------------------------------------------
    PS_INPUT RenderVS( VS_INPUT input )
    {
        PS_INPUT output;
        
        output.Position = mul( float4(input.Position,1), g_mWorldViewProjection);   
        output.Normal = mul(input.Normal, (float3x3)g_mWorld);
        
        return output;    
    }
    
    //--------------------------------------------------------------------------------------
    // This shader outputs the pixel's color by modulating the texture's
    // color with diffuse material color
    //--------------------------------------------------------------------------------------
    float4 RenderPS( PS_INPUT input ) : SV_Target
    { 
        return g_vColor * saturate( dot( normalize(input.Normal), g_vLightDir ) );
    }
    
    
    //--------------------------------------------------------------------------------------
    // Renders scene 
    //--------------------------------------------------------------------------------------
    technique10 Render
    {
        pass P0
        {       
            SetVertexShader( CompileShader( vs_4_0, RenderVS() ) );
            SetGeometryShader( NULL );
            SetPixelShader( CompileShader( ps_4_0, RenderPS() ) );
            
            SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
        }
    }
    
  7. float4 g_vColor でモデルの色を設定しています。
    ティーポットの色を変えて描画してみて下さい。
        float4 g_vColor = float4(1,1,0.8,1);
        float4 g_vColor = float4(1,1,0.4,1);
        float4 g_vColor = float4(1,0.3,0.3,1);
        

【NOTE】

DXUTShapes.cpp のソースコードを見て下さい。
立方体や球はもとより、トーラスやティーポットを生成するソースコードも書かれています。
さすがにティーポットのモデルを生成するのは大変なようです。
プログラムでモデルを生成するときに、少しは役に立つでしょうか。 (^_^;)

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