精华内容
下载资源
问答
  • Direct3D教程

    2011-11-02 09:07:58
    包含几个中文版的Direct3D教程,教程通俗易懂,并附有实例代码
  • c# direct3D教程

    热门讨论 2012-08-30 18:01:23
    c# direct3D教程
  • Direct3D教程+例子源代码.zip
  • Direct3D教程c#版

    2013-08-13 09:51:24
    这是一个pdf格式的关于Direct3D的C#版的简明教程,简单易懂,只是缺少骨骼动画教程
  • 另一个Direct3D框架,这一次用于MFC应用程序,其中包含分步教程
  • 在DX9环境下的完整的Direct3D基础编程源代码 可以让你掌握3D的世界
  • Direct3D 11 教程1:Direct3D 11基础

    千次阅读 2014-04-23 15:18:36
    在第一个教程中,我们学习了创建一个最小Direct3D 11应用程序所需的元素,每个Direct3D 11应用程序必须包含这些元素才能正常工作,这些元素包括创建一个窗口和设备对象,然后才能在窗口中显示颜色。 源代码 ...

    概览

    在第一个教程中,我们学习了创建一个最小Direct3D 11应用程序所需的元素,每个Direct3D 11应用程序必须包含这些元素才能正常工作,这些元素包括创建一个窗口和设备对象,然后才能在窗口中显示颜色。

    程序截图

    源代码

    (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial01。

    创建Direct3D 11设备

    第一个步骤中的创建窗口和消息循环在Direct3D 9、Direct3D 10、Direct3D 11都是相同的,可参见Direct3D 10教程0:Win32编程基础理解这个过程。当显示了一个窗口后,下面继续创建一个Direct3D 11设备,这个设备用于绘制3D场景。首先必须创建三个对象:一个设备、一个立即执行上下文(immediate context)和一个交换链(Swap Chain),立即执行上下文对象是Direct3D 11中新添加的。

    在Direct3D 10中,设备同时用来绘制和资源的创建。在Direct3D 11中,立即执行上下文用于将内容绘制到缓存,而设备用于创建资源。

    当显示了一个窗口后,下面继续创建一个Direct3D 11设备,这个设备用于绘制3D场景。首先必须创建两个对象:一个设备和一个交换链(Swap Chain)

    设备对象用于将内容绘制在一个缓冲中,设备还包含创建资源的方法。

    交换链即表示对缓冲的操作,这些缓冲就是设备绘制的和显示在屏幕上的内容。交换链包含两个或两个以上的缓冲,主要是前缓冲和后备缓冲,它们就是设备绘制形成的纹理,用于显示在屏幕上。前缓冲(front buffer)就是当前显示在屏幕上的内容,这个缓冲是只读的,无法修改。后备缓冲(back buffer)是设备将要绘制的渲染目标,一旦它完成了绘制操作,交换链就会通过交换前缓冲和后备缓冲,将后备缓冲的内容显示在屏幕上,此时后备缓冲就变成了前缓冲。

    要创建交换链,我们需要设置一个DXGI_SWAPCHAIN_DESC结构体说明将要创建的交换链。此结构体的几个字段需要说明一下:BackBufferUsage标志告诉程序我们使用后备缓冲的方式。本例中我们想绘制到后备缓冲,所以将BackBufferUsage设置为DXGI_USAGE_RENDER_TARGET_OUTPUTOutputWindow字段表示交换链将使用的窗口,在这个窗口上我们显示图像。SampleDesc用来开启多重采样(multi-sampling),因为这个教程不使用多重采样,SampleDesc的Count设置为1,Quality设置为0,这样就禁用了多重采样。

    设置好这个描述结构体后,我们就可以调用D3D11CreateDeviceAndSwapChaing方法创建设备和交换链。代码如下:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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(UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
    {
        g_driverType = driverTypes[driverTypeIndex];
        hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags,
                                            D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice,
                                                NULL, &g_pImmediateContext);
        if( SUCCEEDED( hr ) )
            break;
    }
    if( FAILED( hr ) )
        returnhr;

    下一步需要创建一个渲染目标视图(render target view)。渲染目标视图是Direct3D 11中一种资源视图(resource view)。资源视图可以让一个资源绑定到图形管线的某个阶段。可以将资源视图看成C中的类型转换,C中的一块原始内存(raw memory)可以被转换为任意数据结构,我们可以将一块内存转换为整数数组,浮点数数组,结构,结构数组等。如果我们不知道原始内存的类型,那么它对我们来说用处不大。Direct3D 11的资源视图工作原理类似,例如一张2D纹理就类似于一块原始内存,就是一种原始基础资源,有了这个原始资源,我们就可以创建不同的资源视图将这个纹理以不同的格式绑定到图形管线的不同阶段,而不同的格式可以是要绘制的渲染目标,接收深度信息的深度模板缓冲,或者也可以是一个纹理资源。C中的类型转换可以以不同方式使用一块内存,而在Direct3D 11中是资源视图进行类似的操作。

    因为我们需要将交换链中的后备缓冲绑定为一个渲染目标,所以需要创建一个渲染目标视图,这样Direct3D 11就可以在其上进行绘制了。我们首先调用GetBuffer() 方法获取后备缓冲对象。我们可以使用一个D3D11_RENDERTARGETVIEW_DESC结构体表示要创建的渲染目标视图,这个结构体通常是CreateRenderTargetView方法的第二个参数。但是,在本教程中,默认的渲染目标视图就能满足需要,所以第二个参数为NULL表示使用默认的渲染目标视图。创建了渲染目标视图后,我们就可以调用OMSetRenderTargets()方法将它绑定到图形管线,这样管线的绘制输出被写到了后备缓冲中。创建并设置渲染目标视图的代码如下:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // Create a render target view
    ID3D11Texture2D* pBackBuffer;
    hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID* )&pBackBuffer );
    if( FAILED( hr ) )
        returnhr;
     
    hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
    pBackBuffer->Release();
    if( FAILED( hr ) )
        returnhr;
     
    g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );

    最后,我们需要初始化视口(viewport)。视口剪裁空间坐标(X和Y的范围从-1到1,Z的范围从0到1)映射到渲染空间(有时又称为像素空间)。在Direct3D 9中,如果程序没有设置视口,会创建一个与渲染目标相同大小的默认视口。在Direct3D 11中,没有默认视口,我们必须事先设定。因为我们想将整个渲染目标输出,所以设置左上点为(0, 0),宽度和高度与渲染目标相同。代码如下:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 设置视口
    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()会将应用程序置于“睡眠”状态。这样会导致在程序进行绘制时,当消息队列为空时,应用程序会处于等待状态。我们可以使用PeekMessage()代替GetMessage()来解决这个问题。PeekMessage()像GetMessage()一样可以接收消息,当没有消息处于等待时,PeekMessage()会立即返回给应用程序一个FALSE值而不是处于休眠状态。这样我们就可以利用这段时间进行绘制的工作。修改过的消息循环的代码如下:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Main message loop
    MSG msg = {0};
    while( WM_QUIT != msg.message )
    {
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else
        {
            Render();
        }
    }

    绘制代码

    绘制过程是在Render()方法中进行的。在本教程中,我们想让过程尽量简单,所以就用单色填充屏幕。在Direct3D 10中,要将一种颜色填充渲染目标的简单方法就是使用设备的ClearRenderTargetView()方法。我们首先定义一个包含四个浮点数的数组设置要显示的颜色,然后将这个数组传递到ClearRenderTargetView()方法中。本例中使用的是蓝色。填充了后备缓冲后,就可以调用交换链的Present()方法完成绘制。Present()负责将后备缓冲的内容显示在屏幕上。Render()方法的代码如下:


    1
    2
    3
    4
    5
    6
    7
    void Render()
    {
        // Just clear 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 );
    }
    展开全文
  • 概述 在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形。 我们没有太注意我们在顶点缓冲区中拾取的顶点位置。 在本教程中,我们将深入研究3D位置和转换的...(SDK root)\Samples\C++\Direct3D11\Tuto...

    概述

    在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形。 我们没有太注意我们在顶点缓冲区中拾取的顶点位置。 在本教程中,我们将深入研究3D位置和转换的细节。

    本教程的结果将是渲染到屏幕的3D对象。 虽然之前的教程侧重于将2D对象渲染到3D世界,但在这里我们展示了一个3D对象。

     

    资源目录

    (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial04

    Github仓库

     

    3D空间

    在上一个教程中,三角形的顶点被有策略地放置,以在屏幕上完美地对齐。 但是,情况并非总是如此。 因此,我们需要一个系统来表示3D空间中的对象和一个显示它们的系统。

    在现实世界中,物体存在于3D空间中。 这意味着要将对象放置在世界中的特定位置,我们需要使用坐标系并定义与位置对应的三个坐标。 在计算机图形学中,3D空间最常用于笛卡尔坐标系。 在该坐标系中,三个轴X,Y和Z彼此垂直,决定了空间中每个点的坐标。 该坐标系进一步分为左手系统和右手系统。 在左手系统中,当X轴指向右侧,Y轴指向上方时,Z轴指向前方。 在右手系统中,具有相同的X和Y轴,Z轴指向后方。

    图1.左手坐标系与右手坐标系

    现在我们已经讨论过坐标系,考虑3D空间。 点在不同的空间中具有不同的坐标。 作为一维中的一个例子,假设我们有一个标尺,我们注意到标尺的5英寸标记处的点P. 现在,如果我们将标尺向右移动1英寸,则相同的点位于4英寸标记处。 通过移动标尺,参考框架已经改变。 因此,当点没有移动时,它有一个新的坐标。

    图2. 1D中的空间图示

    在3D中,空间通常由原点和来自原点的三个唯一轴定义:X,Y和Z.计算机图形中通常使用多个空间:对象空间,世界空间,视图空间,投影空间和屏幕空间。

    图3.在对象空间中定义的立方体

     

    对象空间

    请注意,多维数据集以原点为中心。 对象空间,也称为模型空间,是指艺术家在创建3D模型时使用的空间。 通常,艺术家创建以原点为中心的模型,以便更容易执行转换,例如旋转模型,我们将在讨论转换时看到。 八个顶点具有以下坐标:   
        (-1,  1, -1)
        ( 1,  1, -1)
        (-1, -1, -1)
        ( 1, -1, -1)
        (-1,  1,  1)
        ( 1,  1,  1)
        (-1, -1,  1)
        ( 1, -1,  1)
    
    因为对象空间是艺术家在设计和创建模型时通常使用的对象空间,所以存储在磁盘上的模型也在对象空间中。 应用程序可以创建顶点缓冲区来表示此类模型,并使用模型数据初始化缓冲区。 因此,顶点缓冲区中的顶点通常也位于对象空间中。 这也意味着顶点着色器接收对象空间中的输入顶点数据。
     

    世界空间

    世界空间是场景中每个对象共享的空间。 它用于定义我们希望渲染的对象之间的空间关系。 为了想象世界空间,我们可以想象我们正站在朝北的长方形房间的西南角。 我们将我们的脚站立的角落定义为原点,(0,0,0)。 X轴向我们的右边; Y轴上升; 并且Z轴向前,与我们面对的方向相同。 当我们这样做时,房间中的每个位置都可以用一组XYZ坐标来识别。 例如,可能有一把椅子在前方5英尺处,在我们右侧2英尺处。 在椅子顶部的8英尺高的天花板上可能有一盏灯。 然后我们可以将椅子的位置称为(2,0,5),将灯的位置称为(2,8,5)。 正如我们所看到的,世界空间就是所谓的在世界上相互联系的物体所组成的。
     
     

    视图空间

    视图空间(有时称为相机空间)类似于世界空间,因为它通常用于整个场景。 但是,在视图空间中,原点位于查看器或摄像机。 视图方向(观察者正在看的位置)定义正Z轴。 应用程序定义的“向上”方向变为正Y轴,如下所示。
    图4.世界空间(左)和视图空间(右)中的相同对象

    左图显示了一个场景,该场景由类似人的物体和观察物体的观察者(相机)组成。 世界空间使用的原点和轴以红色显示。 右图显示了与世界空间相关的视图空间。 视图空间轴显示为蓝色。 为了更清楚地说明,视图空间与左图像中的世界空间的方向与读者不同。 请注意,在视图空间中,查看器正在Z方向上查看。

     

    投影空间

    投影空间是指从视图空间应用投影变换后的空间。 在此空间中,可见内容的X和Y坐标范围为-1到1,Z坐标范围为0到1。

     

    屏幕空间

    屏幕空间通常用于指代帧缓冲区中的位置。 因为帧缓冲区通常是2D纹理,所以屏幕空间是2D空间。 左上角是坐标为(0,0)的原点。 正X向右,正Y向下。 对于w像素宽且h像素高的缓冲区,最右下像素具有坐标(w-1,h-1)。

     

    空间对空间的转换

    转换最常用于将顶点从一个空间转换为另一个空间。 在3D计算机图形学中,管道中逻辑上有三种这样的变换:世界,视图和投影变换。 下一个教程将介绍单个转换操作,如转换,旋转和缩放。

     

    世界转换

    顾名思义,世界转换将顶点从对象空间转换为世界空间。 它通常由一个或多个缩放,旋转和平移组成,基于我们想要给对象的大小,方向和位置。 场景中的每个对象都有自己的世界变换矩阵。 这是因为每个对象都有自己的大小,方向和位置。

     

    视图转换

    顶点转换为世界空间后,视图转换将这些顶点从世界空间转换为视图空间。 回想一下之前的讨论,观看空间是世界从观众(或相机)的角度出现的。 在视图空间中,观察者位于沿正Z轴向外看的原点。

    值得注意的是,尽管视图空间是来自观察者参照系的世界,但视图变换矩阵应用于顶点,而不是观察者。 因此,视图矩阵必须执行我们应用于我们的查看器或相机的相反转换。 例如,如果我们想要将摄像机朝向-Z方向移动5个单元,我们需要计算一个视图矩阵,它可以沿着+ Z方向将顶点平移5个单位。 虽然相机向后移动,但从相机的角度来看,顶点已向前移动。 在XNA Math中,一个方便的API调用XMMatrixLookAtLH()通常用于计算视图矩阵。 我们只需要告诉它观察者在哪里,在哪里看,以及表示观察者顶部的方向,也称为向上矢量,以获得相应的视图矩阵。

     

    投影转换

    投影变换将顶点从诸如世界和视图空间的3D空间转换为投影空间。 在投影空间中,顶点的X和Y坐标是从3D空间中该顶点的X / Z和Y / Z比获得的。

    图5.投影

    在3D空间中,事物以透视的方式出现。 也就是说,物体越近,它出现的越大。 如图所示,在远离观察者眼睛的d个单位处高h单位的树的尖端将出现在与另一棵树的尖端2h单位高和2d单位远的相同点处。 因此,在2D屏幕上出现顶点的位置与其X / Z和Y / Z比率直接相关。

    定义3D空间的参数之一称为视场(FOV)。 FOV表示在特定方向上查看哪些对象从特定位置可见。 人类有一个前瞻性的FOV(我们无法看到我们背后的东西),我们看不到太近或太远的物体。 在计算机图形学中,FOV包含在视锥体中。 视锥体由3D中的6个平面定义。 这些平面中的两个平行于XY平面。 这些被称为近Z和远Z平面。 其他四个平面由观察者的水平和垂直视野定义。 视场越宽,视锥体体积越宽,观察者看到的物体越多。

    GPU会过滤掉视锥体外的对象,这样就不必花时间渲染无法显示的内容。 此过程称为裁剪。 视锥体是一个四面金字塔,顶部被切掉。 剪切此卷是很复杂的,因为要剪切一个视锥体平面,GPU必须将每个顶点与平面的等式进行比较。 相反,GPU通常首先执行投影变换,然后针对视锥体量进行剪辑。 投影变换对视锥体的影响是金字塔形视锥体成为投影空间中的盒子。 这是因为,如前所述,在投影空间中,X和Y坐标基于3D空间中的X / Z和Y / Z. 因此,点a和点b在投影空间中将具有相同的X和Y坐标,这就是视锥体成为盒子的原因。

    图6.查看平截头体

    假设两棵树的尖端恰好位于顶视图平截头体边缘。进一步假设d = 2h。沿投影空间中顶边的Y坐标将为0.5(因为h / d = 0.5)。因此,任何大于0.5的Y投影后Y值都将被裁剪。这里的问题是0.5由程序选择的垂直视场确定,并且不同的FOV值导致GPU必须剪切的不同值。为了使这个过程更加方便,3D程序通常缩放顶点的投影X和Y值,以便可见的X和Y值的范围从-1到1.换句话说,任何X或Y坐标都在[-1]之外1]范围将被删除。为了使该剪切方案起作用,投影矩阵必须通过h / d或d / h的倒数来缩放投影顶点的X和Y坐标。 d / h也是FOV一半的余切。通过缩放,视锥体的顶部变为h / d * d / h = 1.大于1的任何内容都将被GPU裁剪。这就是我们想要的。

    通常也对投影空间中的Z坐标进行类似的调整。 我们希望近和远Z平面分别在投影空间中为0和1。 当Z = 3D空间中的近Z值时,Z在投影空间中应为0; 当Z = 3D空间中的远Z时,Z在投影空间中应为1。 完成此操作后,GPU [0 1]以外的任何Z值都将被裁剪掉。

    在Direct3D 11中,获取投影矩阵的最简单方法是调用XMMatrixPerspectiveFovLH()方法。 我们只提供4个参数-FOVy,Aspect,Zn和Zf-并返回一个矩阵,它可以完成上面提到的所有必要操作。 FOVy是Y方向的视野。 Aspect是宽高比,即视图宽度与高度的比率。 从FOVy和Aspect,可以计算FOVx。 该纵横比通常从渲染目标宽度与高度的比率获得。 Zn和Zf分别是视图空间中的近和远Z值。

     

    使用转换

    在上一个教程中,我们编写了一个程序,用于渲染单个三角形。 当我们创建顶点缓冲区时,我们使用的顶点位置直接在投影空间中,这样我们就不必执行任何变换。 现在我们已经了解了3D空间和变换,我们将修改程序,以便在对象空间中定义顶点缓冲区,就像它应该的那样。 然后,我们将修改顶点着色器以将顶点从对象空间转换为投影空间。

     

    修改顶点缓冲区

    由于我们开始以三维方式表示事物,因此我们将前一个教程中的平面三角形更改为多维数据集。 这将使我们能够更清楚地展示这些概念。

    SimpleVertex vertices[] =
        {
            { XMFLOAT3( -1.0f,  1.0f, -1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },
            { XMFLOAT3(  1.0f,  1.0f, -1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },
            { XMFLOAT3(  1.0f,  1.0f,  1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) },
            { XMFLOAT3( -1.0f,  1.0f,  1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },
            { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f ) },
            { XMFLOAT3(  1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) },
            { XMFLOAT3(  1.0f, -1.0f,  1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
            { XMFLOAT3( -1.0f, -1.0f,  1.0f ), XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) },
        };
    

      

    如果你注意到我们所做的只是指定立方体上的八个点,但我们实际上没有描述各个三角形。 如果我们按原样传递,输出将不是我们所期望的。 我们需要通过这八个点指定形成立方体的三角形。

    在立方体上,许多三角形将共享相同的顶点,并且一次又一次地重新定义相同的点将浪费空间。 因此,有一种方法只指定八个点,然后让Direct3D知道要为三角形选择哪些点。 这是通过索引缓冲区完成的。 索引缓冲区将包含一个列表,该列表将引用缓冲区中的顶点索引,以指定在每个三角形中使用哪些点。 下面的代码显示了构成每个三角形的点。

        // Create index buffer
        WORD indices[] =
        {
            3,1,0,
            2,1,3,
    
            0,5,4,
            1,5,0,
    
            3,4,7,
            0,4,3,
    
            1,6,5,
            2,6,1,
    
            2,7,6,
            3,7,2,
    
            6,4,5,
            7,4,6,
        };
    

      

    如您所见,第一个三角形由点3,1和0定义。这意味着第一个三角形的顶点位于:( - 1.0f,1.0f,1.0f),(1.0f,1.0f,-1.0) f),和(-1.0f,1.0f,-1.0f)。 立方体上有六个面,每个面由两个三角形组成。 因此,您会看到此处定义的12个三角形。

    由于每个顶点都是明确列出的,并且没有两个三角形共享边(至少,它已经被定义),这被认为是一个三角形列表。 总的来说,对于三角形列表中的12个三角形,我们将需要总共36个顶点。

    索引缓冲区的创建与顶点缓冲区非常相似,我们在结构中指定了诸如大小和类型之类的参数,并称为CreateBuffer。 类型是D3D11_BIND_INDEX_BUFFER,因为我们使用DWORD声明了我们的数组,所以我们将使用sizeof(DWORD)。

        D3D11_BUFFER_DESC bd;
        ZeroMemory( &bd, sizeof(bd) );
        bd.Usage = D3D11_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( WORD ) * 36;        // 36 vertices needed for 12 triangles in a triangle list
        bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
        bd.CPUAccessFlags = 0;
        bd.MiscFlags = 0;
        InitData.pSysMem = indices;
        if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ) ) )
            return FALSE;
    

      

    一旦我们创建了这个缓冲区,我们就需要设置它,以便Direct3D知道在生成三角形时引用这个索引缓冲区。 我们指定缓冲区的指针,格式和缓冲区中的偏移量以开始引用。

        // Set index buffer
        g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
    

      

    修改顶点着色器

    在上一个教程的顶点着色器中,我们采用输入顶点位置并输出相同的位置而不进行任何修改。我们可以这样做,因为输入顶点位置已经在投影空间中定义。现在,因为输入顶点位置是在对象空间中定义的,所以我们必须在从顶点着色器输出之前对其进行变换。我们通过三个步骤完成此任务:从对象转换到世界空间,从世界转换到视图空间,以及从视图转换到投影空间。我们需要做的第一件事是声明三个常量缓冲区变量。常量缓冲区用于存储应用程序需要传递给着色器的数据。在渲染之前,应用程序通常会将重要数据写入常量缓冲区,然后在渲染过程中可以从着色器中读取数据。在FX文件中,常量缓冲区变量在C ++结构中声明为全局变量。我们将使用的三个变量是HLSL类型“矩阵”的世界,视图和投影变换矩阵。

    一旦我们声明了我们需要的矩阵,我们就会更新顶点着色器以使用矩阵变换输入位置。 通过将矢量乘以矩阵来变换矢量。 在HLSL中,这是使用mul()内部函数完成的。 我们的变量声明和新的顶点着色器如下所示:

        cbuffer ConstantBuffer : register( b0 )
        {
            matrix World;
            matrix View;
            matrix Projection;
        }
        
        //
        // Vertex Shader
        //
        VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
        {
            VS_OUTPUT output = (VS_OUTPUT)0;
            output.Pos = mul( Pos, World );
            output.Pos = mul( output.Pos, View );
            output.Pos = mul( output.Pos, Projection );
            output.Color = Color;
            return output;
        }
    

      

    在顶点着色器中,每个 mul()将一个变换应用于输入位置。 世界,视图和投影变换按顺序依次应用。 这是必要的,因为向量和矩阵乘法不是可交换的。

     

    设置矩阵

    我们更新了顶点着色器以使用矩阵进行变换,但我们还需要在程序中定义三个矩阵。 这三个矩阵将存储渲染时要使用的变换。 在渲染之前,我们将这些矩阵的值复制到着色器常量缓冲区。 然后,当我们通过调用Draw()启动渲染时,我们的顶点着色器读取存储在常量缓冲区中的矩阵。 除了矩阵之外,我们还需要一个代表常量缓冲区的ID3D11Buffer对象。 因此,我们的全局变量将添加以下内容:

        ID3D11Buffer* g_pConstantBuffer = NULL;
        XMMATRIX g_World;
        XMMATRIX g_View;
        XMMATRIX g_Projection;
    

      

    要创建ID3D11Buffer对象,我们使用 ID3D11Device :: CreateBuffer()并指定D3D11_BIND_CONSTANT_BUFFER

        D3D11_BUFFER_DESC bd;
        ZeroMemory( &bd, sizeof(bd) );
        bd.Usage = D3D11_USAGE_DEFAULT;
        bd.ByteWidth = sizeof(ConstantBuffer);
        bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        bd.CPUAccessFlags = 0;
        if( FAILED(g_pd3dDevice->CreateBuffer( &bd, NULL, &g_pConstantBuffer ) ) )
            return hr;
    

      

    我们需要做的下一件事是提出三个矩阵,我们将用它来进行转换。我们希望三角形位于原点上,与XY平面平行。这正是它如何存储在对象空间中的顶点缓冲区中。因此,世界变换不需要做任何事情,我们将世界矩阵初始化为单位矩阵。我们想要设置我们的相机,使其位于[0 1 -5],查看点[0 1 0]。我们可以使用向上矢量[0 1 0]调用 XMMatrixLookAtLH()来方便地为我们计算视图矩阵,因为我们希望+ Y方向始终保持在顶部。最后,为了得到投影矩阵,我们称之为XMMatrixPerspectiveFovLH(),具有90度垂直视场(pi / 2),宽高比为640/480,来自我们的后缓冲区大小,以及近和远Z分别为0.1和110。这意味着屏幕上将看不到小于0.1或超过110的任何内容。这三个矩阵存储在全局变量g_World,g_View和g_Projection中。

     

    更新常量缓冲区

    我们有矩阵,现在我们必须在渲染时将它们写入常量缓冲区,以便GPU可以读取它们。 要更新缓冲区,我们可以使用 ID3D11DeviceContext :: UpdateSubresource()API并将指针传递给以与着色器常量缓冲区相同的顺序存储的矩阵。 为了做到这一点,我们将创建一个与着色器中的常量缓冲区具有相同布局的结构。 另外,由于矩阵在C ++和HLSL中的内存排列方式不同,我们必须在更新之前转置矩阵。

        //
        // Update variables
        //
        ConstantBuffer cb;
        cb.mWorld = XMMatrixTranspose( g_World );
        cb.mView = XMMatrixTranspose( g_View );
        cb.mProjection = XMMatrixTranspose( g_Projection );
        g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 );
    

      

     

     

    转载于:https://www.cnblogs.com/OctoptusLian/p/9748161.html

    展开全文
  • 概述 在上一个教程中,我们从模型空间到屏幕渲染了一个立方体。 在本教程中,我们将扩展转换的概念并演示可以通过这些转换实现的简单动画。 本教程的结果将是围绕另...(SDK root)\Samples\C++\Direct3D11\Tutoria...

    概述

    在上一个教程中,我们从模型空间到屏幕渲染了一个立方体。 在本教程中,我们将扩展转换的概念并演示可以通过这些转换实现的简单动画。

    本教程的结果将是围绕另一个轨道运行的对象。 展示转换以及如何将它们组合以实现期望的效果将是有用的。 在我们介绍新概念时,未来的教程将在此基础上构建。

     

    资源目录

    (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial05

    Github

     

    转型

    在3D图形中,变换通常用于对顶点和矢量进行操作。 它还用于将它们在一个空间中转换为另一个空间。 通过与矩阵相乘来执行变换。 通常有三种类型的原始变换可以在顶点上执行:平移(相对于原点位于空间中),旋转(相对于x,y,z帧的方向)和缩放(距离 起源)。 除此之外,投影变换用于从视图空间到投影空间。 XNA Math库包含的API可以方便地构建矩阵,用于多种用途,例如平移,旋转,缩放,世界到视图转换,视图到投影转换等。 然后,应用程序可以使用这些矩阵来转换其场景中的顶点。 需要对矩阵变换有基本的了解。 我们将简要介绍下面的一些示例。

     

    平移

    平移是指在空间中移动或移位一定距离。 在3D中,用于翻译的矩阵具有形式。

        1  0  0  0
        0  1  0  0
        0  0  1  0
        a  b  c  1
    

    其中(a,b,c)是定义移动方向和距离的向量。 例如,要沿X轴(负X方向)移动顶点-5单位,我们可以将其与此矩阵相乘:

        1  0  0  0
        0  1  0  0
        0  0  1  0
       -5  0  0  1
    

    如果我们将此应用于以原点为中心的立方体对象,则结果是该框向负X轴移动5个单位,如图5所示,在应用平移之后。

    图1.平移的影响

    在3D中,空间通常由原点和来自原点的三个唯一轴定义:X,Y和Z.计算机图形中通常使用多个空间:对象空间,世界空间,视图空间,投影空间和屏幕空间。

    图2.在对象空间中定义的立方体

     

    旋转

    旋转是指围绕穿过原点的轴旋转顶点。 三个这样的轴是空间中的X,Y和Z轴。 2D中的示例是逆时针旋转矢量[1 0] 90度。 旋转的结果是向量[0 1]。 用于围绕Y轴顺时针旋转1度的矩阵看起来像这样:

        cosΐ  0  -sinΐ   0
         0    1     0    0
        sinΐ  0   cosΐ  0
         0    0     0    1
    

    图6显示了围绕Y轴旋转以原点为中心45度的立方体的效果。

    图3.围绕Y轴旋转的效果

     

    缩放

    缩放是指沿轴方向放大或缩小矢量分量的大小。 例如,矢量可以沿所有方向按比例放大或仅沿X轴按比例缩小。 为了扩展,我们通常在下面应用缩放矩阵:

        p  0  0  0
        0  q  0  0
        0  0  r  0
        0  0  0  1
    

    其中p,q和r分别是沿X,Y和Z方向的比例因子。 下图显示了沿X轴缩放2并沿Y轴缩放0.5的效果。

    图4.缩放的效果

     

    多重转换

    要将多个变换应用于矢量,我们可以简单地将矢量乘以第一个变换矩阵,然后将得到的矢量乘以第二个变换矩阵,依此类推。 因为向量和矩阵乘法是关联的,我们也可以先将所有矩阵相乘,然后将向量乘以乘积矩阵,得到相同的结果。 下图显示了如果我们将旋转和平移转换结合在一起,立方体将如何结束。

    图5.旋转和平移的效果

    创建轨道

    在本教程中,我们将转换两个多维数据集。 第一个将旋转到位,而第二个将围绕第一个旋转,同时在其自己的轴上旋转。 这两个立方体将具有与其关联的自己的世界变换矩阵,并且该矩阵将在渲染的每个帧中重新应用于该矩阵。

    XNA Math中有一些函数可以帮助创建旋转,平移和缩放矩阵。

    • 围绕X,Y和Z轴执行的旋转分别使用函数XMMatrixRotationX,XMMatrixRotationY和XMMatrixRotationZ来完成。 它们创建围绕主轴之一旋转的基本旋转矩阵。 围绕其他轴的复杂旋转可以通过将它们中的几个相乘来完成。
    • 可以通过调用XMMatrixTranslation函数来执行转换。 此函数将创建一个矩阵,用于转换参数指定的点。
    • 使用XMMatrixScaling完成缩放。 它仅沿主轴缩放。 如果需要沿任意轴缩放,则可以将缩放矩阵与适当的旋转矩阵相乘以实现该效果。

    第一个立方体将旋转到位,并作为轨道的中心。 立方体沿Y轴旋转,应用于相关的世界矩阵。 这是通过调用以下代码中显示的XMMatrixRotationY函数来完成的。 立方体每帧旋转一定量。 由于立方体被假设为连续旋转,因此旋转矩阵所基于的值随每帧递增。

    // 1st Cube: Rotate around the origin
        g_World1 = XMMatrixRotationY( t );
    

      

    第一个立方体将旋转到位,并作为轨道的中心。 立方体沿Y轴旋转,应用于相关的世界矩阵。 这是通过调用以下代码中显示的XMMatrixRotationY函数来完成的。 立方体每帧旋转一定量。 由于立方体被假设为连续旋转,因此旋转矩阵所基于的值随每帧递增。

    // 2nd Cube:  Rotate around origin
        XMMATRIX mSpin = XMMatrixRotationZ( -t );
        XMMATRIX mOrbit = XMMatrixRotationY( -t * 2.0f );
        XMMATRIX mTranslate = XMMatrixTranslation( -4.0f, 0.0f, 0.0f );
        XMMATRIX mScale = XMMatrixScaling( 0.3f, 0.3f, 0.3f );
        g_World2 = mScale * mSpin * mTranslate * mOrbit;
    

      

    需要注意的一点是,这些操作不是可交换的。 应用转换的顺序很重要。 试验转化顺序并观察结果。

    由于所有变换函数都将根据参数创建新矩阵,因此它们旋转的量必须递增。 这是通过更新“时间”变量来完成的。

    // Update our time
        t += XM_PI * 0.0125f;
    

      

    在进行渲染调用之前,必须为着色器更新常量缓冲区。 请注意,世界矩阵对于每个多维数据集都是唯一的,因此会为每个传递给它的对象进行更改。

    //
        // Update variables for the first cube
        //
        ConstantBuffer cb1;
        cb1.mWorld = XMMatrixTranspose( g_World1 );
        cb1.mView = XMMatrixTranspose( g_View );
        cb1.mProjection = XMMatrixTranspose( g_Projection );
        g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb1, 0, 0 );
    
        //
        // Render the first cube
        //
        g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
        g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer );
        g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
        g_pImmediateContext->DrawIndexed( 36, 0, 0 );
    
        //
        // Update variables for the second cube
        //
        ConstantBuffer cb2;
        cb2.mWorld = XMMatrixTranspose( g_World2 );
        cb2.mView = XMMatrixTranspose( g_View );
        cb2.mProjection = XMMatrixTranspose( g_Projection );
        g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb2, 0, 0 );
    
        //
        // Render the second cube
        //
        g_pImmediateContext->DrawIndexed( 36, 0, 0 );
    

      

    深度缓冲区

    本教程还有另外一个重要的补充,那就是深度缓冲区。 没有它,较小的轨道立方体在围绕后者的后部时仍会被绘制在较大的中心立方体的顶部。 深度缓冲区允许Direct3D跟踪绘制到屏幕的每个像素的深度。 Direct3D 11中深度缓冲区的默认行为是检查屏幕上绘制的每个像素与屏幕空间像素的深度缓冲区中存储的值。 如果正在渲染的像素的深度小于或等于深度缓冲器中已经存在的值,则绘制像素并且将深度缓冲器中的值更新为新绘制的像素的深度。 另一方面,如果正在绘制的像素的深度大于深度缓冲器中已经存在的值,则丢弃该像素并且深度缓冲器中的深度值保持不变。

    示例中的以下代码创建深度缓冲区(DepthStencil纹理)。 它还创建深度缓冲区的DepthStencilView,以便Direct3D 11知道将其用作深度模板纹理。

     // Create depth stencil texture
        D3D11_TEXTURE2D_DESC descDepth;
        ZeroMemory( &descDepth, sizeof(descDepth) );
        descDepth.Width = width;
        descDepth.Height = height;
        descDepth.MipLevels = 1;
        descDepth.ArraySize = 1;
        descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
        descDepth.SampleDesc.Count = 1;
        descDepth.SampleDesc.Quality = 0;
        descDepth.Usage = D3D11_USAGE_DEFAULT;
        descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
        descDepth.CPUAccessFlags = 0;
        descDepth.MiscFlags = 0;
        hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
        if( FAILED(hr) )
            return hr;
    
        // Create the depth stencil view
        D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
        ZeroMemory( &descDSV, sizeof(descDSV) );
        descDSV.Format = descDepth.Format;
        descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
        descDSV.Texture2D.MipSlice = 0;
        hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
        if( FAILED(hr) )
            return hr;
    

      

    为了使用这个新创建的深度模板缓冲区,教程必须将其绑定到设备。 这是通过将深度模板视图传递给OMSetRenderTargets函数的第三个参数来完成的。

    g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
    

      

    与渲染目标一样,我们还必须在渲染之前清除深度缓冲区。 这可确保先前帧的深度值不会错误地丢弃当前帧中的像素。 在下面的代码中,教程实际上是将深度缓冲区设置为最大量(1.0)。

        //
        // Clear the depth buffer to 1.0 (max depth)
        //
    

      

    最终效果

     

    转载于:https://www.cnblogs.com/OctoptusLian/p/9752062.html

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

    Github-LearnDirectX-DX3D11 tutorial01

    概述

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

    资源目录

    (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial01

     

    设置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(在本文首部)。

     

    转载于:https://www.cnblogs.com/OctoptusLian/p/9729605.html

    展开全文
  • Direct3D起步-教程

    2010-05-25 17:21:57
    Direct3D起步-教程,一本教会初学者学习Direct3D的好东西
  • 概述 在之前的教程中,世界看起来很无聊,因为所有对象都以相同的方式点亮。 本教程将介绍简单照明的概念及其应用方法。 使用的技术将是朗伯照明。...(SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial06 Gi...
  • Direct3D 游戏编程入门教程
  • Direct 3D 游戏编程入门教程(第2版)基于DirectX 9.0,是介绍Direct3D技术的入门教程,详细介绍了Direct3D的背景、基本知识以及3D程序设计的相关概念与技术。全书由浅入深,分为四个部分,第一部分介绍Direct3D的发展...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 469
精华内容 187
关键字:

direct3d教程