基于 DirectX11 的 MMDViewer 04-渲染目标视图和多视口

  这篇文章主要介绍渲染管线输出部分的内容:交换链和渲染目标对象,并且介绍多视口渲染方法。

  交换链:



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

    UINT create_device_flags = 0;
#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 = 1;
    swap_desc.BufferDesc.Width = width;
    swap_desc.BufferDesc.Height = height;
    swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swap_desc.BufferDesc.RefreshRate.Numerator = 60;
    swap_desc.BufferDesc.RefreshRate.Denominator = 1;
    swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swap_desc.OutputWindow = g_hWnd;
    swap_desc.SampleDesc.Count = 1;
    swap_desc.SampleDesc.Quality = 0;
    swap_desc.Windowed = TRUE;

    for ( UINT driver_type_index = 0; 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(0, __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(1, &g_pRenderTargetView, 0);

  

  使用函数 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(1, 0, 0, 1);

    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 = 0;
    view_port.TopLeftY = 0;

    g_pImmediateContext->RSSetViewports(1, &view_port);

  

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

    D3D11_VIEWPORT view_port[4];
    for ( int i = 0; i < 4; i++ )
    {
        view_port[i].Width = ( FLOAT ) width / 2;
        view_port[i].Height = ( FLOAT ) height / 2;
        view_port[i].MinDepth = 0.0f;
        view_port[i].MaxDepth = 1.0f;
        view_port[i].TopLeftX = 0;
        view_port[i].TopLeftY = 0;
    }
    view_port[1].TopLeftX = ( FLOAT ) width / 2;
    view_port[1].TopLeftY = 0;

    view_port[2].TopLeftX = 0;
    view_port[2].TopLeftY = ( FLOAT ) height / 2;

    view_port[3].TopLeftX = ( FLOAT ) width / 2;
    view_port[3].TopLeftY = ( FLOAT ) height / 2;
    g_pImmediateContext->RSSetViewports(4, 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)0;
    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(12)]
void GS(triangle VS_OUTPUT input[3], inout TriangleStream<GS_OUTPUT> output)
{
    for(int j = 0; j < 4; j++)
    {
        GS_OUTPUT element;
        element.view_idx = j;

        for (uint i = 0; i < 3;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

原文地址:https://www.cnblogs.com/ForEmail5/p/8150432.html

时间: 2024-11-08 06:35:21

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

基于 DirectX11 的 MMDViewer 03-渲染管线(1)

准备工作: 开始搭建框架之前,你需要确保已经进行了 D3D 开发环境的搭建,相关教程可以阅读这篇文章.不了解 DirectX11 的人,这个作者有关 DirectX11 的教程最好阅读一下,虽然文章不多,但都很详细,有了基础以后在进行深一步的扩展. 和 OpenGL 一样,在渲染出图形之前,都需要经过很多步骤(窗口配置.图形上下文的创建.顶点数据配置.着色器的配置.变换矩阵配置等等),不是一两行代码就可以了.而 DirectX11 则更为复杂,其中如果发生一点错误,将导致图形渲染失败,但你难以检

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

项目的创建和配置: 1.新建一个 Win32 空项目 2.创建源码文件夹.库文件夹和资源文件夹 3.在 VS2013(我使用的 IDE 是 vs2013)配置这些文件夹 这里使用了 $(SolutionDir) 宏来指定上面创建的文件夹,因为使用的不是绝对路径,所以将项目拷贝到其他文件夹或电脑也可以正确读取.通过上面的设置,告诉程序去哪找到源码文件和库文件. 创建窗口: 创建窗口有几个固定的步骤,只要按照这些步骤来就好了,下面是创建的代码 HWND Create() { /* 设计窗口类 */

spring(6) 渲染web视图

[0]README 1)本文部分文字描述转自:"Spring In Action(中/英文版)",旨在review  "spring(6) 渲染web视图" 的相关知识: [1] 理解视图解析 [1.1]视图解析的基础知识以及spring 提供的其他视图解析器 1)spring mvc 定义了一个名为 ViewResolver的接口,如下 public interface ViewResolver { View resolveViewName(String view

Vuejs - 花式渲染目标元素

Vue.js是什么 摘自官方文档: Vue (读音 /vju?/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合.另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动. 对比其他框架? 一般提到一个框架时,大家都喜欢跟其他框架作对比,以说服读者去使用它,但是这里就不做对比了,是不是很失望?每个人都有每个人的

基于阿里云Ubuntu14.04 64bit部署WordPress博客系统

环境:基于阿里云Ubuntu14.04  64bit服务器系统 1, 安装apache2+mysql5+php5+php5-mysql sudo apt-get install apache2 sudo apt-get install php5 sudo apt-get install mysql-server sudo apt-get install php5-mysql sudo /etc/init.d/apache2 restart 至此重启了apache后应该就已经配置好服务器了,对此先

Ogre 渲染目标解析与多文本合并渲染

实现目标 因为需求,想找一个在Ogre中好用的文本显示,经过查找和一些比对.有三种方案 一利用Overlay的2D显示来达到效果. http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableTextOverlay 二重写Renderable与MovableObject,利用对应字体查找到每个字符元素纹理坐标. http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText 三利

LOG.ZS.0001.基于Freetype的游戏字体渲染优化思路

Total Utf8-ucs2 Html_parse Layout Render_string Init_texture Ft_load_glyph 原始 2293 1 26 708 1556 2 1403 上表用于记录优化各步骤的消耗时间. 生成的文本纹理,文本是加州宾馆的全歌词. 原始版本整个纹理的生成耗时2300毫秒左右,可以看到实际是慢得发指. 究其原因,是由于实现iron引擎的时候未进行任何性能方面的考虑. 上述时间表的构成: total : 总消耗时间 utf8-ucs2: 将utf

Spring Boot? 使用Thymeleaf模板引擎渲染web视图

静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static /public /resources /META-INF/resources 举例:我们可以在src/main/resources/目录下创建static,在该位置放置一个图片文件.启动程序后,尝试访问http://localhost:8080/D.jpg.如能显示图片,配置成功. 渲染

SeimiAgent——基于QtWebkit的通用网页渲染代理服务

SeimiAgent SeimiAgent是基于QtWebkit开发的可在服务器端后台运行的一个webkit服务,可以通过SeimiAgent提供的http接口向SeimiAgent发送一个load请求(需求加载的URL以及对这个页面接受的渲染时间或是使用什么代理等参数),通过SeimiAgent去加载并渲染想要处理的动态页面,然后将渲染好的页面直接返给调用方进行后续处理.SeimiAgent的加载渲染环境都是通用浏览器级的,所以不用担心他对动态页面的处理能力.目前SeimiAgent只支持返回