天天看点

在direct 3d中使用渲染到贴图的技巧

在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