DirectX11 With Windows SDK--24 Render-To-Texture(RTT)技术的应用
原文:DirectX11 With Windows SDK--24 Render-To-Texture(RTT)技术的应用

前言

尽管在上一章的动态天空盒中用到了Render-To-Texture技术,但那是针对纹理立方体的特化实现。考虑到该技术的应用层面非常广,在这里抽出独立的一章专门来讲有关它的通用实现以及各种应用。

章节回顾
深入理解与使用2D纹理资源(重点阅读ScreenGrab库)
23 立方体映射:动态天空盒的实现

DirectX11 With Windows SDK完整目录

Github项目源码

欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

再述Render-To-Texture技术

在前面的章节中,我们默认的渲染目标是来自DXGI后备缓冲区,它是一个2D纹理。而Render-To-Texture技术,实际上就是使用一张2D纹理作为渲染目标,但一般是自己新建的2D纹理。与此同时,这个纹理还能够绑定到着色器资源视图(SRV)供着色器所使用,即原本用作输出的纹理现在用作输入。

它可以用于:

  1. 小地图的实现
  2. 阴影映射(Shadow mapping)
  3. 屏幕空间环境光遮蔽(Screen Space Ambient Occlusion)
  4. 利用天空盒实现动态反射/折射(Dynamic reflections/refractions with cube maps)

在这一章,我们将展示下面这三种应用:

  1. 屏幕淡入/淡出
  2. 小地图(有可视范围的)
  3. 保存纹理到文件

TextureRender类

该类借鉴了上一章DynamicSkyEffect的实现,因此也继承了它简单易用的特性:

class TextureRender
{
public:template<class T>using ComPtr = Microsoft::WRL::ComPtr<T>;TextureRender(ID3D11Device * device,int texWidth, int texHeight,bool generateMips = false);~TextureRender();// 开始对当前纹理进行渲染void Begin(ID3D11DeviceContext * deviceContext);// 结束对当前纹理的渲染,还原状态void End(ID3D11DeviceContext * deviceContext);// 获取渲染好的纹理ID3D11ShaderResourceView * GetOutputTexture();// 设置调试对象名void SetDebugObjectName(const std::string& name);private:ComPtr<ID3D11ShaderResourceView>    m_pOutputTextureSRV;    // 输出的纹理对应的着色器资源视图ComPtr<ID3D11RenderTargetView>      m_pOutputTextureRTV;    // 输出的纹理对应的渲染目标视图ComPtr<ID3D11DepthStencilView>      m_pOutputTextureDSV;    // 输出纹理所用的深度/模板视图D3D11_VIEWPORT                      m_OutputViewPort;       // 输出所用的视口ComPtr<ID3D11RenderTargetView>      m_pCacheRTV;            // 临时缓存的后备缓冲区ComPtr<ID3D11DepthStencilView>      m_pCacheDSV;            // 临时缓存的深度/模板缓冲区D3D11_VIEWPORT                      m_CacheViewPort;        // 临时缓存的视口bool                                m_GenerateMips;         // 是否生成mipmap链
};

它具有如下特点:

  1. 支持任意宽高的纹理(在初始化时确定),因为它内置了一个独立的深度/模板缓冲区
  2. 使用BeginEnd方法,确保在这两个方法调用之间的所有绘制都将输出到该纹理
  3. Begin方法会临时缓存后备缓冲区、深度/模板缓冲区和视口,并在End方法恢复,因此无需自己去重新设置这些东西

TextureRender初始化

现在我们需要完成下面5个步骤:

  1. 创建纹理
  2. 创建纹理对应的渲染目标视图
  3. 创建纹理对应的着色器资源视图
  4. 创建与纹理等宽高的深度/模板缓冲区和对应的视图
  5. 初始化视口

具体代码如下:

TextureRender::TextureRender(ID3D11Device * device, int texWidth, int texHeight, bool generateMips): m_GenerateMips(generateMips), m_CacheViewPort()
{// ******************// 1. 创建纹理//ComPtr<ID3D11Texture2D> texture;D3D11_TEXTURE2D_DESC texDesc;texDesc.Width = texWidth;texDesc.Height = texHeight;texDesc.MipLevels = (m_GenerateMips ? 0 : 1);   // 0为完整mipmap链texDesc.ArraySize = 1;texDesc.SampleDesc.Count = 1;texDesc.SampleDesc.Quality = 0;texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;texDesc.Usage = D3D11_USAGE_DEFAULT;texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;texDesc.CPUAccessFlags = 0;texDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;// 现在texture用于新建纹理HR(device->CreateTexture2D(&texDesc, nullptr, texture.ReleaseAndGetAddressOf()));// ******************// 2. 创建纹理对应的渲染目标视图//D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;rtvDesc.Format = texDesc.Format;rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;rtvDesc.Texture2D.MipSlice = 0;HR(device->CreateRenderTargetView(texture.Get(),&rtvDesc,m_pOutputTextureRTV.GetAddressOf()));// ******************// 3. 创建纹理对应的着色器资源视图//D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;srvDesc.Format = texDesc.Format;srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;srvDesc.Texture2D.MostDetailedMip = 0;srvDesc.TextureCube.MipLevels = -1; // 使用所有的mip等级HR(device->CreateShaderResourceView(texture.Get(),&srvDesc,m_pOutputTextureSRV.GetAddressOf()));// ******************// 4. 创建与纹理等宽高的深度/模板缓冲区和对应的视图//texDesc.Width = texWidth;texDesc.Height = texHeight;texDesc.MipLevels = 0;texDesc.ArraySize = 1;texDesc.SampleDesc.Count = 1;texDesc.SampleDesc.Quality = 0;texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;texDesc.Usage = D3D11_USAGE_DEFAULT;texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;texDesc.CPUAccessFlags = 0;texDesc.MiscFlags = 0;ComPtr<ID3D11Texture2D> depthTex;device->CreateTexture2D(&texDesc, nullptr, depthTex.GetAddressOf());D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;dsvDesc.Format = texDesc.Format;dsvDesc.Flags = 0;dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;dsvDesc.Texture2D.MipSlice = 0;HR(device->CreateDepthStencilView(depthTex.Get(),&dsvDesc,m_pOutputTextureDSV.GetAddressOf()));// ******************// 5. 初始化视口//m_OutputViewPort.TopLeftX = 0.0f;m_OutputViewPort.TopLeftY = 0.0f;m_OutputViewPort.Width = static_cast<float>(texWidth);m_OutputViewPort.Height = static_cast<float>(texHeight);m_OutputViewPort.MinDepth = 0.0f;m_OutputViewPort.MaxDepth = 1.0f;
}

TextureRender::Begin方法--开始对当前纹理进行渲染

该方法缓存当前渲染管线绑定的渲染目标视图、深度/模板视图以及视口,并替换初始化好的这些资源。注意还需要清空一遍缓冲区:

void TextureRender::Begin(ID3D11DeviceContext * deviceContext)
{// 缓存渲染目标和深度模板视图deviceContext->OMGetRenderTargets(1, m_pCacheRTV.GetAddressOf(), m_pCacheDSV.GetAddressOf());// 缓存视口UINT num_Viewports = 1;deviceContext->RSGetViewports(&num_Viewports, &m_CacheViewPort);// 清空缓冲区float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };deviceContext->ClearRenderTargetView(m_pOutputTextureRTV.Get(), black);deviceContext->ClearDepthStencilView(m_pOutputTextureDSV.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);// 设置渲染目标和深度模板视图deviceContext->OMSetRenderTargets(1, m_pOutputTextureRTV.GetAddressOf(), m_pOutputTextureDSV.Get());// 设置视口deviceContext->RSSetViewports(1, &m_OutputViewPort);
}

TextureRender::End方法--结束对当前纹理的渲染,还原状态

在对当前纹理的所有绘制方法调用完毕后,就需要调用该方法以恢复到原来的渲染目标视图、深度/模板视图以及视口。若在初始化时还指定了generateMipstrue,还会给该纹理生成mipmap链:

void TextureRender::End(ComPtr<ID3D11DeviceContext> deviceContext)
{// 恢复默认设定deviceContext->RSSetViewports(1, &m_CacheViewPort);deviceContext->OMSetRenderTargets(1, m_pCacheRTV.GetAddressOf(), m_pCacheDSV.Get());// 若之前有指定需要mipmap链,则生成if (m_GenerateMips){deviceContext->GenerateMips(m_pOutputTextureSRV.Get());}// 清空临时缓存的渲染目标视图和深度模板视图m_pCacheDSV.Reset();m_pCacheRTV.Reset();
}

最后就可以通过TextureRender::GetOutputTexture方法获取渲染好的纹理了。

注意:不要将纹理既作为渲染目标,又作为着色器资源,虽然不会报错,但这样会导致程序运行速度被拖累。在VS的输出窗口你可以看到它会将该资源强制从着色器中撤离,置其为NULL,以保证不会同时绑定在输入和输出端。

屏幕淡入/淡出效果的实现

该效果对应的特效文件为ScreenFadeEffect.cpp,着色器文件为ScreenFade_VS.hlslScreenFade_PS.hlsl

ScreenFadeEffect类在这不做讲解,有兴趣的可以查看第13章的自定义Effects管理类实现教程,或者去翻看ScreenFadeEffect类的源码实现。

首先是ScreenFade.hlsli

// ScreenFade.hlsli
Texture2D gTex : register(t0);
SamplerState gSam : register(s0);cbuffer CBChangesEveryFrame : register(b0)
{float g_FadeAmount;      // 颜色程度控制(0.0f-1.0f)float3 g_Pad;
}cbuffer CBChangesRarely : register(b1)
{matrix g_WorldViewProj;
}struct VertexPosTex
{float3 PosL : POSITION;float2 Tex : TEXCOORD;
};struct VertexPosHTex
{float4 PosH : SV_POSITION;float2 Tex : TEXCOORD;
};

然后分别是对于的顶点着色器和像素着色器实现:

// ScreenFade_VS.hlsl
#include "ScreenFade.hlsli"// 顶点着色器
VertexPosHTex VS(VertexPosTex vIn)
{VertexPosHTex vOut;vOut.PosH = mul(float4(vIn.PosL, 1.0f), g_WorldViewProj);vOut.Tex = vIn.Tex;return vOut;
}
// ScreenFade_PS.hlsl
#include "ScreenFade.hlsli"// 像素着色器
float4 PS(VertexPosHTex pIn) : SV_Target
{return g_Tex.Sample(g_Sam, pIn.Tex) * float4(g_FadeAmount, g_FadeAmount, g_FadeAmount, 1.0f);
}

该套着色器通过gFadeAmount来控制最终输出的颜色,我们可以通过对其进行动态调整来实现一些效果。当gFadeAmount从0到1时,屏幕从黑到正常显示,即淡入效果;而当gFadeAmount从1到0时,平面从正常显示到变暗,即淡出效果。

一开始像素着色器的返回值采用的是和Rastertek一样的tex.Sample(sam, pIn.Tex) * gFadeAmount,但是在截屏出来的.dds文件观看的时候颜色变得很奇怪

原本以为是输出的文件格式乱了,但当我把Alpha通道关闭后,图片却一切正常了

故这里应该让Alpha通道的值乘上1.0f以保持Alpha通道的一致性

为了实现屏幕的淡入淡出效果,我们需要一张渲染好的场景纹理,即通过TextureRender来实现。

首先我们看GameApp::UpdateScene方法中用于控制屏幕淡入淡出的部分:

// 更新淡入淡出值
if (m_FadeUsed)
{m_FadeAmount += m_FadeSign * dt / 2.0f; // 2s时间淡入/淡出if (m_FadeSign > 0.0f && m_FadeAmount > 1.0f){m_FadeAmount = 1.0f;m_FadeUsed = false; // 结束淡入}else if (m_FadeSign < 0.0f && m_FadeAmount < 0.0f){m_FadeAmount = 0.0f;SendMessage(MainWnd(), WM_DESTROY, 0, 0);   // 关闭程序// 这里不结束淡出是因为发送关闭窗口的消息还要过一会才真正关闭}
}// ...// 退出程序,开始淡出
if (m_KeyboardTracker.IsKeyPressed(Keyboard::Escape))
{m_FadeSign = -1.0f;m_FadeUsed = true;
}

启动程序的时候,mFadeSign的初始值是1.0f,这样就使得打开程序的时候就在进行屏幕淡入。

而用户按下Esc键退出的话,则先触发屏幕淡出效果,等屏幕变黑后再发送关闭程序的消息给窗口。注意发送消息到真正关闭还相隔一段时间,在这段时间内也不要关闭淡出效果的绘制,否则最后那一瞬间又突然看到场景了。

然后在GameApp::DrawScene方法中,我们可以将绘制过程简化成这样:

// ******************
// 绘制Direct3D部分
//// 预先清空后备缓冲区
m_pd3dImmediateContext->ClearRenderTargetView(m_pRenderTargetView.Get(), reinterpret_cast<const float*>(&Colors::Black));
m_pd3dImmediateContext->ClearDepthStencilView(m_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);if (mFadeUsed)
{// 开始淡入/淡出m_pScreenFadeRender->Begin(m_pd3dImmediateContext.Get());
}// 绘制主场景...if (mFadeUsed)
{// 结束淡入/淡出,此时绘制的场景在屏幕淡入淡出渲染的纹理m_pScreenFadeRender->End(m_pd3dImmediateContext.Get());// 屏幕淡入淡出特效应用m_ScreenFadeEffect.SetRenderDefault(m_pd3dImmediateContext.Get());m_ScreenFadeEffect.SetFadeAmount(m_FadeAmount);m_ScreenFadeEffect.SetTexture(m_pScreenFadeRender->GetOutputTexture());m_ScreenFadeEffect.SetWorldViewProjMatrix(XMMatrixIdentity());m_ScreenFadeEffect.Apply(m_pd3dImmediateContext.Get());// 将保存的纹理输出到屏幕m_pd3dImmediateContext->IASetVertexBuffers(0, 1, m_FullScreenShow.modelParts[0].vertexBuffer.GetAddressOf(), strides, offsets);m_pd3dImmediateContext->IASetIndexBuffer(m_FullScreenShow.modelParts[0].indexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0);m_pd3dImmediateContext->DrawIndexed(6, 0, 0);// 务必解除绑定在着色器上的资源,因为下一帧开始它会作为渲染目标m_ScreenFadeEffect.SetTexture(nullptr);m_ScreenFadeEffect.Apply(m_pd3dImmediateContext.Get());
}

对了,如果窗口被拉伸,那我们之前创建的纹理宽高就不适用了,需要重新创建一个。在GameApp::OnResize方法可以看到:

void GameApp::OnResize()
{// ...// 摄像机变更显示if (mCamera != nullptr){// ...// 屏幕淡入淡出纹理大小重设m_pScreenFadeRender = std::make_unique<TextureRender>(m_pd3dDevice.Get(), m_ClientWidth, m_ClientHeight, false);}
}

由于屏幕淡入淡出效果需要先绘制主场景到纹理,然后再用该纹理完整地绘制到屏幕上,就不说前面还进行了大量的深度测试了,两次绘制下来使得在渲染淡入淡出效果的时候帧数下降比较明显。因此不建议经常这么做。

小地图的实现

关于小地图的实现,有许多种方式。常见的如下:

  1. 美术预先绘制一张地图纹理,然后再在上面绘制一些2D物件表示场景中的物体
  2. 捕获游戏场景的俯视图用作纹理,但只保留静态物体,然后再在上面绘制一些2D物件表示场景中的物体
  3. 通过俯视图完全绘制出游戏场景中的所有物体

可以看出,性能的消耗越往后要求越高。

因为本项目的场景是在夜间森林,并且树是随机生成的,因此采用第二种方式,但是地图可视范围为摄像机可视区域,并且不考虑额外绘制任何2D物件。

小地图对应的特效文件为MinimapEffect.cpp,着色器文件为Minimap_VS.hlslMinimap_PS.hlsl。同样这里只关注HLSL实现。

首先是Minimap.hlsli

// Minimap.hlsliTexture2D g_Tex : register(t0);
SamplerState g_Sam : register(s0);cbuffer CBChangesEveryFrame : register(b0)
{float3 g_EyePosW;            // 摄像机位置float g_Pad;
}cbuffer CBDrawingStates : register(b1)
{int g_FogEnabled;            // 是否范围可视float g_VisibleRange;        // 3D世界可视范围float2 g_Pad2;float4 g_RectW;              // 小地图xOz平面对应3D世界矩形区域(Left, Front, Right, Back)float4 g_InvisibleColor;     // 不可视情况下的颜色
}struct VertexPosTex
{float3 PosL : POSITION;float2 Tex : TEXCOORD;
};struct VertexPosHTex
{float4 PosH : SV_POSITION;float2 Tex : TEXCOORD;
};

为了能在小地图中绘制出局部区域可视的效果,还需要依赖3D世界中的一些参数。其中gRectW对应的是3D世界中矩形区域(即x最小值, z最大值, x最大值, z最小值)。

然后是顶点着色器和像素着色器的实现:

// Minimap_VS.hlsl
#include "Minimap.hlsli"// 顶点着色器
VertexPosHTex VS(VertexPosTex vIn)
{VertexPosHTex vOut;vOut.PosH = float4(vIn.PosL, 1.0f);vOut.Tex = vIn.Tex;return vOut;
}
// Minimap_PS.hlsl
#include "Minimap.hlsli"// 像素着色器
float4 PS(VertexPosHTex pIn) : SV_Target
{// 要求Tex的取值范围都在[0.0f, 1.0f], y值对应世界坐标z轴float2 PosW = pIn.Tex * float2(g_RectW.zw - g_RectW.xy) + g_RectW.xy;float4 color = g_Tex.Sample(g_Sam, pIn.Tex);[flatten]if (g_FogEnabled && length(PosW - g_EyePosW.xz) / g_VisibleRange > 1.0f){return g_InvisibleColor;}return color;
}

接下来我们需要通过Render-To-Texture技术,捕获整个场景的俯视图。关于小地图的绘制放在了GameApp::InitResource中:

bool GameApp::InitResource()
{// ...m_pMinimapRender = std::make_unique<TextureRender>(m_pd3dDevice.Get(), 400, 400, true);// 初始化网格,放置在右下角200x200m_Minimap.SetMesh(m_pd3dDevice, Geometry::Create2DShow(0.75f, -0.66666666f, 0.25f, 0.33333333f));// ...// 小地图摄像机m_MinimapCamera = std::unique_ptr<FirstPersonCamera>(new FirstPersonCamera);m_MinimapCamera->SetViewPort(0.0f, 0.0f, 200.0f, 200.0f);   // 200x200小地图m_MinimapCamera->LookTo(XMVectorSet(0.0f, 10.0f, 0.0f, 1.0f),XMVectorSet(0.0f, -1.0f, 0.0f, 1.0f),XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f));m_MinimapCamera->UpdateViewMatrix();// ...// 小地图范围可视m_MinimapEffect.SetFogState(true);m_MinimapEffect.SetInvisibleColor(XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f));m_MinimapEffect.SetMinimapRect(XMVectorSet(-95.0f, 95.0f, 95.0f, -95.0f));m_MinimapEffect.SetVisibleRange(25.0f);// 方向光(默认)DirectionalLight dirLight[4];dirLight[0].Ambient = XMFLOAT4(0.15f, 0.15f, 0.15f, 1.0f);dirLight[0].Diffuse = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);dirLight[0].Specular = XMFLOAT4(0.1f, 0.1f, 0.1f, 1.0f);dirLight[0].Direction = XMFLOAT3(-0.577f, -0.577f, 0.577f);dirLight[1] = dirLight[0];dirLight[1].Direction = XMFLOAT3(0.577f, -0.577f, 0.577f);dirLight[2] = dirLight[0];dirLight[2].Direction = XMFLOAT3(0.577f, -0.577f, -0.577f);dirLight[3] = dirLight[0];dirLight[3].Direction = XMFLOAT3(-0.577f, -0.577f, -0.577f);for (int i = 0; i < 4; ++i)m_BasicEffect.SetDirLight(i, dirLight[i]);// ******************// 渲染小地图纹理// m_BasicEffect.SetViewMatrix(m_MinimapCamera->GetViewXM());m_BasicEffect.SetProjMatrix(XMMatrixOrthographicLH(190.0f, 190.0f, 1.0f, 20.0f));   // 使用正交投影矩阵(中心在摄像机位置)// 关闭雾效m_BasicEffect.SetFogState(false);m_pMinimapRender->Begin(m_pd3dImmediateContext.Get());DrawScene(true);m_pMinimapRender->End(m_pd3dImmediateContext.Get());m_MinimapEffect.SetTexture(m_pMinimapRender->GetOutputTexture());// ...
}

通常小地图的制作,建议是使用正交投影矩阵,XMMatrixOrthographicLH函数的中心在摄像机位置,不以摄像机为中心的话可以用XMMatrixOrthographicOffCenterLH函数。

然后如果窗口大小调整,为了保证小地图在屏幕的显示是在右下角,并且保持200x200,需要在GameApp::OnResize重新调整网格模型:

void GameApp::OnResize()
{// ...// 摄像机变更显示if (mCamera != nullptr){// ...// 小地图网格模型重设m_Minimap.SetMesh(m_pd3dDevice.Get(), Geometry::Create2DShow(1.0f - 100.0f / m_ClientWidth * 2,  -1.0f + 100.0f / m_ClientHeight * 2, 100.0f / m_ClientWidth * 2, 100.0f / m_ClientHeight * 2));}
}

最后是GameApp::DrawScene方法将小地图纹理绘制到屏幕的部分:

// 此处用于小地图和屏幕绘制
UINT strides[1] = { sizeof(VertexPosTex) };
UINT offsets[1] = { 0 };// 小地图特效应用
m_MinimapEffect.SetRenderDefault(m_pd3dImmediateContext.Get());
m_MinimapEffect.Apply(m_pd3dImmediateContext.Get());
// 最后绘制小地图
m_pd3dImmediateContext->IASetVertexBuffers(0, 1, m_Minimap.modelParts[0].vertexBuffer.GetAddressOf(), strides, offsets);
m_pd3dImmediateContext->IASetIndexBuffer(m_Minimap.modelParts[0].indexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0);
m_pd3dImmediateContext->DrawIndexed(6, 0, 0);

项目演示

本项目的场景沿用了第20章的森林场景,并搭配了夜晚雾效,在打开程序后可以看到屏幕淡入的效果,按下Esc后则屏幕淡出后退出。

然后人物在移动的时候,小地图的可视范围也会跟着移动。

DirectX11 With Windows SDK完整目录

Github项目源码

欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

posted on 2019-05-05 10:01 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10811422.html

DirectX11 With Windows SDK--24 Render-To-Texture(RTT)技术的应用相关推荐

  1. 什么是渲染目标(render target) 渲染到纹理(Render To Texture, RTT)详解

    渲染到纹理(Render To Texture, RTT)详解 RTT是现在很多特效里面都会用到的一项很基本的技术,实现起来很简单,也很重要.但是让人不解的是网上搜索了半天只找到很少的文章说这个事儿, ...

  2. DirectX11 With Windows SDK--09 纹理映射与采样器状态

    DirectX11 With Windows SDK--09 纹理映射与采样器状态 原文:DirectX11 With Windows SDK--09 纹理映射与采样器状态 前言 在之前的Direct ...

  3. DirectX11 With Windows SDK--22 立方体映射:静态天空盒的读取与实现

    前言 这一章我们主要学习由6个纹理所构成的立方体映射,以及用它来实现一个静态天空盒. 但是在此之前先要消除两个误区: 认为这一章的天空盒就是简单的在一个超大立方体的六个面内部贴上天空盒纹理: 认为天空 ...

  4. DirectX11 With Windows SDK--17 利用几何着色器实现公告板效果

    DirectX11 With Windows SDK--17 利用几何着色器实现公告板效果 原文:DirectX11 With Windows SDK--17 利用几何着色器实现公告板效果 前言 上一 ...

  5. DirectX11 With Windows SDK--12 深度/模板状态、平面镜反射绘制

    前言 深度/模板测试使用的是与后备缓冲区同等分辨率大小的缓冲区,每个元素的一部分连续位用于深度测试,其余的则用作模板测试.两个测试的目的都是为了能够根据深度/模板状态需求的设置来选择需要绘制的像素. ...

  6. DirectX11 With Windows SDK--07 添加光照与常用几何模型、光栅化状态

    DirectX11 With Windows SDK--07 添加光照与常用几何模型.光栅化状态 原文:DirectX11 With Windows SDK--07 添加光照与常用几何模型.光栅化状态 ...

  7. DirectX11 With Windows SDK--36 延迟渲染基础

    前言 随着图形硬件变得越来越通用和可编程化,采用实时3D图形渲染的应用程序已经开始探索传统渲染管线的替代方案,以避免其缺点.其中一项最流行的技术就是所谓的延迟渲染.这项技术主要是为了支持大量的动态灯光 ...

  8. DirectX11 With Windows SDK--11 混合状态

    文章目录 前言 混合等式 混合等式 混合状态 混合运算符的设置 混合因子的设置 ID3D11Device::CreateBlendState方法--创建混合状态 ID3D11DeviceContext ...

  9. DirectX11 With Windows SDK--20 硬件实例化与视锥体裁剪

    DirectX11 With Windows SDK--20 硬件实例化与视锥体裁剪 原文:DirectX11 With Windows SDK--20 硬件实例化与视锥体裁剪 前言 这一章将了解如何 ...

最新文章

  1. 【PHP源码分析】small内存规格的计算
  2. 老赵谈IL(3):IL可以看到的东西,其实大都也可以用C#来发现
  3. 简单的错觉画_一看就错?眼睛厉害还是大神画的厉害!
  4. 服务器有操作系统吗,云服务器有操作系统吗
  5. java 三角依次递增在递减_java中用for循环怎样打印三角行啊,主要是不理解什么情况外层循环递增什么时候递减,如等腰三角形...
  6. 谁来执行Rebalance以及管理consumer的group呢?
  7. 树莓派与安卓手机app的WIFI通信(局域网通信)
  8. P1375-小猫【卡特兰数】
  9. 仿照小米官网项目具体操作与细节
  10. ES6-字符串扩展-padStart(),padEnd()
  11. 如何使用Java代码获取文件、文件流或字符串的编码方式
  12. QGIS教程02---QGIS加载数据的4种方法
  13. 关闭jupyter notebook报错:python.exe-应用程序错误
  14. Axis2创建web service(一) - eclipse安装Axis2插件
  15. EXCEL VBA 中关于斗牛的算法
  16. 绕过content-type检测文件类型上传webshell
  17. 《肖申克的救赎》观后
  18. 滑动轨迹生成的思路和代码分享-测试可过极验 90%机率
  19. 超市使用erp系统有哪些优势?
  20. 梦幻西游原服务器物品,角色转移服务器说明 物品转移携带有限制

热门文章

  1. javaScript(1):基础部分
  2. hahahahahah
  3. ScrollView’s handy trick
  4. JQuery 动画卷页 -- 返回顶部 动画特效(兼容Chrome)
  5. hdu 6386 Age of Moyu (重边判断)
  6. STL 二分查找 upper_bound和lower_bound用法
  7. ubuntu12.04 安装中文输入法
  8. setTimeout() 实现程序每隔一段时间自动执行
  9. 初试牛刀---css中的小细节
  10. SQLServer 2014 本地机房HA+灾备机房DR解决方案