天天看點

在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