zoukankan      html  css  js  c++  java
  • Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础

    Github-LearnDirectX-DX3D11 tutorial01

    概述

    在这第一篇教程中,我们将通过介绍创建最小Direct3D应用程序所必需的元素。每一个Direct3D应用程序必需拥有这些元素才能正常地工作。这些元素包括设置窗口和设备对象,以及在窗口上显示颜色。

    资源目录

    (SDK root)SamplesC++Direct3D11TutorialsTutorial01

    设置Direct3D 11 设备

    第一步是创建一个窗口和消息循环,这些在Direct3D 9, Direct3D 10, 和Direct3D 11都是相同的。有关此过程的介绍,请参阅Direct3D 10教程00:Win 32 Basics。现在我们有了一个正在显示的窗口,我们可以继续设置一个Direct3D 11设备。如果我们将要渲染任何3D场景,设置这个是有必要的。首先要做的是创建三个对象:一个设备(device),一个直接的上下文(immediate context),一个交换链(swap chain)直接上下文是Direct3d 11中的一个新对象。

    在Direct3D 10中,设备对象用于执行渲染和资源的创建。在Direct3D 11中,应用程序使用直接上下文对缓冲区执行渲染,设备中包含创建资源的方法。

    交换链负责接收设备渲染的缓冲区,并在实际监视器屏幕上显示内容。交换链包含两个或多个缓冲区,主要是前面和后面。这些纹理是设备为了在监视器上显示而呈现的纹理。前台缓冲区是当前呈现给用户的内容。这个缓冲区是只能读,不能做修改。后台缓冲区是设备将要绘制的渲染目标。一旦设备完成了绘图操作,交换链将通过交换两个缓冲区来显示后台缓冲区。此时后台缓冲区变成了前台缓冲区,反之亦然。

    为了创建交换链,我们填写 DXGI_SWAPCHAIN_DESC 结构来描述我们即将创建的交换链。有一些字段值得一提。BackBufferUsage是一个标志,它告诉应用程序如何使用后台缓冲区。 在这种情况下,我们想要渲染到后台缓冲区,因此我们将 BackBufferUsage 设置为 DXGI_USAGE_RENDER_TARGET_OUTPUT。OutputWindow字段表示交换链将用于在屏幕上显示图像的窗口。SampleDesc用于启用多次采样。 由于本教程不使用多次采样,因此SampleDesc的Count设置为1,Quality设置为0以禁用多次采样。

    填写完描述后,我们可以调用D3D11CreateDeviceAndSwapChain函数为我们创建设备和交换链。以下是创建设备和交换链的代码:

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

      

    接下来我们要做的事情是创建一个渲染目标的视图。

    渲染目标视图是Direct3D 11里的一种资源视图。资源视图允许资源在特定场合绑定到图形管道上。将资源视图看成是C语言中的类型转换。C中的一块原始内存可以转换为任何数据类型。我们可以将这块内存转换为整数数组,浮点数组,结构数组,结构数组等等。如果我们不知道它的类型,原始内存本身对我们没有太大用处。Direct3D 11中的资源视图与该方法类似。例如,一个2D纹理,类似于原始内存块,是原始的底层资源。一旦我们拥有了该资源,我们就可以创建不同的资源视图,将该纹理绑定到不同格式的图形管道中的不同阶段:作为要渲染的渲染目标,作为将接收深度信息的深度模板缓冲区,或作为纹理资源。在C语言类型转换中允许以不同的方式使用内存块的情况下,Direct3D 11资源视图也是如此。

    我们需要创建一个渲染目标视图,因为我们想将交换链中的后台缓冲区绑定为我们的渲染目标。这样能够使Direct3D 11渲染到它上面。我们首先调用GetBuffer()来获取后台缓冲区对象。或者,我们可以填写D3D11_RENDERTARGETVIEW_DESC结构,该结构描述要创建的渲染目标视图。此描述通常是CreateRenderTargetView的第二个参数。然而,对于这些教程,默认的渲染目标视图已经足够了。可以通过传递NULL作为第二个参数来获取默认的渲染目标视图。一旦我们创建了渲染目标视图,我们就可以在直接上下文中调用OMSetRenderTargets()来将它绑定到管道上。这可确保管道呈现的输出被写入后台缓冲区。创建和设置渲染目标视图的代码如下:

     // Create a render target 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渲染之前我们需要设置的最后一件事是初始化视口。

    视口映射剪辑空间坐标,其中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设备并且我们已准备好渲染。 但是,我们的消息循环仍然存在问题:它使用GetMessage()来获取消息。GetMessage()的问题在于,如果应用程序窗口的队列中没有消息,则GetMessage()会阻塞,并且在消息可用之前不会返回。因此,当消息队列为空时,我们的应用程序在GetMessage()内等待,而不是像渲染那样。我们可以使用PeekMessage()而不是GetMessage()来解决这个问题。 PeekMessage()可以检索像GetMessage()那样的消息,但是当没有消息等待时,PeekMessage()会立即返回而不是阻塞。 然后我们可以花时间做一些渲染。 使用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中,使用单一颜色填充渲染目标的简单方法是使用直接上下文的ClearRenderTargetView()方法。

    • 首先,我们定义一个由四个浮点数组成的数组,用于描述我们想要填充屏幕的颜色。
    • 接着,我们将它传递给ClearRenderTargetView()。在这个例子中,我们选择了蓝色的阴影。
    • 填充后台缓冲区后,我们调用交换链的Present()方法来完成渲染。 Present()负责将交换链的后台缓冲区内容显示在屏幕上,以便用户可以看到它。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 );
        }
    

      

    本教程最终的运行效果:

    小结

    本教程是我在学习DirectX中查看SDK文档中看到的,因此想在国庆期间翻译成中文,方便以后查阅。

    教程总共有七篇:

    希望翻译过的教程能对学习DX的朋友们有所帮助,本教程的源码我已上传至Github(在本文首部)。

  • 相关阅读:
    Java基础笔记(九)—— 流程控制
    Java基础笔记(七)—— 成员变量、静态变量、局部变量
    Java基础笔记(六)——进制表示、ASCII码和Unicode编码
    Java基础笔记(五)——数据类型转换
    Java基础笔记(四)——命名规则、数据类型
    java基础笔记(三)——main方法
    Java基础笔记(二)——配置环境变量
    原始生物 题解
    Ant Trip 题解
    叶子清除计划【第五周】 题解
  • 原文地址:https://www.cnblogs.com/OctoptusLian/p/9729605.html
Copyright © 2011-2022 走看看