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



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

 

建立window:参见上例。

 

建立Direct3D11 device

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

 

 

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

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

1.adevice

2.animmediate context

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 能够渲染之前,我们还需要做最后一件事情,就是初始化viewport viewport 映射到空间坐标的时候,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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值