上篇文章给出了一个简单并且可以运行的渲染框架,接下来将介绍框架中的渲染管线构成。

  1、创建渲染管线

  在你创建完一个窗口后,接着便要创建渲染管线,使用的函数是 D3D11CreateDeviceAndSwapChain,

  交换链:


  要创建交换链,必须先设置交换链描述。交换链描述定义了将由交换链使用的渲染缓冲区的大小和数量。它还将窗口与交换链相关联,从而确定最终图像的显示位置。交换链描述还定义了该应用的消除锯齿(如果有的话)的质量以及在展示过程中后端缓冲区的翻转方式。

    UINT create_device_flags = ;
#ifdef _DEBUG
create_device_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif D3D_DRIVER_TYPE driver_types[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT num_driver_types = ARRAYSIZE(driver_types); D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE(featureLevels); DXGI_SWAP_CHAIN_DESC swap_desc;
ZeroMemory(&swap_desc, sizeof(swap_desc));
swap_desc.BufferCount = ;
swap_desc.BufferDesc.Width = width;
swap_desc.BufferDesc.Height = height;
swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_desc.BufferDesc.RefreshRate.Numerator = ;
swap_desc.BufferDesc.RefreshRate.Denominator = ;
swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_desc.OutputWindow = g_hWnd;
swap_desc.SampleDesc.Count = ;
swap_desc.SampleDesc.Quality = ;
swap_desc.Windowed = TRUE; for ( UINT driver_type_index = ; driver_type_index < num_driver_types; driver_type_index++ )
{
g_driverType = driver_types[driver_type_index];
hr = D3D11CreateDeviceAndSwapChain(NULL, g_driverType, NULL, create_device_flags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &swap_desc, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
if ( SUCCEEDED(hr) ) break;
}

  创建交换链是指定了一个窗口的句柄,并且设置了一个 D3D11_CREATE_DEVICE_DEBUG 标志,这个标志可以创建一个支持调试层的设备。如果我们做错了事,调试层为渲染管线的正确性和一致性提供了额外的检查并提供了更好的反馈。但是,如果在启用调试层的情况下运行应用程序,则应用程序将显着变慢。

要创建支持调试层的设备,必须安装DirectX SDK(以获取D3D11SDKLayers.dll)

  渲染管线输出:


  渲染管线并不能将渲染结果直接输出到窗口,只能输出到一个叫渲染目标视图(ID3D11RenderTargetView)的对象,在创建 ID3D11RenderTargetView 时需要和一个纹理对象绑定。可以使用交换链的 GetBuffer 方法来获取交换链后台纹理缓冲区指针,并创建一个渲染目标视图,最后将该视图设置到渲染管线,就可以将渲染管线的结果呈现给窗口了。

    /* 获取交换链的后缓冲 */
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer(, __uuidof(ID3D11Texture2D), ( LPVOID* ) &pBackBuffer);
if ( FAILED(hr) ) return hr; /* 创建渲染目标视图 */
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
pBackBuffer->Release();
if ( FAILED(hr) ) return hr; g_pImmediateContext->OMSetRenderTargets(, &g_pRenderTargetView, );

  

  使用函数 OMSetRenderTargets 设置渲染目标视图到渲染管线时,可以设置 1 - D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT 之间数量的渲染目标视图。默认情况下使用第一个渲染目标视图,如果你要使用其它的渲染目标视图,必须在像素着色器中映射管线多输出值到 SV_Target[n] (其中 介于 0 和 D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT 之间)语义,实现多渲染目标(MRT)。像素着色器代码如下:

struct PS_OUTPUT
{
float4 color0 : SV_Target0;
float4 color1 : SV_Target1;
}; //--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
PS_OUTPUT PS( VS_OUTPUT input )
{
PS_OUTPUT o; o.color0 = input.Color;
o.color1 = float4(, , , ); return o;
}

  因为没有多少文章介绍 DirectX11 多渲染目标(MRT)的实现,所以在这里简单介绍一下。

  视口(ViewPort):


  然不是严格考虑Direct3D初始化阶段的一部分,但设置视口定义是初始化光栅化器阶段的必要组件。视口定义了我们的最终渲染将进入的屏幕空间区域。对于这个应用程序,我们将渲染到应用程序窗口的整个客户区,但是如果我们想实现分屏多人或画中画效果,我们也可以定义两个视口。

    D3D11_VIEWPORT view_port;

    view_port.Width = ( FLOAT ) width;
view_port.Height = ( FLOAT ) height;
view_port.MinDepth = 0.0f;
view_port.MaxDepth = 1.0f;
view_port.TopLeftX = ;
view_port.TopLeftY = ; g_pImmediateContext->RSSetViewports(, &view_port);

  

  使用 RSSetViewports 设置视口到渲染管线时,可以设置 1 D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX 之间数量的视口。默认情况下使用第一个视口,如果你想使用其它的视口,必须在几何着色器中设置 SV_ViewportArrayIndex 语义确定输出到哪个视口。如果想将窗口或分为 4 部分,先创建 4 个视口:

    D3D11_VIEWPORT view_port[];
for ( int i = ; i < ; i++ )
{
view_port[i].Width = ( FLOAT ) width / ;
view_port[i].Height = ( FLOAT ) height / ;
view_port[i].MinDepth = 0.0f;
view_port[i].MaxDepth = 1.0f;
view_port[i].TopLeftX = ;
view_port[i].TopLeftY = ;
}
view_port[].TopLeftX = ( FLOAT ) width / ;
view_port[].TopLeftY = ; view_port[].TopLeftX = ;
view_port[].TopLeftY = ( FLOAT ) height / ; view_port[].TopLeftX = ( FLOAT ) width / ;
view_port[].TopLeftY = ( FLOAT ) height / ;
g_pImmediateContext->RSSetViewports(, view_port);

  接着是几何着色器的设置:

//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
} //--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
}; //--------------------------------------------------------------------------------------
struct GS_OUTPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
uint view_idx : SV_VIEWPORTARRAYINDEX;
}; //--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
{
VS_OUTPUT output = (VS_OUTPUT);
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Color = Color;
return output;
} //--------------------------------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------------------------------
[maxvertexcount()]
void GS(triangle VS_OUTPUT input[], inout TriangleStream<GS_OUTPUT> output)
{
for(int j = ; j < ; j++)
{
GS_OUTPUT element;
element.view_idx = j; for (uint i = ; i < ;i++)
{
element.Pos = input[i].Pos;
element.Color = input[i].Color;
output.Append(element);
}
output.RestartStrip();
}
} //--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( VS_OUTPUT input ) : SV_Target
{
return input.Color;
}

  在编译并设置几何着色器到渲染管线后,得到以下结果:

  因为没有什么文章介绍这种方法的实现,所以在这里简单介绍一下。当然你要可以不这样做,你可以渲染 4 次,每次使用不同的视口,得到和上面一样的结果。

  源码下载:MMDViewer 04.zip

基于 DirectX11 的 MMDViewer 04-渲染目标视图和多视口的更多相关文章

  1. 基于 DirectX11 的 MMDViewer 01-简介

    这个项目主要是为了 DirectX11 而来,前面做了一个关于 OpenGL 的项目,这次打算使用 DirectX11 来做一个 MMD 的模型浏览器.以前,我使用过 DirectX11 来做过一些项 ...

  2. 基于 DirectX11 的 MMDViewer 03-渲染管线

    准备工作: 开始搭建框架之前,你需要确保已经进行了 D3D 开发环境的搭建,相关教程可以阅读这篇文章.不了解 DirectX11 的人,这个作者有关 DirectX11 的教程最好阅读一下,虽然文章不 ...

  3. 基于 DirectX11 的 MMDViewer 02-创建一个窗口

    项目的创建和配置: 1.新建一个 Win32 空项目 2.创建源码文件夹.库文件夹和资源文件夹 3.在 VS2013(我使用的 IDE 是 vs2013)配置这些文件夹 这里使用了 $(Solutio ...

  4. Spring实战第六章学习笔记————渲染Web视图

    Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...

  5. RenderDoc图形调试器详细使用教程(基于DirectX11)

    前言 由于最近Visual Studio的图形调试器老是抽风,不得不寻找一个替代品了. 对于图形程序开发者来说,学会使用RenderDoc图形调试器可以帮助你全面了解渲染管线绑定的资源和运行状态,从而 ...

  6. Vuejs - 花式渲染目标元素

    Vue.js是什么 摘自官方文档: Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库 ...

  7. Spring学习(六)--渲染Web视图

    一.将模型数据渲染为Html 在上一篇文章中,我们所编写的控制器方法都没有直接产生浏览器中渲染所需的HTML.这些方法只是将数据填充到模型中,然后将模型传递给一个用来渲染的视图.这些方法会返回一个St ...

  8. CVPR2020|3D-VID:基于LiDar Video信息的3D目标检测框架

    作者:蒋天园 Date:2020-04-18 来源:3D-VID:基于LiDar Video信息的3D目标检测框架|CVPR2020 Brief paper地址:https://arxiv.org/p ...

  9. 基于显卡的光栅化渲染器Gaius计划

    决定实现一个基于显卡的光栅化渲染器,能将一些基于显卡的新算法融入其中.

随机推荐

  1. NSLayoutConstraint 布局,配合简单的动画效果

    demo地址 :链接: http://pan.baidu.com/s/1c00ipDQ 密码: mi4c 1 @interface ViewController () @property (nonat ...

  2. SQL之 UNION ALL 和UNION

    有时候复杂的逻辑处理可以交给SQL来处理,自认为是比java处理要快点. 举个例子:如何统计每个品牌的的偏好用户数? 当时我做的处理是在java中处理这些品牌,若是品牌相同,就加一,但是这种方法很慢, ...

  3. JS 区分单击双击

    var timeout =null; $("#Btn").on("click",function(){ clearTimeout(timeout);//停止单击 ...

  4. 防范DDoS攻击的几种方式

    一.拒绝服务攻击的发展: 从拒绝服务攻击诞生到现在已经有了很多的发展,从最初的简单Dos到现在的DdoS.那么什么是Dos和DdoS呢?DoS是一种利用单台计算机的攻击 方式.而DdoS(Distri ...

  5. pid参数调节的几句话

    如果参数上升太快,降低Kp值,如果震荡太剧烈(振荡幅度过大),降低Ki值,如果曲线震荡部分上升下降太快则尝试调整Kd值.

  6. 一些IPC常用头文件

    //my_err.h#include <errno.h> /* for definition of errno */ #include <stdarg.h> /* ISO C ...

  7. linux多线程并发

    多线程并发 进程和线程的概念 进程 进程包括程序映象.地址空间等要素.内核采用PCB来管理进程.进程是内核进行调度的基本单元,每个独立的进程都有自己的代码段.数据段以及堆栈,它们有自己的虚拟地址空间, ...

  8. Android 编译系统的组成

    Android 和 Linux 的编译系统都是通过 Makefile 工具来组织编译源代码的. Makefile 工具用来解释和执行 Makefile 文件,在 Makefile 文件里定义好工程源代 ...

  9. 64位windows系统安装javaee6.0不成功解决方案

    64位windows系统安装javaee6.0不成功解决方案 (2013-01-19 14:59:51) 转载▼ 标签: 杂谈   could not find the required versio ...

  10. 面向对象(PHP学习)

    在对超大型项目的开发过程中,如果使用面向过程地开发,代码量是非常的庞大,这将大量的用到判断和循环嵌套, 和很多很相似的代码,不仅使项目代码量更加的庞大,还不利于开发,重用及维护. 面向对象就能很好的解 ...