【DirectX 11 SDK 学习笔记】Direct3D 11 Basics

来源:互联网 发布:中房网端口能不能退 编辑:程序博客网 时间:2024/06/05 11:31


在这个例子中,将要学习创建一个最小的Direct3D应用的基本元素,这些都是基本的功能属性,包括建立一个窗口和device对象,并且在窗口上显示颜色。

 

建立window:参见上例。

 

建立Direct3D11 device

创建窗口和消息循环的初始步骤在Direct3D9Direct3D10,和Direct3D11中都是一样的。

 

 

目前,我们有一个可以显示的window了,能够继续创建Direct3D11 device。如果我们要进行渲染,这一步是必须的。

第一步就是创建3个对象:

1.adevice

2.animmediatecontext

3.a swapchain

其中,immediate contextDirect3D 11 中新加的对象。

 

Direct10中,device对象被用来执行渲染和创建资源。在DirectX11中,这个程序通常通过immediatecontext来执行buffer上的渲染,而且,device中含有很多用来创建资源的函数。swap chain负责将buff数据传送到设备渲染器,而且将内容显示在真正的显示器屏幕上面。

 

通常swap chain包含两个或两个以上的buffer,其中最主要和最重要的是front bufferback buffer,里面存放的是设备渲染器要按顺序渲染到屏幕上的纹理数据。front buff是正在呈现给用户的数据,就是看见的每一帧哦~而且这个front buffer是只读,不能被修改。back buffdevice绘图的渲染目标,一旦完成绘图操作,swap chain将交换这两个bufferback buffer变成front buffer,然后将交换后的front buffer呈现给用户。

 

如果要创建swap chain,我们首先要填充DXGI_SWAPCHAIN_DESC 结构体,这个结构体是用来描述我们所创建的swap chain,这里有几个值得注意的地方:

BackBufferUsage这个标记告诉应用back buffer将如何使用,如果我们想要渲染back buffer,在这种情况下,我们将这个标记设置为DXGI_USAGE_RENDER_TARGET_OUTPUT

OutputWindow表示swap chain将用来显示图像到屏幕上的窗口。

SampleDesc 用来开启multi-sampling。由于本例没有使用multi-sampling,所以SampleDesc.Count=1SampleDesc.Quality= 0 multi-sampling功能关闭。

 

一旦DXGI_SWAPCHAIN_DESC结构体填充完成,我们可以调用D3D11CreateDeviceAndSwapChain函数来创建deviceswap chain。下面是创建代码:

 

DXGI_SWAP_CHAIN_DESCsd;
    ZeroMemory( &sd, sizeof(sd));
    sd.BufferCount = 1;
    sd.BufferDesc.Width = 640;
    sd.BufferDesc.Height =480;
    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;

if(FAILED( D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0,featureLevels, numFeatureLevels,D3D11_SDK_VERSION, &sd, &g_pSwapChain

,&g_pd3dDevice, NULL, &g_pImmediateContext ) ) )
    {
        return FALSE;
    }

 

接下来,我们需要创建render target view。它是Direct3D 11resource view的一种。Resource view能够让 resource绑定在图形管线上的特定阶段。假若 resource viewC类型,一块在C类型的内存空间中的raw memory能够被转化为任何数据类型,整型数组,浮点数组,结构体,结构体数组等等。如果我们不知道raw memory的类型,它对于我们其实没什么用。Direct3D11 resource也是类似这样来转换的。例如,一个2D texture,类似于一个rawmemory,是原始底层资源,一旦我们拥有了这样的资源,我们可以创建不同的 resource view来绑定这个texture到不同的渲染管线阶段,将texture转换为不同的格式:作为将要渲染的render target,转换为能接受深度信息的depth stencil buffer ,或者作为texture resource,正如C类型能够允许memory chunk通过不同的方式来使用Direct3D 11 resource views也是一样。

 

之所以我们要创建render target view,是因为我们想将swap chainback buffer作为渲染目标。这样能够允许 Direct3D 11 在之上进行渲染。首先,我们通过调用GetBuffer()来得到back buffer对象,也可以通过填充D3D11_RENDERTARGETVIEW_DESC来描述将要创建的targetview。通常是CreateRenderTargetView的第二个参数。然而,对于这些教程,使用默认的target view就可以满足需求了,可以通过传递NULL参数来获得默认 target view。若我们已经创建了render target view,我们可以通过immediatecontext接口调用OMSetRenderTargets()来将它绑定到pipeline.这样能够保证pipeline的渲染输出能够写入到back buffer

下面是创建和设置render target view的代码:

 // Create a rendertarget view
    ID3D11Texture2D*pBackBuffer;
    if( FAILED(g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ),(LPVOID*)&pBackBuffer ) ) )
        return FALSE;
    hr =g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL,&g_pRenderTargetView );
    pBackBuffer->Release();
    if( FAILED( hr ) )
        return FALSE;
   g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView,NULL );

 

direct3d 11 能够渲染之前,我们还需要做最后一件事情,就是初始化viewportviewport映射到空间坐标的时候,xy的范围从-11,z范围从01,为了渲染一个目标空间,像总所周知的像素空间。在Direct3D 9中,如果应用程序没有建立viewport,将会创建一个和render target尺寸一样的默认viewport。在Direct3D11中,没有默认的viewpoint。所以,在我们能够看到屏幕上的任何东西之前,我们要创建一个viewport。假若我们想要渲染全部输出窗口,我们可以将左上角设置为 (0 , 0),长和宽设置和渲染目标一致。示例代码如下:

D3D11_VIEWPORTvp;
    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 );

修改消息循环:

我们已经建立好了窗口和Direct3D 11 device,而且我们已经准备好渲染了,但是消息循环还有一个问题,它用GetMessage()来获取消息,这个函数的问题在于应用程序窗口队列里面没有消息,会一直阻塞不返回,直到有可以获取的消息出现。所以,如果我们的消息队列是空的,我们的程序会一直等待消息,而不是执行渲染动作。解决方法很简单,只需要用PeekMessage()代替GetMessage()PeekMessage()具有和GetMessage()一样检索消息功能,但是不会等待消息,PeekMessage()会立即返回结果而不是像GetMessage()会阻塞。我们可以把这点时间利用起来进行渲染。修改后的消息队列,使用PeekMessage()看起来是这样的:

    MSG msg = {0};
    while( WM_QUIT != msg.message)
    {
        if( PeekMessage( &msg, NULL,0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg);
            DispatchMessage( &msg);
        }
        else
        {
            Render();  // Do some rendering
        }
    }

渲染代码:

本例中的渲染代码是在Render()函数中调用执行的,渲染最简单的场景,只是将屏幕填充为单一颜色。在Direct3D 11 中,有一个简单的方法来用单色填充渲染目标,就是调用immediate context接口中的ClearRenderTargetView()方法。首先,我们定义一个四个float的数组来描述我们要填充到屏幕的颜色,接下来就是将它传递给ClearRenderTargetView()。在这个例子中,我们选择了一个暗蓝色,一旦我们填充好了back buffer,我们可以调用swap chainPresent()函数来结束渲染。Present()负责将swap chain backbuffer的内容呈现到屏幕上,这样,用户就能看见了。

Render()是长这个样子的:

  void Render()
    {
        //
        // Clear the backbuffer
        //
        float ClearColor[4] = { 0.0f,0.125f, 0.6f, 1.0f }; // RGBA
       g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor);
   
        g_pSwapChain->Present( 0, 0);
    }



编码调试:


缺少头文件和lib库:


解决方法:


1.include头文件和lib目录



2.加入依赖库


d3d11.lib


d3dcompiler.lib


d3dx11d.lib


dxerr.lib


dxguid.lib


运行效果:



程序流程:


1.进入wWinMain函数


2.调用InitWindow函数,初始化窗口,在该函数中调用主要的RegisterClassEx,CreateWindowShowWindow函数,将生成的hwnd保存在   g_hWnd中。通过wcex.lpfnWndProc = WndProc;来指定函数WndProc为窗口过程函数。由于windows的程序流程很复杂,在初始化的时候无法跟踪,只能大致了解流程,这些是windows比较底层核心的流程.可以跳过.


3.设置的断点特别注意一定要在ShowWindow处设置断点,否则会看不清流程。



执行流程:


先进入wWinMain函数,执行其中的InitWindow,然后跳回来执行InitDevice,然后进入修改过的消息循环,可以看到不停的PeekMessage,当队列为空的时候,执行Render();


0 0
原创粉丝点击