DirectX 11 SDK文档(二)

DirectX 11 SDK文档(二)_第1张图片

总结

     这是第一个教程,我们将通过必要的元素来创建一个小型的DirectX 11应用程序。每个DirectX 11应用程序必须拥有这些元素得以正常运转。这些元素包括创建一个窗口对象和设备对象,并且能够显示一种颜色的窗口。

创建DirectX 11 设备

      创建窗口对象和消息循环请参见DirectX 11 SDK文档(一)。现在我们有一个能够显示的窗口,接下来我们能够创建Direct3D 11 设备。如果我们要渲染3D的场景,创建设备是必须的。第一件事要做的就是创建以下三个对象:device,immediate context,swap chain。immediate context在Direct3D 11 是一个新的对象。

      在Direct3D 10中device对象被用来渲染场景和创建资源。在Direct3D 11中immediate context被应用程序用来将场景渲染到缓冲区里,而device有很多创建资源的函数。

      swap chain负责交换device渲染的场景所存放缓冲区,并且能够将要显示的内容呈现在屏幕上。swap chain将包含两个或更多的缓冲区,主要包含前景缓冲区和背景缓冲区。前景缓冲区就是用户当前在屏幕上所看到的。前景缓冲区是只读,并且不能被修改。背景缓冲区就是device所渲染场景的目标位置。一旦完成了绘制操作,swap chain通过交换两个缓冲区将背景缓冲区的内容呈现在屏幕上。这时背景缓冲区变成了前景缓冲区,而前景缓冲区变成了背景缓冲区。

      为了创建swap chain,我们填充一个DXGI_SWAPCHAIN_DESC结构体,DXGI_SWAPCHAIN_DESC结构体描述了我们要创建swap chain的对象属性。DXGI_SWAPCHAIN_DESC结构体的变量虽然多,但是我们只要关心一小部分就可以了。BackBufferUsage标记应用程序将如何使用背景缓冲区。在这个例子中,我们要渲染这个背景缓冲区,所以我们将BackBufferUsage赋值为DXGI_USAGE_RENDER_TARGET_OUTPUT。OutputWindow代表窗口,该窗口是swap chain将图像呈现的区域。SampleDesc用来支持多采样,既然这个例子备没有使用多采样,所以将SampleDesc.Count=1,SampleDesc.Quality=0。

      一旦DXGI_SWAPCHAIN_DESC结构体被填好,我们就可以调用D3D11CreateDeviceAndSwapChain()函数为我们创建device 和 swap chain。代码如下:

      DXGI_SWAP_CHAIN_DESC sd;
      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 11是resource view的一种类型。在特定的阶段,resource view允许一个资源受graphics pipeline绑定。resource views是C中声明的类型,是一个大块的raw memory将应用于任何的数据类型。我们能够在resource views中将大块的raw memory用于定义一个整数数组,一个浮点数数组,一个结构体,一个结构体数组,等等。如果我们不知道raw memory的数据类型,那么它对我们来讲是没有用处的。Direct3D 11的resource views与之类似。目前为止,一个2D的纹理保存方式与raw memory类似,也是一个潜在的raw resource。一旦我们有了这个资源,我们就可以在graphics pipeline的不同阶段创建不同的resource views,数据格式类型如下:作为渲染目标,作为深度模板缓冲区来接受深度信息,或者作为纹理资源。在C中的声明中允许一个内存块以不同的方式使用,resource views也是如此。

      我们需要创建一个render target view,因为我们需要将它绑定到swap chain后背缓冲区,作为渲染目标。所以Direct3D 11能够将渲染的场景写入缓冲区。我们可以调用GetBuffer()函数来获得背景缓冲区对象。选择性的,我们可以选择填充一个描述render target view的D3D11_RENDERTARGETVIEW_DESC结构体来创建render target view。这个描述通常是CreateRenderTargetView()函数的第二个参数。然而,在这个教程,创建一个默认的render target view就够了,所以第二个参数传NULL。一旦我们创建了默认的render target view,我们就可以调用immediate context对象的OMSetRenderTargets()函数,就可以将render target view绑定到pipeline。这个确保了pipeline渲染的场景内容输出到背景缓冲区。代码如下:

      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能够渲染之前,我们需要初始化一下视图。这个视图用于映射空间坐标系。这个视图的X,Y在[-1,1],Z在[0,1]
用于渲染目标空间,有时就是所谓的像素空间。在Direct3D 9中,如果应用程序没有设置视图,就会默认一个和渲染目标大小相等的视图。在Direct3D 11中没有默认的视图,所以我们必须想在屏幕上看到东西之前设置视图。既然我们要使用整个渲染目标作为输出,我们设置左上角的点是(0,0),并且宽高设置成与渲染目标相等。代码如下:

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

修改消息循环

      我们已经创建了窗口和Direct3D 11 device,并且我们为渲染做好了准备。然而,在我们的消息循环代码里仍然有个问题:它使用 GetMessage()函数来获取消息。如果应用程序窗口的消息队列内没有消息,GetMessage()函数阻塞程序不会返回,直到消息队列内有消息。以至于在消息队列为空的时候我们的应用程序不得不等待,在此期间我们不能进行渲染操作。我们可以用PeekMessage()函数来代替GetMessage()来解决这个问题。PeekMessage()检索消息的操作与GetMessage()一样,但是当消息队列内没有消息时不会等待,而是直接返回。我们可以利用这个时间来做一些渲染操作。代码修改如下:

      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()方法将渲染目标填充成一种颜色。第一,我们要定义一个长度为四的浮点数组来表示填充在屏幕上的颜色。Present()函数负责把swap chain中背景缓冲区的内容显示在屏幕上,以至于我们能看到。代码如下:

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

你可能感兴趣的:(DirectX 11 SDK文档(二))