初始化设备大致分这几个步骤:
1.Create device
2.Create swap chain
3.Create a render target view
4.Create depth stencil texture
5.Create the depth stencil view
6.Setup the viewport
7.Compile and create the vertex shader. Define, create and set the input layout at the same time.
7.1.Compile the vertex shader
7.2.Create the vertex shader
7.3.Define the input layout
7.4.Create the input layout
7.5.Set the input layout
8.Compile and create the pixel shader
8.1.Compile the pixel shader
8.2.Create the pixel shader
9.Create and set vertex buffer
9.1.Create vertex buffer
9.2.Set vertex buffer
10.Create and set index buffer
10.1.Create index buffer
10.2.Set index buffer
11.Set primitive topology
12.Create the constant buffer
13.Initialize the world matrix, view matrix, projection matrix
例子:(vs2012下)
1.lighting.fx
// Constant Buffer Variables
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
float4 vLightDir[2];
float4 vLightColor;
}
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : TEXCOORD0;
};
// 以上都是声明
// 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( float4(input.Norm, 1), World ).xyz;// .xyz指取前三位向量,等式左边的PS_INPUT中的Norm是float3型,而右边是float4型
// 也可写成output.Norm = mul( input.Norm, (float3x3)World );
return output;
}
// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
float4 finalColor = 0;
float k = 0.85f;// 反射率
for(int i = 0; i < 2; i++)
{
finalColor += k * saturate(dot((float3)vLightDir[i], -input.Norm) * vLightColor);// 反射率 * saturate(dot(两光线向量·顶点法线向量)·颜色值),saturate表示饱和处理——大于1变为1,小于0变成0
}
finalColor.a = 1;// 同finalColor.w = 1; rgba对应xyzw
return finalColor;
}
2.winmain.cpp
#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
// 找到项目的属性->链接器->输入->附加依赖项,在%(AdditionalDependencies)前追加上以下项:
// d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;
// 或者像下面这样添加代码:
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "comctl32.lib")
using namespace DirectX;
struct VertexNormal
{
XMFLOAT3 Pos;
XMFLOAT3 Normal;
};
struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
XMFLOAT4 vLightDir[2];// 光照方向向量,两个才有较好效果,一个无法体现棱角
XMFLOAT4 vLightColor;// 光照颜色
};
HINSTANCE g_hInst = nullptr;
HWND g_hWnd = nullptr;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = nullptr;
ID3D11Device1* g_pd3dDevice1 = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr;
ID3D11DeviceContext1* g_pImmediateContext1 = nullptr;
IDXGISwapChain* g_pSwapChain = nullptr;
IDXGISwapChain1* g_pSwapChain1 = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11Texture2D* g_pDepthStencil = nullptr;
ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
ID3D11VertexShader* g_pVertexShader = nullptr;
ID3D11PixelShader* g_pPixelShader = nullptr;
//ID3D11PixelShader* g_pPixelShaderSolid = nullptr;// 用于着色光源,用不到
ID3D11InputLayout* g_pVertexLayout = nullptr;
ID3D11Buffer* g_pVertexBuffer = nullptr;
//ID3D11Buffer* g_pIndexBuffer = nullptr;// 索引缓冲,用不到,顶点生成时已被排序,无需索引
ID3D11Buffer* g_pConstantBuffer = nullptr;
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )
{
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
return 0;
if( FAILED( InitDevice() ) )
{
CleanupDevice();
return 0;
}
MSG msg = {};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
CleanupDevice();
UnregisterClass(L"class1", g_hInst);
return ( int )msg.wParam;
}
HRESULT InitDevice()
{
HRESULT hr = S_OK;
// 1.Create device
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if ( hr == E_INVALIDARG )
{
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
}
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
IDXGIFactory1* dxgiFactory = nullptr;
{
IDXGIDevice* dxgiDevice = nullptr;
hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );
if (SUCCEEDED(hr))
{
IDXGIAdapter* adapter = nullptr;
hr = dxgiDevice->GetAdapter(&adapter);
if (SUCCEEDED(hr))
{
hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );
adapter->Release();
}
dxgiDevice->Release();
}
}
if (FAILED(hr))
return hr;
// 2.Create swap chain
IDXGIFactory2* dxgiFactory2 = nullptr;
hr = dxgiFactory->QueryInterface( __uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2) );
if ( dxgiFactory2 )
{
// DirectX 11.1 or later
hr = g_pd3dDevice->QueryInterface( __uuidof(ID3D11Device1), reinterpret_cast<void**>(&g_pd3dDevice1) );
if (SUCCEEDED(hr))
{
(void) g_pImmediateContext->QueryInterface( __uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&g_pImmediateContext1) );
}
DXGI_SWAP_CHAIN_DESC1 sd;
ZeroMemory(&sd, sizeof(sd));
sd.Width = width;
sd.Height = height;
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
hr = dxgiFactory2->CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1 );
if (SUCCEEDED(hr))
{
hr = g_pSwapChain1->QueryInterface( __uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain) );
}
dxgiFactory2->Release();
}
else
{
// DirectX 11.0 systems
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
hr = dxgiFactory->CreateSwapChain( g_pd3dDevice, &sd, &g_pSwapChain );
}
// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
dxgiFactory->MakeWindowAssociation( g_hWnd, DXGI_MWA_NO_ALT_ENTER );
dxgiFactory->Release();
if (FAILED(hr))
return hr;
// 3.Create a render target view
ID3D11Texture2D* pBackBuffer = nullptr;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &pBackBuffer ) );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
// 4.Create depth stencil texture
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = width;
descDepth.Height = height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = g_pd3dDevice->CreateTexture2D( &descDepth, nullptr, &g_pDepthStencil );
if( FAILED( hr ) )
return hr;
// 5.Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
// 6.Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)width;
vp.Height = (FLOAT)height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
// 7.Compile and create the vertex shader. Define, create and set the input layout at the same time.
// 7.1.Compile the vertex shader
ID3DBlob* pVSBlob = nullptr;
hr = CompileShaderFromFile( L"lighting.fx", "VS", "vs_5_0", &pVSBlob );
if( FAILED( hr ) )
{
MessageBox( nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// 7.2.Create the vertex shader
hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return hr;
}
// 7.3.Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },// 12是对齐字节位移,前一个元素是XMFLOAT3,大小3 * sizeof(XMFLOAT3) = 12,为了方便可用D3D11_APPEND_ALIGNED_ELEMENT可以代替12
};
UINT numElements = ARRAYSIZE( layout );
// 7.4.Create the input layout
hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &g_pVertexLayout );
pVSBlob->Release();
if( FAILED( hr ) )
return hr;
// 7.5.Set the input layout
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );
// 8.Compile and create the pixel shader
// 8.1.Compile the pixel shader
ID3DBlob* pPSBlob = nullptr;
hr = CompileShaderFromFile( L"lighting.fx", "PS", "ps_5_0", &pPSBlob );
if( FAILED( hr ) )
{
MessageBox( nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// 8.2.Create the pixel shader
hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return hr;
// 9.Create and set vertex buffer
// 9.1.Create vertex buffer
VertexNormal source[12] =
{
{XMFLOAT3(1, 0, 0), XMFLOAT3()},
{XMFLOAT3(0, 0, 1), XMFLOAT3()},
{XMFLOAT3(-1, -1, 0), XMFLOAT3()},
{XMFLOAT3(-1, 1, 0), XMFLOAT3()},
{XMFLOAT3(0, 0, 1), XMFLOAT3()},
{XMFLOAT3(1, 0, 0), XMFLOAT3()},
{XMFLOAT3(-1, -1, 0), XMFLOAT3()},
{XMFLOAT3(0, 0, 1), XMFLOAT3()},
{XMFLOAT3(-1, 1, 0), XMFLOAT3()},
{XMFLOAT3(-1, -1, 0), XMFLOAT3()},
{XMFLOAT3(-1, 1, 0), XMFLOAT3()},
{XMFLOAT3(1, 0, 0), XMFLOAT3()},
};
// 赋予各个面单位化外法向量
for (int i = 0; i < 4; i++)
{
XMVECTOR v01 = XMLoadFloat3(&source[3 * i + 1].Pos) - XMLoadFloat3(&source[3 * i].Pos);
XMVECTOR v02 = XMLoadFloat3(&source[3 * i + 2].Pos) - XMLoadFloat3(&source[3 * i].Pos);
XMVECTOR normal = XMVector3Normalize(XMVector3Cross(v01, v02));
for (int j = 0; j < 3; j++)
{
XMStoreFloat3(&source[3 * i + j].Normal, normal);
}
}
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( VertexNormal ) * 12;// 顶点数
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = source;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
//delete pVertices;
if( FAILED( hr ) )
return hr;
// 9.2.Set vertex buffer
UINT stride = sizeof( VertexNormal );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// 10.Create and set index buffer
// We don't need this step in this example, because the vertices are sorted to be clockwise already.
// 10.1.Create index buffer
// 10.2.Set index buffer
// 11.Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
// 12.Create the constant buffer
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
hr = g_pd3dDevice->CreateBuffer( &bd, nullptr, &g_pConstantBuffer );
if( FAILED( hr ) )
return hr;
// 13.Initialize the world matrix, view matrix, projection matrix
g_World = XMMatrixIdentity();
XMVECTOR eye = XMVectorSet(-5.0f, 0.0f, 3.0f, 1.0f);
XMVECTOR focus = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
XMVECTOR up = XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f);
g_View = XMMatrixLookAtLH(eye, focus, up);
float nearZ = 0.01f;
float farZ = 500.0f;
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, nearZ, farZ );
return S_OK;
}
void Render()
{
static DWORD t0 = GetTickCount();
DWORD t1 = GetTickCount();
float t = (t1 - t0) / 1000.0f;
ConstantBuffer cb = {};
cb.mWorld = XMMatrixTranspose(g_World * XMMatrixRotationZ(2.0f * XM_PI / 3.0f * t));// 周期3s
cb.mView = XMMatrixTranspose(g_View);
cb.mProjection = XMMatrixTranspose(g_Projection);
cb.vLightDir[0] = XMFLOAT4(0.0f, -1.0f, 0.5f, 1.0f);
cb.vLightDir[1] = XMFLOAT4(0.0f, 1.0f, 0.5f, 1.0f);
XMStoreFloat4(&cb.vLightColor, Colors::White);
g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, Colors::Black);// 清屏
g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);// 清depth stencil view
g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pConstantBuffer);
g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb, 0, 0);// ID3DBuffer继承于ID3DResource,一个更新一个draw
g_pImmediateContext->Draw(12, 0);// 如果用了索引缓存,用DrawIndexed()
g_pSwapChain->Present(1, 0);// 第一个参数调节刷新率
}
// 初始化窗口
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
// Register class
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_APPLICATION );
wcex.hCursor = LoadCursor( nullptr, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"class1";
wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_APPLICATION );
if( !RegisterClassEx( &wcex ) )
return E_FAIL;
// Create window
g_hInst = hInstance;
RECT rc = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };
AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
g_hWnd = CreateWindow( L"class1", L"简单四面体方向光渲染",
WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,
nullptr );
if( !g_hWnd )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
return S_OK;
}
void CleanupDevice()
{
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
if( g_pConstantBuffer ) g_pConstantBuffer->Release();
if( g_pVertexBuffer ) g_pVertexBuffer->Release();
//if( g_pIndexBuffer ) g_pIndexBuffer->Release();
if( g_pVertexLayout ) g_pVertexLayout->Release();
if( g_pVertexShader ) g_pVertexShader->Release();
//if( g_pPixelShaderSolid ) g_pPixelShaderSolid->Release();
if( g_pPixelShader ) g_pPixelShader->Release();
if( g_pDepthStencil ) g_pDepthStencil->Release();
if( g_pDepthStencilView ) g_pDepthStencilView->Release();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain1 ) g_pSwapChain1->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pImmediateContext1 ) g_pImmediateContext1->Release();
if( g_pImmediateContext ) g_pImmediateContext->Release();
if( g_pd3dDevice1 ) g_pd3dDevice1->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
// 回调函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
{
if (wParam == VK_ESCAPE)
{
PostQuitMessage(0);
}
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
// 从文件编译着色器,由微软官网例子提供
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
// Disable optimizations to further improve shader debugging
dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
ID3DBlob* pErrorBlob = nullptr;
hr = D3DCompileFromFile( szFileName, nullptr, nullptr, szEntryPoint, szShaderModel,
dwShaderFlags, 0, ppBlobOut, &pErrorBlob );
if( FAILED(hr) )
{
if( pErrorBlob )
{
OutputDebugStringA( reinterpret_cast<const char*>( pErrorBlob->GetBufferPointer() ) );
pErrorBlob->Release();
}
return hr;
}
if( pErrorBlob ) pErrorBlob->Release();
return S_OK;
}
效果图: