~プログラミング~ 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_pConstantBuffer;
    ID3D11InputLayout*      m_pInputLayout;
    ID3D11VertexShader*     m_pVertexShader;
    ID3D11PixelShader*      m_pPixelShader;
    D3D11_VIEWPORT          m_Viewport;

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 ];
};

Vertex g_VertexList[] {
    { { -0.5f,  0.5f, -0.5f }, {  0.0f,  0.0f, -1.0f } },
    { {  0.5f,  0.5f, -0.5f }, {  0.0f,  0.0f, -1.0f } },
    { { -0.5f, -0.5f, -0.5f }, {  0.0f,  0.0f, -1.0f } },
    { {  0.5f, -0.5f, -0.5f }, {  0.0f,  0.0f, -1.0f } },

    { { -0.5f,  0.5f,  0.5f }, {  0.0f,  0.0f,  1.0f } },
    { { -0.5f, -0.5f,  0.5f }, {  0.0f,  0.0f,  1.0f } },
    { {  0.5f,  0.5f,  0.5f }, {  0.0f,  0.0f,  1.0f } },
    { {  0.5f, -0.5f,  0.5f }, {  0.0f,  0.0f,  1.0f } },

    { { -0.5f,  0.5f,  0.5f }, { -1.0f,  0.0f,  0.0f } },
    { { -0.5f,  0.5f, -0.5f }, { -1.0f,  0.0f,  0.0f } },
    { { -0.5f, -0.5f,  0.5f }, { -1.0f,  0.0f,  0.0f } },
    { { -0.5f, -0.5f, -0.5f }, { -1.0f,  0.0f,  0.0f } },

    { {  0.5f,  0.5f,  0.5f }, {  1.0f,  0.0f,  0.0f } },
    { {  0.5f, -0.5f,  0.5f }, {  1.0f,  0.0f,  0.0f } },
    { {  0.5f,  0.5f, -0.5f }, {  1.0f,  0.0f,  0.0f } },
    { {  0.5f, -0.5f, -0.5f }, {  1.0f,  0.0f,  0.0f } },

    { { -0.5f,  0.5f,  0.5f }, {  0.0f,  1.0f,  0.0f } },
    { {  0.5f,  0.5f,  0.5f }, {  0.0f,  1.0f,  0.0f } },
    { { -0.5f,  0.5f, -0.5f }, {  0.0f,  1.0f,  0.0f } },
    { {  0.5f,  0.5f, -0.5f }, {  0.0f,  1.0f,  0.0f } },

    { { -0.5f, -0.5f,  0.5f }, {  0.0f, -1.0f,  0.0f } },
    { { -0.5f, -0.5f, -0.5f }, {  0.0f, -1.0f,  0.0f } },
    { {  0.5f, -0.5f,  0.5f }, {  0.0f, -1.0f,  0.0f } },
    { {  0.5f, -0.5f, -0.5f }, {  0.0f, -1.0f,  0.0f } },
};

WORD g_IndexList[] {
     0,  1,  2,     3,  2,  1,
     4,  5,  6,     7,  6,  5,
     8,  9, 10,    11, 10,  9,
    12, 13, 14,    15, 14, 13,
    16, 17, 18,    19, 18, 17,
    20, 21, 22,    23, 22, 21, 
};

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 },
};


struct ConstantBuffer {
    XMFLOAT4X4 world;
    XMFLOAT4X4 view;
    XMFLOAT4X4 projection;
    XMFLOAT4   light;
};





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_pConstantBuffer      = NULL;
    m_pInputLayout         = NULL;
    m_pVertexShader        = NULL;
    m_pPixelShader         = NULL;
}

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;



    //頂点バッファ作成
    D3D11_BUFFER_DESC vbDesc;
    vbDesc.ByteWidth           = sizeof( Vertex ) * 24;
    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          = g_VertexList;
    vrData.SysMemPitch      = 0;
    vrData.SysMemSlicePitch = 0;

    hr = m_pDevice->CreateBuffer( &vbDesc, &vrData, &m_pVertexBuffer );
    if ( FAILED( hr ) )
        return hr;


    //インデックスバッファ作成
    D3D11_BUFFER_DESC ibDesc;
    ibDesc.ByteWidth           = sizeof( WORD ) * 6 * 6;
    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          = g_IndexList;
    irData.SysMemPitch      = 0;
    irData.SysMemSlicePitch = 0;

    hr = m_pDevice->CreateBuffer( &ibDesc, &irData, &m_pIndexBuffer );
    if ( FAILED( hr ) )
        return hr;


    //定数バッファ作成
    D3D11_BUFFER_DESC cbDesc;
    cbDesc.ByteWidth           = sizeof( ConstantBuffer );
    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_pConstantBuffer );
    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;

    return hr;
}

void CD3DTest::Release()
{
    if( m_pImmediateContext ) {
        m_pImmediateContext->ClearState();
    }
    SAFE_RELEASE( m_pVertexBuffer );
    SAFE_RELEASE( m_pIndexBuffer );
    SAFE_RELEASE( m_pConstantBuffer );
    SAFE_RELEASE( m_pInputLayout );
    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()
{
    XMMATRIX worldMatrix = XMMatrixTranslation( 0.0f, 0.0f, 0.0f );
        
    XMVECTOR eye         = XMVectorSet( 2.0f, 2.0f, -2.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( 45.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 light       = XMVector3Normalize( XMVectorSet( 0.0f, 0.5f, -1.0f, 0.0f ) );

    ConstantBuffer cb;
    XMStoreFloat4x4( &cb.world,      XMMatrixTranspose( worldMatrix ) );
    XMStoreFloat4x4( &cb.view,       XMMatrixTranspose( viewMatrix ) );
    XMStoreFloat4x4( &cb.projection, XMMatrixTranspose( projMatrix ) );
    XMStoreFloat4(   &cb.light,      light );
    m_pImmediateContext->UpdateSubresource( m_pConstantBuffer, 0, NULL, &cb, 0, 0 );


    float clearColor[ 4 ] = { 0.0f, 0.0f, 0.0f, 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_pConstantBuffer );
    m_pImmediateContext->VSSetShader( m_pVertexShader, NULL, 0 );
    m_pImmediateContext->RSSetViewports( 1, &m_Viewport );
    m_pImmediateContext->PSSetShader( m_pPixelShader, NULL, 0 );
    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( 36, 0, 0 );

    m_pSwapChain->Present( 0, 0 );
}

vs_test.vsh

struct VS_IN
{
    float4 pos : POSITION0;
    float4 nor : NORMAL0;
};

struct VS_OUT
{
    float4 pos : SV_POSITION;
    float4 col : COLOR0;
};

cbuffer ConstantBuffer
{
    float4x4 World;         //ワールド変換行列
    float4x4 View;          //ビュー変換行列
    float4x4 Projection;    //透視射影変換行列
    float4   Light;
}

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);
        
    nor        = mul(input.nor, World).xyz;
    nor        = normalize(nor);
        
    col        = saturate(dot(nor, (float3)Light));
    col        = col * 0.5f + 0.5f;
        
    output.col = float4(col, col, col, 1.0f);
    return output;
}

ps_test.psh

struct PS_IN
{
    float4 pos : SV_POSITION;
    float4 col : COLOR0;
};


float4 ps_main( PS_IN input ) : SV_Target
{
    return input.col;
}