• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
hhdllhflower
博客园    首页    新随笔    联系   管理    订阅  订阅

Render To Texture

什么是纹理

熟悉DX的兄弟们都知道什么叫纹理了,这里简单介绍一下,先看看现实生活中的例子吧,其实纹理的例子比比皆是,比如地板,墙面都是纹理。在图形学中,纹理主要是为了增强场景的真实感,比如你想绘制一个地面,简单一点可以直接使用一个矩形,稍微复杂一点可以用三角形网格,再复杂一点可以使用地面纹理,有了纹理以后真实感明显增强了。DX中的纹理其实就是就是对现实生活中纹理的模拟,但是它不仅仅是一张图片那么简单,有着完整的数据结构,比如宽度,高度,内存类型,表面(Surface)等。

渲染到纹理

常规的渲染操作都是直接将场景呈现到backbuffer中的,backbuffer说白了其实就是一个表面,再说白了就是一块内存,场景通过绘制函数载入显存后,再通过Present函数送至显示器。那么为什么还要渲染到纹理呢?这是为了实现一些特殊的效果,比如常见的环境映射,简单的说,想象你有一个光滑的球体,它应该是可以反射周围的物体的,这就是环境映射。

实现步骤

上面说了常规的渲染操作是将场景送至backbuffer,而backbuffer实际上是一个Surface,而纹理恰恰又包含了Surface,所以我们只需要取得纹理的Surface,其次将场景送至这个Surface,最后再把这个纹理渲染到backbuffer中即可。举个例子,假设你要在一面墙壁上画一幅画,你有两种方法

1 直接在墙上画,这个很好理解,就对应常规的backbuffer渲染。

2 先将画画在纸上,然后将纸贴到墙上,这就对应渲染到纹理的过程。

这里墙壁相当于backbuffer,而纸张相当于纹理的Surface,在纸上作画相当于渲染到纹理,把纸贴到墙上相当于把纹理渲染到backbuffer,希望大家没有迷糊就好。具体的步骤如下

1 创建纹理并获得纹理的表面(Surface)

2 向纹理的表面渲染场景

3 渲染纹理本身

创建纹理并获取纹理表面

为了在纹理上渲染,我们应该先准备一个纹理,使用DX的函数CreateTexture就可以创建一个纹理了,注意在设置参数的时候需要将usage设置为D3DUSAGE_RENDERTARGET,因为只有这样才能在纹理上渲染。

 

IDirect3DTexture9*        g_pRenderTexture    = NULL ;

 

// Create texture

HRESULT hr = g_pd3dDevice->CreateTexture(

256,

256,

1,

D3DUSAGE_RENDERTARGET,

D3DFMT_R5G6B5,

D3DPOOL_DEFAULT,

&g_pRenderTexture,

NULL) ;

if (FAILED(hr))

{

MessageBox(NULL, "Create texture failed!", "Error", 0) ;

return E_FAIL ;

}

下面我们要取得纹理对应的Surface,以便在其上绘制场景,

 

IDirect3DSurface9*        g_pRenderSurface    = NULL ;

 

// Get texture surface

hr = g_pRenderTexture->GetSurfaceLevel(0, &g_pRenderSurface) ;

if (FAILED(hr))

{

MessageBox(NULL, "Get surface on texture failed!", "Error", 0) ;

return E_FAIL ;

}

将场景渲染至纹理表面

下面开始向纹理的Surface中绘制场景,为了简单起见,这里绘制一个茶壶,需要注意的是,绘制时需要将纹理的表面设置为当前的RenderTarget,所以首先要保存原来的RenderTarget。

 

//保存旧的RenderTarget

g_pd3dDevice->GetRenderTarget(0, &g_pOldRenderTarget) ;

 

//设置纹理表面为当前RenderTarget

g_pd3dDevice->SetRenderTarget(0, g_pRenderSurface) ;

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0 );

 

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )

{

g_pd3dDevice->SetTexture(0, NULL) ;

 

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );

g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME) ;

g_pTeapotMesh->DrawSubset(0) ; // 绘制茶壶

 

g_pd3dDevice->EndScene();

}

渲染纹理本身

接下来将纹理渲染到backbuffer,在这之前要恢复原来的RenderTarget,因为这次是将纹理送到backbuffer,而backbuff而就是原来的RenderTarget。

 

// 恢复RenderTarget

g_pd3dDevice->SetRenderTarget(0, g_pOldRenderTarget) ;

 

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff00ff00, 1.0f, 0 );

 

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )

{

g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID) ;

 

//绘制纹理

RenderQuad() ;

 

g_pd3dDevice->EndScene();

}

 

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

虽然是两次渲染,但是只需要调用一次present函数,因为之前的绘制只是将场景送至显存,而Present函数才真正将场景显示出来。

上面的代码用到了自定义函数RenderQuad,这个函数将纹理渲染出来,细节如下

 

void RenderQuad()

{

// Setup texture

g_pd3dDevice->SetTexture(0, g_pRenderTexture) ;

g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

g_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU,  D3DTADDRESS_WRAP );

g_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV,  D3DTADDRESS_WRAP );

 

// Set stream source

g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(Vertex) );

g_pd3dDevice->SetFVF(VertexFVF) ;

 

g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2) ;

}

 

源文档 <http://www.cnblogs.com/graphics/archive/2011/04/23/2024294.html> 

posted @ 2012-10-04 20:35  hhdllhflower  阅读(681)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3