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

  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. 监听器(Listener)学习(二)在开发中的常见应用

    监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用: 统计当前在线人数 自定义Session扫描器 一.统计当前在线人数 在JavaWeb应用开发中,有时候 ...

  2. BZOJ4547 Hdu5171 小奇的集合 【矩阵快速幂优化递推】

    BZOJ4547 Hdu5171 小奇的集合 Description 有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值.(数据保证这个 ...

  3. 将美化进行到底,把 PowerShell 做成 oh-my-zsh 的样子

    不知你有没有看过 Linux 上 oh-my-zsh 的样子?看过之后你一定会惊叹,原来命令行还能这么玩!然而 Windows 下能这么玩吗?答案是可行的,接下来就来看看怎么玩. Windows 下我 ...

  4. globalalloc、malloc和new的区别

    简单来说: malloc是c分配内存的库函数,new是c++分配内存的操作符,而globalalloc是win32提供的分配内存的API malloc不能自动调用构造和析构函数,在c++中没什么实用价 ...

  5. Promise详解

    前言 && 基础概念 Promise 是解决 JS 异步的一种方案,相比传统的回调函数,Promise 能解决多个回调严重嵌套的问题. Promise 对象代表一个异步操作,有三种状态 ...

  6. ASP.NET性能优化原则

    从哪些方面对asp.net进行性能优化,本文作了详细的阐述,希望对大家有所帮助. 一.SqlDataRead和Dataset的选择Sqldataread优点:读取数据非常快.如果对返回的数据不需做大量 ...

  7. C#数据路接口中获取SQL数据的用法

    获取一条记录 string sql = string.Format(“”); DataRow row; if (GetFirstDataRow(sql, out row))      {        ...

  8. Eclipse的maven工具

    左侧是组件以及组件依赖树(层级结构):右侧是识别出来的所有的组件:  

  9. NetCore 下集成SignalR并进行分组处理

    Tips: 1.注意跟普通版Net.MVC的前端处理方式不一样,以前可以connection.start()后直接done里面再做逻辑处理,现在不行了 建议做法是在具体的业务Hub里重写OnConne ...

  10. mqtt 异步消息 长连接 解析

    mqtt 是轻量级基于代理的发布/订阅的消息传输协议,设计思想是开放,简单,轻量级,且易于实现,这些优点使得他受用于任何环境 该协议的特点有: 使用发布/订阅消息的模式,提供一对多的消息发布,解除应用 ...