由于要做directx方面的东西,所以今天开始学习directx。
硬件环境:Win7 X64
软件环境:directx sdk(DXSDK_Jun10)+VS2010
参考资料:direct documentations for C++
例程:Tutorial01(sdk自带)
代码:见附录
代码效果:
学习过程:
首先说明要创建的三个必须objects:a device, an immediate context, and a swapchain.
然后分别说明三个objects的作用:
the device object was used to perform both rendering andresource creation.
the immediate context is used by the application to performrendering onto a buffer, and the device contains methods to createresources.
The swap chain is responsible for taking the buffer to which thedevice renders, and displaying the content on the actual monitorscreen.
其中在swap chain作用介绍中提到了backbuffer和frontbuffer,swapchain主要就是用来操纵这两个buffer。
提到了要用到的:
structure:
DXGI_SWAPCHAIN_DESC
flag:
BackBufferUsage -> a flag thattells the application how the back buffer will be used.
并说明,由于我们这个例子中要渲染的是backbuffer,可以将BackBufferUsage设置为DXGI_USAGE_RENDER_TARGET_OUTPUT。
看代码我们知道
一共有四个过程函数和一个wWinMain函数(这里定义和声明都在cpp文件中),当然从wWinMain开始看
看wWinMain就知道函数结构了,相当清晰
先创建句柄hPrevInstance和lpCmdLine。
然后调用InitWindow,InitDevice,初始化失败调用CleanupDevice直接返回。初始化成功则开启消息循环,当
程序退出时再调用CleanupDevice正常结束。
结合文档分析:
1:
Once the description has been filled out, we can call theD3D11CreateDeviceAndSwapChain function to create both thedevice and the swap chain for us.
可以知道先填充一个DXGI_SWAP_CHAIN_DESC 类型的sd,然后调用D3D11CreateDeviceAndSwapChain
就可以创建device and the swap chain。这个部分例子是在InitDevice函数中实现的。
2:
然后需要创建一个a render targetview,渲染视图,这个东西是用来解释资源的。做过C++的知道,当内存中存有一定的数据,按不同方式解释出的结果是不同的。比如同样是11111111这样一个字节,按unsingedint类型解释和int类型解释出来的值就不同。这个东西的功能和这个类似(视图嘛是吧,应该很好理解,就是说从不同的角度去看,去解释同样的资源啊)。
3:
然后初始化一个D3D11_VIEWPORT 类型的vp。网上翻译为视口
查找msdn可以知道这个东西
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476260(v=vs.85).aspx
是与视角坐标系有关的一个东西,猜测可能与视角深度的应用,比如透视等的实现有关系,这个东西在11和10中的支持不同。
4:
然后就构建一个消息循环,如果获取到什么消息就去处理消息,否则一直不停地渲染界面。这里用非足赛方式的函数PeekMessage()来等待消息,用GetMessage()的话会阻塞的。
5.渲染函数,这里例子程序只是最简单地向屏幕填充一种颜色,在Directx11中,用ClearRenderTargetView()可以很轻松地实现对目标的渲染。不过文档中说当我们填充完backbuffer,就调用Present()去完成渲染,由
http://msdn.microsoft.com/en-us/library/windows/desktop/bb173539(v=vs.85).aspx
可知它的作用是
Set all the elements in a render target to one value.
即把目标的所有元素设置成一个值。这里用来把窗口的工作区颜色都设置成蓝色,就是说定义了一个颜色点,可以用这个这个函数把这个颜色点的性质应用到对象的所有元素上。链接还讲了一个不宜使用的情况,自己看。
整个程序就是这样。
展示了一个最基本的directx11程序。
这不过是本人的学习笔记。
有人描述的比较专业,理解也比本人深刻,更值得大家参考,可以看看:
http://www.cnblogs.com/xdotnet/archive/2011/07/15/directx11_cpp_device.html
同时把代码也附在后面,其实代码在directx11的sdk文档及例程中都有的,在官网上下载一个directx11的sdk一安装,资料就全都有了,暂时学这个要看英语能力了。
附录:
//--------------------------------------------------------------------------------------
// File: Tutorial01.cpp
//
// This application demonstrates creating a Direct3D 11device
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include "resource.h"
//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCEg_hInst = NULL;
HWNDg_hWnd = NULL;
D3D_DRIVER_TYPEg_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVELg_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*g_pd3dDevice = NULL;
ID3D11DeviceContext*g_pImmediateContext = NULL;
IDXGISwapChain*g_pSwapChain = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULTCALLBACKWndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes intoa message processing
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPWSTR lpCmdLine, int nCmdShow )
{
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
if(FAILED( InitWindow( hInstance, nCmdShow ) ) )
return 0;
if( FAILED(InitDevice() ) )
{
CleanupDevice();
return 0;
}
// Mainmessage loop
MSG msg ={0};
while(WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
CleanupDevice();
return 0;
// return ( int)msg.wParam;
}
//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
// Registerclass
WNDCLASSEXwcex;
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_TUTORIAL1 );
wcex.hCursor= LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"TutorialWindowClass";
wcex.hIconSm= LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
if(!RegisterClassEx( &wcex ) )
return E_FAIL;
// Createwindow
g_hInst =hInstance;
RECT rc = {0, 0, 900, 480 };
//计算需要创建的客户区窗口大小
//第二个参数决定窗口的样式
//第三个参数决定窗口是否有菜单
AdjustWindowRect( &rc,WS_OVERLAPPEDWINDOW, FALSE );
g_hWnd =CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 1:Direct3D 11 Basics", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom -rc.top, NULL, NULL, hInstance,
NULL );
if( !g_hWnd)
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
returnS_OK;
}
//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam,LPARAM lParam )
{
PAINTSTRUCTps;
HDC hdc;
switch(message )
{
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return0;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr =S_OK;
RECTrc;
GetClientRect( g_hWnd, &rc );
UINT width =rc.right - rc.left;
UINT height= rc.bottom - rc.top;
UINTcreateDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
//创建下面这个数组的目的是为了定义一些可能用到的驱动类型和SDK支持版本等级
//后面还有个循环,用来一个一个试,看到底是哪种驱动,采用这种方式,
//从而可以使代码在各种可能驱动环境下都可以用
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINTnumDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels);
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;
for( UINTdriverTypeIndex = 0; driverTypeIndex <numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL,createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd,&g_pSwapChain, &g_pd3dDevice,&g_featureLevel,&g_pImmediateContext );
if(SUCCEEDED( hr ) )
break;
}
if(FAILED(hr ))
return hr;
// Createa render target view
ID3D11Texture2D* pBackBuffer = NULL;
//绑定buffer和交换链
hr =g_pSwapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if(FAILED(hr ))
return hr;
//为资源数据创建一个渲染视图
//第一个参数指向一个ID3D11Resource 类型的着色目标
//第二个参数指向一个D3D11_RENDER_TARGET_VIEW_DESC类型的结构,这个用来描述访问资源的方式
//第三个参数指向一个视图,
hr =g_pd3dDevice->CreateRenderTargetView( pBackBuffer,NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED(hr ) )
return hr;
//将渲染目标和buffer绑定到OMstage,这个决定最后哪些像素点是可见的
g_pImmediateContext->OMSetRenderTargets( 1,&g_pRenderTargetView, NULL );
// Setupthe 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 );
returnS_OK;
}
//--------------------------------------------------------------------------------------
// Render the frame
//--------------------------------------------------------------------------------------
void Render()
{
// Justclear the backbuffer
floatClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f };//red,green,blue,alpha
//将渲染目标的每一个元素都设置为同一个值,类似于纹理映射
g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor );
g_pSwapChain->Present(0, 0 );
}
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
//将视图,交换链,上下文以及设备都释放
if(g_pImmediateContext )g_pImmediateContext->ClearState();
if(g_pRenderTargetView )g_pRenderTargetView->Release();
if(g_pSwapChain ) g_pSwapChain->Release();
if(g_pImmediateContext )g_pImmediateContext->Release();
if(g_pd3dDevice ) g_pd3dDevice->Release();
}