基于DirectX11的MMDViewer04-渲染目标视图和多视口
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于DirectX11的MMDViewer04-渲染⽬标视图和多视⼝
上篇⽂章给出了⼀个简单并且可以运⾏的渲染框架,接下来将介绍框架中的渲染管线构成。
1、创建渲染管线
在你创建完⼀个窗⼝后,接着便要创建渲染管线,使⽤的函数是 D3D11CreateDeviceAndSwapChain,
交换链:
要创建交换链,必须先设置交换链描述。
交换链描述定义了将由交换链使⽤的渲染缓冲区的⼤⼩和数量。
它还将窗⼝与交换链相关联,从⽽确定最终图像的显⽰位置。
交换链描述还定义了该应⽤的消除锯齿(如果有的话)的质量以及在展⽰过程中后端缓冲区的翻转⽅式。
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] (其中 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 次,每次使⽤不同的视⼝,得到和上⾯⼀样的结果。
源码下载:。