~プログラミング~ DirectX 11でテクスチャマッピング(ソースコード)

CD3DTest.h

#define SAFE_RELEASE(p)      { if( NULL != p ) { p->Release(); p = NULL; } }


class CD3DTest {
public:
    ID3D11Device*             m_pDevice;
    ID3D11DeviceContext*      m_pImmediateContext;
    IDXGISwapChain*           m_pSwapChain;
    ID3D11Texture2D*          m_pDepthStencilTexture;
    ID3D11RenderTargetView*   m_pRenderTargetView;
    ID3D11DepthStencilView*   m_pDepthStencilView;
    ID3D11Buffer*             m_pVertexBuffer;
    ID3D11Buffer*             m_pIndexBuffer;
    ID3D11Buffer*             m_pMatrixBuffer;
    ID3D11Buffer*             m_pLightBuffer;
    ID3D11InputLayout*        m_pInputLayout;
    ID3D11Resource*           m_pTexture;
    ID3D11ShaderResourceView* m_pTextureView;
    ID3D11SamplerState*       m_pSampler;
    ID3D11VertexShader*       m_pVertexShader;
    ID3D11PixelShader*        m_pPixelShader;
    D3D11_VIEWPORT            m_Viewport;
    int                       m_VertexCount;
    int                       m_IndexCount;
    float                     m_Angle;

public:
            CD3DTest();
    virtual ~CD3DTest();
    virtual HRESULT Create( HWND hwnd );
    virtual void    Release();
    virtual void    Render();
};

CD3DTest.cpp

#include "stdafx.h"

struct Vertex {
    float pos[ 3 ];
    float nor[ 3 ];
    float tex[ 2 ];
};

D3D11_INPUT_ELEMENT_DESC g_VertexDesc[] {
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,                            0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

struct ConstantMatrixBuffer {
    XMFLOAT4X4 world;
    XMFLOAT4X4 view;
    XMFLOAT4X4 projection;
};

struct ConstantLight {
    XMFLOAT4 pos;               //座標(x,y,z)
    XMFLOAT4 diffuse;           //拡散(r,g,b)
    XMFLOAT4 specular;          //反射(r,g,b)
    XMFLOAT4 attenuate;         //減衰(a,b,c)
};

struct ConstantMaterial {
    XMFLOAT4 ambient;           //環境(r,g,b)
    XMFLOAT4 diffuse;           //拡散(r,g,b)
    XMFLOAT4 specular;          //反射(r,g,b,光沢度係数)
};

struct ConstantLightBuffer {
    XMFLOAT4         eyePos;   //視点座標
    XMFLOAT4         ambient;  //環境光(r,g,b)
    ConstantLight    pntLight; //点光源
    ConstantMaterial material; //物体の質感
};


int SEGMENT = 36;





CD3DTest::CD3DTest()
{
    m_pDevice               = NULL;
    m_pImmediateContext     = NULL;
    m_pSwapChain            = NULL;
    m_pDepthStencilTexture  = NULL;
    m_pRenderTargetView     = NULL;
    m_pDepthStencilView     = NULL;
    m_pVertexBuffer         = NULL;
    m_pIndexBuffer          = NULL;
    m_pMatrixBuffer         = NULL;
    m_pLightBuffer          = NULL;
    m_pInputLayout          = NULL;
    m_pTexture              = NULL;
    m_pTextureView          = NULL;
    m_pSampler              = NULL;
    m_pVertexShader         = NULL;
    m_pPixelShader          = NULL;
    m_VertexCount           = 0;
    m_IndexCount            = 0;
}

CD3DTest::~CD3DTest()
{
    Release();
}

HRESULT CD3DTest::Create( HWND hwnd )
{
    Release();

    HRESULT              hr;
    CRect                rect;
    DXGI_SWAP_CHAIN_DESC scDesc;

    ::GetClientRect( hwnd, &rect );
    ::ZeroMemory( &scDesc, sizeof( scDesc ) );
    scDesc.BufferCount        = 1;
    scDesc.BufferDesc.Width   = rect.Width();
    scDesc.BufferDesc.Height  = rect.Height();
    scDesc.BufferDesc.Format  = DXGI_FORMAT_R8G8B8A8_UNORM;
    scDesc.BufferUsage        = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scDesc.OutputWindow       = hwnd;
    scDesc.SampleDesc.Count   = 1;
    scDesc.SampleDesc.Quality = 0;
    scDesc.Windowed           = TRUE;

    UINT flags = 0;
#ifdef _DEBUG
    flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
    D3D_FEATURE_LEVEL pLevels[] = { D3D_FEATURE_LEVEL_11_0 };
    D3D_FEATURE_LEVEL level;

    hr = D3D11CreateDeviceAndSwapChain( NULL,
                                        D3D_DRIVER_TYPE_HARDWARE,
                                        NULL,
                                        flags,
                                        pLevels,
                                        1,
                                        D3D11_SDK_VERSION,
                                        &scDesc,
                                        &m_pSwapChain,
                                        &m_pDevice,
                                        &level,
                                        &m_pImmediateContext );
    if ( FAILED( hr ) )
        return hr;


    ID3D11Texture2D* pBackBuffer;

    hr = m_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&pBackBuffer );
    if ( FAILED( hr ) )
        return hr;

    hr = m_pDevice->CreateRenderTargetView( pBackBuffer, NULL, &m_pRenderTargetView );
    pBackBuffer->Release();
    if ( FAILED( hr ) )
        return hr;



    //深度ステンシルバッファ作成
    D3D11_TEXTURE2D_DESC txDesc;
    ZeroMemory( &txDesc, sizeof( txDesc ) );
    txDesc.Width              = rect.Width();
    txDesc.Height             = rect.Height();
    txDesc.MipLevels          = 1;
    txDesc.ArraySize          = 1;
    txDesc.Format             = DXGI_FORMAT_D24_UNORM_S8_UINT;
    txDesc.SampleDesc.Count   = 1;
    txDesc.SampleDesc.Quality = 0;
    txDesc.Usage              = D3D11_USAGE_DEFAULT;
    txDesc.BindFlags          = D3D11_BIND_DEPTH_STENCIL;
    txDesc.CPUAccessFlags     = 0;
    txDesc.MiscFlags          = 0;
    hr = m_pDevice->CreateTexture2D( &txDesc, NULL, &m_pDepthStencilTexture );
    if ( FAILED( hr ) )
        return hr;

    D3D11_DEPTH_STENCIL_VIEW_DESC dsDesc;
    ZeroMemory( &dsDesc, sizeof( dsDesc ) );
    dsDesc.Format             = txDesc.Format;
    dsDesc.ViewDimension      = D3D11_DSV_DIMENSION_TEXTURE2D;
    dsDesc.Texture2D.MipSlice = 0;
    hr = m_pDevice->CreateDepthStencilView( m_pDepthStencilTexture, &dsDesc, &m_pDepthStencilView );
    if ( FAILED( hr ) )
        return hr;


        //頂点バッファ作成
    int     vcount = ( SEGMENT + 1 ) * ( SEGMENT / 2 + 1 );
    Vertex* pVList = new Vertex[ vcount ];

    for ( int i = 0; i <= ( SEGMENT / 2 ); ++ i ) {
        float irad = XM_PI * 2.0f / (float)SEGMENT * (float)i;
        float y    = (float)cos( irad );
        float r    = (float)sin( irad );
        float v    = (float)i / (float)( SEGMENT / 2 );
        for ( int j = 0; j <= SEGMENT; ++ j ) {
            float jrad = XM_PI * 2.0f / (float)SEGMENT * (float)j;
            float x    = r * (float)cos( jrad );
            float z    = r * (float)sin( jrad );
            float u    = (float)j / (float)SEGMENT;
            int   inx  = i * ( SEGMENT + 1 ) + j;
            pVList[ inx ].pos[ 0 ] = x;
            pVList[ inx ].pos[ 1 ] = y;
            pVList[ inx ].pos[ 2 ] = z;
            pVList[ inx ].nor[ 0 ] = x;
            pVList[ inx ].nor[ 1 ] = y;
            pVList[ inx ].nor[ 2 ] = z;
            pVList[ inx ].tex[ 0 ] = u;
            pVList[ inx ].tex[ 1 ] = v;
        }
    }


    D3D11_BUFFER_DESC vbDesc;
    vbDesc.ByteWidth           = sizeof( Vertex ) * vcount;
    vbDesc.Usage               = D3D11_USAGE_DEFAULT;
    vbDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
    vbDesc.CPUAccessFlags      = 0;
    vbDesc.MiscFlags           = 0;
    vbDesc.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA vrData;
    vrData.pSysMem             = pVList;
    vrData.SysMemPitch         = 0;
    vrData.SysMemSlicePitch    = 0;

    hr = m_pDevice->CreateBuffer( &vbDesc, &vrData, &m_pVertexBuffer );
    if ( FAILED( hr ) ) {
        delete[] pVList;
        return hr;
    }
    delete[] pVList;


    //インデックスバッファ作成
    int   icount = SEGMENT * 3 + SEGMENT * ( SEGMENT / 2 - 1 ) * 6 + SEGMENT * 3;
    WORD* pIList = new WORD[ icount ];

    icount = 0;
    int i  = 0;
    for ( int j = 0; j < SEGMENT; ++ j ) {
        pIList[ icount     ] =   i       * ( SEGMENT + 1 ) + j;
        pIList[ icount + 1 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j + 1;
        pIList[ icount + 2 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j;
        icount += 3;
    }
    for ( i = 1; i < SEGMENT / 2; ++ i ) {
        for ( int j = 0; j < SEGMENT; ++ j ) {
            pIList[ icount     ] =   i       * ( SEGMENT + 1 ) + j;
            pIList[ icount + 1 ] =   i       * ( SEGMENT + 1 ) + j + 1;
            pIList[ icount + 2 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j;
            icount += 3;
            pIList[ icount     ] =   i       * ( SEGMENT + 1 ) + j + 1;
            pIList[ icount + 1 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j + 1;
            pIList[ icount + 2 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j;
            icount += 3;
        }
    }
    i = SEGMENT / 2;
    for ( int j = 0; j < SEGMENT; ++ j ) {
        pIList[ icount     ] =   i       * ( SEGMENT + 1 ) + j;
        pIList[ icount + 1 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j + 1;
        pIList[ icount + 2 ] = ( i + 1 ) * ( SEGMENT + 1 ) + j;
        icount += 3;
    }

    D3D11_BUFFER_DESC ibDesc;
    ibDesc.ByteWidth           = sizeof( WORD ) * icount;
    ibDesc.Usage               = D3D11_USAGE_DEFAULT;
    ibDesc.BindFlags           = D3D11_BIND_INDEX_BUFFER;
    ibDesc.CPUAccessFlags      = 0;
    ibDesc.MiscFlags           = 0;
    ibDesc.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA irData;
    irData.pSysMem             = pIList;
    irData.SysMemPitch         = 0;
    irData.SysMemSlicePitch    = 0;

    hr = m_pDevice->CreateBuffer( &ibDesc, &irData, &m_pIndexBuffer );
    if ( FAILED( hr ) ) {
        delete[] pIList;
        return hr;
    }
    delete[] pIList;


    //定数バッファ作成
    D3D11_BUFFER_DESC cbDesc;
    cbDesc.ByteWidth           = sizeof( ConstantMatrixBuffer );
    cbDesc.Usage               = D3D11_USAGE_DEFAULT;
    cbDesc.BindFlags           = D3D11_BIND_CONSTANT_BUFFER;
    cbDesc.CPUAccessFlags      = 0;
    cbDesc.MiscFlags           = 0;
    cbDesc.StructureByteStride = 0;

    hr = m_pDevice->CreateBuffer( &cbDesc, NULL, &m_pMatrixBuffer );
    if ( FAILED( hr ) )
        return hr;

    cbDesc.ByteWidth           = sizeof( ConstantLightBuffer );
    cbDesc.Usage               = D3D11_USAGE_DEFAULT;
    cbDesc.BindFlags           = D3D11_BIND_CONSTANT_BUFFER;
    cbDesc.CPUAccessFlags      = 0;
    cbDesc.MiscFlags           = 0;
    cbDesc.StructureByteStride = 0;

    hr = m_pDevice->CreateBuffer( &cbDesc, NULL, &m_pLightBuffer );
    if ( FAILED( hr ) )
        return hr;


    //テクスチャ読み込み
    hr = CreateWICTextureFromFile( m_pDevice, _T( "sample.png" ), &m_pTexture, &m_pTextureView );
    if ( FAILED( hr ) )
        return hr;

    D3D11_SAMPLER_DESC smpDesc;
    ::ZeroMemory( &smpDesc, sizeof( D3D11_SAMPLER_DESC ) );
    smpDesc.Filter   = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    smpDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
    smpDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
    smpDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
    hr = m_pDevice->CreateSamplerState( &smpDesc, &m_pSampler );
    if ( FAILED( hr ) )
        return hr;

    //頂点レイアウト作成
    hr = m_pDevice->CreateInputLayout( g_VertexDesc, ARRAYSIZE( g_VertexDesc ), g_vs_main, sizeof( g_vs_main ), &m_pInputLayout );
    if ( FAILED( hr ) )
        return hr;

    //頂点シェーダー生成
    hr = m_pDevice->CreateVertexShader( &g_vs_main, sizeof( g_vs_main ), NULL, &m_pVertexShader );
    if ( FAILED( hr ) )
        return hr;

    //ピクセルシェーダー生成
    hr = m_pDevice->CreatePixelShader( &g_ps_main, sizeof( g_ps_main ), NULL, &m_pPixelShader );
    if ( FAILED( hr ) )
        return hr;


    //ビューポート設定
    m_Viewport.TopLeftX = 0;
    m_Viewport.TopLeftY = 0;
    m_Viewport.Width    = (FLOAT)rect.Width();
    m_Viewport.Height   = (FLOAT)rect.Height();
    m_Viewport.MinDepth = 0.0f;
    m_Viewport.MaxDepth = 1.0f;


    m_VertexCount = vcount;
    m_IndexCount  = icount;

    return hr;
}

void CD3DTest::Release()
{
    if( m_pImmediateContext ) {
        m_pImmediateContext->ClearState();
    }
    SAFE_RELEASE( m_pVertexBuffer );
    SAFE_RELEASE( m_pIndexBuffer );
    SAFE_RELEASE( m_pMatrixBuffer );
    SAFE_RELEASE( m_pLightBuffer );
    SAFE_RELEASE( m_pInputLayout );
    SAFE_RELEASE( m_pSampler );
    SAFE_RELEASE( m_pTextureView );
    SAFE_RELEASE( m_pTexture );
    SAFE_RELEASE( m_pVertexShader );
    SAFE_RELEASE( m_pPixelShader );
    SAFE_RELEASE( m_pRenderTargetView );
    SAFE_RELEASE( m_pDepthStencilView );
    SAFE_RELEASE( m_pDepthStencilTexture );
    SAFE_RELEASE( m_pSwapChain );
    SAFE_RELEASE( m_pImmediateContext );
    SAFE_RELEASE( m_pDevice );
}

void CD3DTest::Render()
{
    m_Angle += XMConvertToRadians( 1.0f );
    XMMATRIX worldMatrix = XMMatrixRotationY( m_Angle );

    XMVECTOR eye         = XMVectorSet( 0.0f, 3.0f, -7.0f, 0.0f );
    XMVECTOR focus       = XMVectorSet( 0.0f, 0.0f,  0.0f, 0.0f );
    XMVECTOR up          = XMVectorSet( 0.0f, 1.0f,  0.0f, 0.0f );
    XMMATRIX viewMatrix  = XMMatrixLookAtLH( eye, focus, up );

    float    fov         = XMConvertToRadians( 20.0f );
    float    aspect      = m_Viewport.Width / m_Viewport.Height;
    float    nearZ       =   0.1f;
    float    farZ        = 100.0f;
    XMMATRIX projMatrix  = XMMatrixPerspectiveFovLH( fov, aspect, nearZ, farZ );

    XMVECTOR lightPosition    = XMVectorSet( -9.5f,  9.5f, -1.0f, 0.0f );
    XMVECTOR lightAmbient     = XMVectorSet(  0.6f,  0.6f,  0.6f, 0.0f );
    XMVECTOR lightDiffuse     = XMVectorSet(  1.0f,  1.0f,  1.0f, 0.0f );
    XMVECTOR lightSpecular    = XMVectorSet(  1.0f,  1.0f,  1.0f, 0.0f );
    XMVECTOR lightAttenuate   = XMVectorSet(  1.0f,  0.0f,  0.0f, 0.0f );
    XMVECTOR materialAmbient  = XMVectorSet(  1.0f,  1.0f,  1.0f, 0.0f );
    XMVECTOR materialDiffuse  = XMVectorSet(  1.0f,  1.0f,  1.0f, 0.0f );
    XMVECTOR materialSpecular = XMVectorSet(  0.5f,  0.5f,  0.5f, 50.0f );


    ConstantMatrixBuffer cmb;
    XMStoreFloat4x4( &cmb.world,       XMMatrixTranspose( worldMatrix ) );
    XMStoreFloat4x4( &cmb.view,        XMMatrixTranspose( viewMatrix ) );
    XMStoreFloat4x4( &cmb.projection,  XMMatrixTranspose( projMatrix ) );
    ConstantLightBuffer clb;
    XMStoreFloat4( &clb.eyePos,             eye );
    XMStoreFloat4( &clb.ambient,            lightAmbient );
    XMStoreFloat4( &clb.pntLight.pos,       lightPosition );
    XMStoreFloat4( &clb.pntLight.diffuse,   lightDiffuse );
    XMStoreFloat4( &clb.pntLight.specular,  lightSpecular );
    XMStoreFloat4( &clb.pntLight.attenuate, lightAttenuate );
    XMStoreFloat4( &clb.material.ambient,   materialAmbient );
    XMStoreFloat4( &clb.material.diffuse,   materialDiffuse );
    XMStoreFloat4( &clb.material.specular,  materialSpecular );
    m_pImmediateContext->UpdateSubresource( m_pMatrixBuffer, 0, NULL, &cmb, 0, 0 );
    m_pImmediateContext->UpdateSubresource( m_pLightBuffer,  0, NULL, &clb, 0, 0 );


    float clearColor[ 4 ] = { 0.3f, 0.3f, 0.3f, 1.0f }; //red,green,blue,alpha

    UINT strides = sizeof( Vertex );
    UINT offsets = 0;
    m_pImmediateContext->IASetInputLayout( m_pInputLayout );
    m_pImmediateContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &strides, &offsets );
    m_pImmediateContext->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
    m_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
    m_pImmediateContext->VSSetConstantBuffers( 0, 1, &m_pMatrixBuffer );
    m_pImmediateContext->VSSetShader( m_pVertexShader, NULL, 0 );
    m_pImmediateContext->RSSetViewports( 1, &m_Viewport );
    m_pImmediateContext->PSSetConstantBuffers( 0, 1, &m_pLightBuffer );
    m_pImmediateContext->PSSetShader( m_pPixelShader, NULL, 0 );
    m_pImmediateContext->PSSetShaderResources( 0, 1, &m_pTextureView );
    m_pImmediateContext->PSSetSamplers( 0, 1, &m_pSampler );
    m_pImmediateContext->OMSetRenderTargets( 1, &m_pRenderTargetView, m_pDepthStencilView );

    m_pImmediateContext->ClearRenderTargetView( m_pRenderTargetView, clearColor );
    m_pImmediateContext->ClearDepthStencilView( m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
    m_pImmediateContext->DrawIndexed( m_IndexCount, 0, 0 );

    m_pSwapChain->Present( 0, 0 );
}

vs_test.vsh

struct VS_IN
{
    float4 pos : POSITION0;
    float4 nor : NORMAL0;
    float2 tex : TEXCOORD0;
};

struct VS_OUT
{
    float4 pos  : SV_POSITION;
    float4 posw : POSITION0;
    float4 norw : NORMAL0;
    float2 tex  : TEXCOORD0;
};

cbuffer ConstantBuffer
{
    float4x4 world;         //ワールド変換行列
    float4x4 view;          //ビュー変換行列
    float4x4 projection;    //透視射影変換行列
}

VS_OUT vs_main( VS_IN input )
{
    VS_OUT output;
    float3 nor;
    float  col;

    output.pos  = mul(input.pos,  world);
    output.pos  = mul(output.pos, view);
    output.pos  = mul(output.pos, projection);

    output.posw = mul(input.pos,  world);
    output.norw = mul(input.nor,  world);

    output.tex  = input.tex;

    return output;
}

ps_test.psh

struct PS_IN {
    float4 pos  : SV_POSITION;
    float4 posw : POSITION0;    //ワールド座標系の座標
    float4 norw : NORMAL0;      //ワールド座標系の法線
    float2 tex  : TEXCOORD0;
};

struct Light {
    float4 pos;               //座標(x,y,z)
    float4 diffuse;           //拡散(r,g,b)
    float4 specular;          //反射(r,g,b)
    float4 attenuate;         //減衰(a,b,c)
};

struct Material {
    float4 ambient;           //環境(r,g,b)
    float4 diffuse;           //拡散(r,g,b)
    float4 specular;          //反射(r,g,b,光沢度係数)
};

cbuffer ConstantBuffer {
    float4   eyePos;          //視点座標
    float4   ambient;         //環境光(r,g,b)
    Light    pntLight;        //点光源
    Material material;        //物体の質感
};

Texture2D    myTexture : register(t0); //テクスチャー
SamplerState mySampler : register(s0); //サンプラー


float4 ps_main( PS_IN input ) : SV_Target
{
    float3 n;
    float3 v;
    float3 l;
    float3 r;
    float  d;
    float  a;
    float3 iT;
    float3 iA;
    float3 iD;
    float3 iS;

    n = normalize(input.norw.xyz);
    v = normalize(eyePos.xyz - input.posw.xyz);
    l = pntLight.pos.xyz - input.posw.xyz;
    d = length(l);                                                                                         //光源距離
    l = normalize(l);                                                                                      //正規化光源ベクトル
    r = 2.0 * n * dot(n, l) - l;                                                                           //正規化反射ベクトル
    a = saturate(1.0f / (pntLight.attenuate.x + pntLight.attenuate.y * d + pntLight.attenuate.z * d * d)); //減衰

    iT = myTexture.Sample(mySampler, input.tex);
    iA =                                                 iT * material.ambient.xyz  * ambient.xyz;
    iD =     saturate(dot(l, n))                       * iT * material.diffuse.xyz  * pntLight.diffuse.xyz  * a;
    iS = pow(saturate(dot(r, v)), material.specular.w) *      material.specular.xyz * pntLight.specular.xyz * a;

    return float4(saturate(iA + iD + iS), 1.0);
}