在direct 3d中支持直接渲染到贴图,使用手动的方式,还需要创建自己创建depth stencil。在d3dx中提供了ID3DXRenderToSurface接口简化了render to surface的操作,不再需要自己维护depth stencil。以下是渲染到贴图的基本步骤:
声明必要的接口:
CComPtr<ID3DXRenderToSurface> m_renderToSurface;
D3DVIEWPORT9 m_viewport;
CComPtr<IDirect3DTexture9> m_fullScreenTexture;
CComPtr<IDirect3DSurface9> m_fullScreenTextureSurf;
初始化阶段
// 创建全屏渲染贴图
FAILED_THROW_D3DEXCEPTION(D3DXCreateTexture(
pd3dDevice,
pBackBufferSurfaceDesc->Width,
pBackBufferSurfaceDesc->Height,
1,
0, //D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&m_fullScreenTexture));
FAILED_THROW_D3DEXCEPTION(m_fullScreenTexture->GetSurfaceLevel(0, &m_fullScreenTextureSurf));
// 创建 RenderToSurface
D3DSURFACE_DESC desc;
FAILED_THROW_D3DEXCEPTION(m_fullScreenTextureSurf->GetDesc(&desc));
FAILED_THROW_D3DEXCEPTION(D3DXCreateRenderToSurface(
pd3dDevice,
desc.Width,
desc.Height,
desc.Format,
TRUE,
D3DFMT_D16,
&m_renderToSurface));
// 保存一下viewport
pd3dDevice->GetViewport(&m_viewport);
// 清理一下render target,防止alpha绑定问题
HRESULT hr;
V(m_renderToSurface->BeginScene(m_fullScreenTextureSurf, &m_viewport));
V(pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00, 1.0f, 0));
V(m_renderToSurface->EndScene(0));
物体渲染到贴图
// 将模型渲染到贴图的surface上
if(SUCCEEDED(m_renderToSurface->BeginScene(m_fullScreenTextureSurf, &m_viewport)))
{
V(pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0));
...
V(m_renderToSurface->EndScene(0));
}
再将整个贴图渲染到屏幕
// 将目标贴图渲染到屏幕上
if(SUCCEEDED(pd3dDevice->BeginScene()))
{
V(pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0));
// 声明一个方形的矩形顶点格式
struct VERTEX
{
FLOAT x, y, z, w;
FLOAT u, v;
} vertices[] =
{
{ m_viewport.X, m_viewport.Y, 0.5f, 1.0f, 0.0f, 0.0f, },
{ m_viewport.X + m_viewport.Width, m_viewport.Y, 0.5f, 1.0f, 1.0f, 0.0f, },
{ m_viewport.X, m_viewport.Y + m_viewport.Height, 0.5f, 1.0f, 0.0f, 1.0f, },
{ m_viewport.X + m_viewport.Width, m_viewport.Y + m_viewport.Height, 0.5f, 1.0f, 1.0f, 1.0f, },
};
// 将贴图以矩形的方式直接渲染到屏幕
V(pd3dDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1));
V(pd3dDevice->SetTexture(0, m_fullScreenTexture));
V(pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1));
V(pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ));
V(pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, _countof(vertices) - 2, vertices, sizeof(vertices[0])));
V(pd3dDevice->EndScene());
}
总结:
渲染到贴图有很多实际作用,如实现画中画,但常用的是用来实现景深的一种手段,现将场景渲染到贴图并保存对应的深度值,在将贴图渲染到屏幕的时候,对贴图进行抖动模糊,并根据深度来决定模糊插值,从而实现模拟“景深”的一种手段。
但是渲染到贴图本身也有很多缺陷,其性能会下降大致2/3,且最为重要的是“不支持multisample”,目前普遍的解决方法(针对dx9)就是使用IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::StretchRect