Шейдеры в программе DirectX11

Сначала надо скомпилировать текст шейдеров, или файла эффектов с шейдерами, создать формат вершин, константный буфер для переменных которые передаются в шейдер, семплеры для текстур- в разделе инициализации программы. В части рендеринга устанавливается вершинный индексный буфер, формат вершин, текстуры, переменные которые подаются на вход шейдера через константный буфер, и рисуется примитив.

//------------------------------------------
//константный буфер передаем в шейдер матрицу WVP
//в глобальной области видимости
struct CBChangesEveryFrame
{
XMMATRIX mxWVP;
};


DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS| D3DCOMPILE_DEBUG;
HRESULT hr;
ID3DBlob* pErrorBlob;
ID3DBlob* pVSBlob = NULL;

//------------------------------------------
//компилируем вершинный шейдер в файле эффектов
hr = D3DX11CompileFromFile( szEffectFileName, NULL, NULL, "VS", "vs_4_0",
dwShaderFlags, 0, NULL, &pVSBlob, &pErrorBlob, NULL );
if( FAILED(hr) )
{
if( pErrorBlob != NULL )
MessageBox(NULL, (char*)pErrorBlob->GetBufferPointer(), "Info", MB_OK) ;
if( pErrorBlob ) pErrorBlob->Release();
return;
}
if( pErrorBlob ) pErrorBlob->Release();


//------------------------------------------
//создаем указатель на интерфейс вершинного шейдера
hr = mDev->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return;
}

//----------------------------------------------------------
//компилируем пиксельный шейдер
ID3DBlob* pPSBlob = NULL;
hr = D3DX11CompileFromFile( szEffectFileName, NULL, NULL, "PS", "ps_4_0",
dwShaderFlags, 0, NULL, &pPSBlob, &pErrorBlob, NULL );
if( FAILED(hr) )
{
if( pErrorBlob != NULL )
MessageBox(NULL, (char*)pErrorBlob->GetBufferPointer(), "Info", MB_OK) ;
if( pErrorBlob ) pErrorBlob->Release();
return;
}
if( pErrorBlob ) pErrorBlob->Release();

// создаем пиксельный шейдер
hr = mDev->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &m_pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return;


//формат вершины позиция и текстурные координаты
D3D11_INPUT_ELEMENT_DESC vertexLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

UINT numElements = sizeof( vertexLayout ) / sizeof( vertexLayout[0] );

//создаем input layout на базе имеющегося формата вершин
m_pVertexLayout = NULL;
mDev->CreateInputLayout( vertexLayout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &m_pVertexLayout );
pVSBlob->Release();
if( FAILED( hr ) )
return;

//-------------------------------
// создаем sample state для текстуры которая будет передаваться в шейдер
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = mDev->CreateSamplerState( &sampDesc, &m_pSamplerLinear );
if( FAILED( hr ) )
return;

//--------------------------------------------
//создаем константный буфер
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
bd.ByteWidth = sizeof(CBChangesEveryFrame);
hr = mDev->CreateBuffer( &bd, NULL, &m_pCBChangesEveryFrame );
if( FAILED( hr ) )
return;


//-------------------------------------------------
//секция draw scene
//буфер вершин будет отображатся как triangle list
m_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
//устанавливаем формат вершин для входа на шейдер
m_pImmediateContext->IASetInputLayout( m_pVertexLayout );

//устанавливаем вершинный и индексный буфер
UINT stride = sizeof( MY_VERTEX );
UINT offset = 0;
m_pImmediateContext->IASetVertexBuffers( 0, 1, &(pFrame->pMeshContainer->pVB), &stride, &offset );
m_pImmediateContext->IASetIndexBuffer( pFrame->pMeshContainer->pIB, DXGI_FORMAT_R32_UINT, 0 );


//подаем в шейдер матрицу WVP пользуясь константным буфером
mWVP = mWorld * mView * mProj;
CBChangesEveryFrame cb;
cb.mxWVP = mxWVP;
m_pImmediateContext->UpdateSubresource( m_pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );

//в цикле берем материал и рисуем примитив
for(UINT i=0; ipMeshContainer->nNumMat; i++)
{
//устанавливаем текстуру
m_pImmediateContext->PSSetShaderResources( 0, 1, &(pFrame->pMeshContainer->m_TextureArray[i].m_pTexture) );

//устанавливаем вершинный шейдер
m_pImmediateContext->VSSetShader( m_pVertexShader, NULL, 0 );
m_pImmediateContext->VSSetConstantBuffers( 0, 1, &m_pCBChangesEveryFrame );
//устанавливаем пиксельный шейдер
m_pImmediateContext->PSSetShader( m_pPixelShader, NULL, 0 );
//устанавливаем буфер констант и семплеры для подачи в шейдер
m_pImmediateContext->PSSetConstantBuffers( 0, 1, &m_pCBChangesEveryFrame );
m_pImmediateContext->PSSetSamplers( 0, 1, &m_pSamplerLinear );


UINT nIndxCount = pFrame->pMeshContainer->atr[i].FaceCount * 3;
UINT nStartIndexLocation = pFrame->pMeshContainer->atr[i].FaceStart * 3;
UINT nBaseVertLocation = pFrame->pMeshContainer->atr[i].VertexStart;

//рисум примитив с данным материалом
m_pImmediateContext->DrawIndexed(nIndxCount,nStartIndexLocation, 0 );
}