【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3160|回复: 1

【转贴】Render to Texture(渲染到纹理)

[复制链接]
发表于 2008-7-12 03:46:22 | 显示全部楼层 |阅读模式
.内容
   渲染到纹理是D3D中的一项高级技术。一方面,它很简单,另一方面它很强大并能产生很多特殊效果。 比如说发光效果,环境映射,阴影映射,都可以通过它来实现。渲染到纹理只是渲染到表面的一个延伸。我们只需再加些东西就可以了。首先,我们要创造一个纹理,并且做好一些防范措施。第二步我们就可以把适当的场景渲染到我们创建的纹理上了。然后,我们把这个纹理用在最后的渲染上。

.main.cpp
   首先我们得声明所需要的对象。当然我们需要一张用来渲染的纹理。此外,我们还需要两个Surface对象。一个是用来存储后台缓冲区,一个用来当纹理的渲染对象。后面我再详细介绍它们。另外我们还需要两个矩阵,一个是用来当纹理的投影矩阵,另一个是存储原来的矩阵。

LPDIRECT3DTEXTURE9 pRenderTexture = NULL;
LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL;
D3DXMATRIX matProjection,matOldProjection;

   现在我们来创建纹理。前两个参数是纹理的宽度和高度,第三个参数是纹理的多级渐进纹理序列参数,在这里是设为1,第四个参数非常重要而且必须设为D3DUSAGE_RENDERTARGET,表明我们所创建的纹理是用来渲染的。剩下的参数就是指纹理格式,顶点缓冲区的内存位置,和一个指向纹理的指针。当纹理是用来当渲染对象时,顶点缓冲区的内存位置必须设为D3D_DEFAILT。

g_App.GetDevice()->CreateTexture(256,256,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&pRenderTexture,NULL);

   为了访问纹理内存对象,我们需要一个Surface对象,因为D3D中的纹理是用这样的一个Surface来存储纹理数据的。为了得到纹理表面的Surface,我们需要调用方法GetSurfaceLevel() 。第一个参数我们设为0,第二个参数为一个指向surface对象的指针。

pRenderTexture->GetSurfaceLevel(0,&pRenderSurface);

下一步就是创建一个适合纹理维数的投影矩阵,因为纹理的横纵比和后台缓冲区的不一样。

D3DXMatrixPerspectiveFovLH(&matProjection,D3DX_PI / 4.0f,1,1,100);

在我们的循环渲染之前,我们必须保存后台缓冲区和它的投影矩阵。

g_App.GetDevice()->GetTransform(D3DTS_PROJECTION,&matOldProjection);
g_App.GetDevice()->GetRenderTarget(0,&pBackBuffer);

   渲染循环函数可以分为两个部分。第一部分是渲染到纹理的过程。因此,渲染对象必须设为纹理表面。然后我们就可以把东西渲染到这个对象上了。渲染到另一个表面上和正常地渲染到后台缓冲区差不多。只有一点不同,那就是先不调用Prensent()函数,因为纹理上的内容并不需要显示在屏幕上。象平时一样,我们先要重置表面颜色缓冲区,并且调用BeginSence()和EndSence()方法。为了能够适当的渲染,我们必须设置和纹理表面相符的投影矩阵。否则最后的图象可能被扭曲

//render-to-texture
g_App.GetDevice()->SetRenderTarget(0,pRenderSurface); //set new render target
g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,100,100),1.0f,0); //clear texture
g_App.GetDevice()->BeginScene();

g_App.GetDevice()->SetTexture(0,pPyramideTexture);

D3DXMatrixRotationY(&matRotationY,fRotation);
D3DXMatrixTranslation(&matTranslation,0.0f,0.0f,5.0f);
g_App.GetDevice()->SetTransform(D3DTS_WORLD,&(matRotationY * matTranslation));
g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matProjection); //set projection matrix

g_App.GetDevice()->SetStreamSource(0,pTriangleVB,0,sizeof(D3DVERTEX));
g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST,0,4);

g_App.GetDevice()->EndScene();

   渲染循环的第二部分就是渲染最后场景的过程(也就是显示到屏幕上的过程)。渲染对象重新设为后台缓冲区,投影矩阵重新设为原来的投影矩阵。由于纹理已经准备好了,所以它和纹理层0相关联。

//render scene with texture
g_App.GetDevice()->SetRenderTarget(0,pBackBuffer); //set back buffer
g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
g_App.GetDevice()->BeginScene();

g_App.GetDevice()->SetTexture(0,pRenderTexture); //set rendered texture

g_App.GetDevice()->SetTransform(D3DTS_WORLD,&matTranslation);
g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matOldProjection); //restore projection matrix

g_App.GetDevice()->SetStreamSource(0,pQuadVB,0,sizeof(D3DVERTEX));
g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);

g_App.GetDevice()->EndScene();
g_App.GetDevice()->resent(NULL,NULL,NULL,NULL);

最后我们通过调用Release()方法释放Surface对象。

pRenderSurface->Release();
pRenderSurface = NULL;

pBackBuffer->Release();
pBackBuffer = NULL;

   渲染到纹理能让你做很多事情,但是你必须注意一些限制。首先深度缓冲区必须总是大于或等于渲染对象的大小。此外,渲染对象和深度缓冲区的格式必须一致。
 楼主| 发表于 2008-7-12 03:48:02 | 显示全部楼层
RenderToTexture.JPG

#include < D3DX9.h >
#include < string >
typedef std:: string String;
#define SAFE_RELEASE(o) {if(o){o->Release();o = 0;}}


LPDIRECT3D9 g_pD3D = 0 ; // D3D Driver
LPDIRECT3DDEVICE9 g_pd3dDevice = 0 ; // D3D 设备
D3DCAPS9 g_Caps = {(D3DDEVTYPE) 0 } ; // D3D 的帽子
LPD3DXMESH g_pMeshTeapot = 0 ; // 茶壶顶点缓冲区
LPDIRECT3DVERTEXBUFFER9 g_pVB = 0 ; // 顶点缓冲区
LPDIRECT3DINDEXBUFFER9 g_pIB = 0 ; // 索引缓冲区
LPDIRECT3DTEXTURE9 g_pTexture = 0 ; // 贴图
LPDIRECT3DTEXTURE9 g_pRenderTexture = 0 ; // 渲染到贴图
LPDIRECT3DSURFACE9 g_pRenderSurface = 0 ; // 渲染到贴图的表面
// 顶点定义
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
struct CUSTOMVERTEX
{
D3DXVECTOR3 position;
D3DCOLOR color;
float u , v;
} ;

// 错误记录
void D3DErr(String strMsg)
{
MessageBox( 0 , strMsg.c_str() , " 错误 " , MB_OK);
}

// 初始化顶点缓冲区
HRESULT InitVB()
{
// 创建茶壶
if (FAILED(D3DXCreateTeapot(g_pd3dDevice , & g_pMeshTeapot , 0 )))
return E_FAIL;
// 创建顶点缓冲区
if (FAILED(g_pd3dDevice -> CreateVertexBuffer( 4 * sizeof (CUSTOMVERTEX) , 0 , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & g_pVB , 0 )))
return E_FAIL;

CUSTOMVERTEX * pVertecies;
// 锁定缓冲区
if (SUCCEEDED(g_pVB -> Lock( 0 , 0 , ( void ** ) & pVertecies , 0 )))
{
pVertecies[ 0 ].position = D3DXVECTOR3( - 1 , 1 , 0 );
pVertecies[ 1 ].position = D3DXVECTOR3( - 1 , - 1 , 0 );
pVertecies[ 2 ].position = D3DXVECTOR3( 1 , 1 , 0 );
pVertecies[ 3 ].position = D3DXVECTOR3( 1 , - 1 , 0 );

pVertecies[ 0 ].u = 0 ;
pVertecies[ 0 ].v = 0 ;

pVertecies[ 1 ].u = 0 ;
pVertecies[ 1 ].v = 1 ;

pVertecies[ 2 ].u = 1 ;
pVertecies[ 2 ].v = 0 ;

pVertecies[ 3 ].u = 1 ;
pVertecies[ 3 ].v = 1 ;

pVertecies[ 0 ].color = 0xFFFFFFFF ;
pVertecies[ 1 ].color = 0xFFFFFFFF ;
pVertecies[ 2 ].color = 0xFFFFFFFF ;
pVertecies[ 3 ].color = 0xFFFFFFFF ;
g_pVB -> Unlock();
}
else
{
return E_FAIL;
}

// 载入纹理
if (FAILED(D3DXCreateTextureFromFile(g_pd3dDevice , " ..\\BRICE.JPG " , & g_pTexture)))
{
D3DErr( " 无法载入纹理Brice.jpg " );
return E_FAIL;
}

// 创建渲染到贴图的表面
if (FAILED(g_pd3dDevice -> CreateTexture( 512 , 512 , 1 , D3DUSAGE_RENDERTARGET , D3DFMT_A8R8G8B8 , D3DPOOL_DEFAULT , & g_pRenderTexture , 0 )))
{
D3DErr( " 无法创建渲染贴图 " );
return E_FAIL;
}
// 获取贴图的渲染表面
if (FAILED(g_pRenderTexture -> GetSurfaceLevel( 0 , & g_pRenderSurface)))
{
return E_FAIL;
}
return S_OK;
}

// 初始化模型
HRESULT InitGeometry()
{
// 创建顶点缓冲区
if (FAILED(InitVB()))
return E_FAIL;
return S_OK;
}

// 设置矩阵变换
void SetTransform()
{

// 世界变换
D3DXMATRIX matWorld;
D3DXMatrixIdentity( & matWorld);
// 设置世界矩阵
g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);
// Set up our view matrix. A view matrix can be defined given an eye point,
// a point to lookat, and a direction for which way is up. Here, we set the
// eye five units back along the z-axis and up three units, look at the
// origin, and define "up" to be in the y-direction.
// 视口变换
D3DXMATRIX matView;
D3DXMatrixLookAtLH( & matView , & D3DXVECTOR3( 0 , 0 , - 5 )
, & D3DXVECTOR3( 0 , 0 , 0 )
, & D3DXVECTOR3( 0 , 1 , 0 ));
g_pd3dDevice -> SetTransform(D3DTS_VIEW , & matView);
// For the projection matrix, we set up a perspective transform (which
// transforms geometry from 3D view space to 2D viewport space, with
// a perspective divide making objects smaller in the distance). To build
// a perpsective transform, we need the field of view (1/4 pi is common),
// the aspect ratio, and the near and far clipping planes (which define at
// what distances geometry should be no longer be rendered).
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 800.0f / 600.0f , 1.0f , 100.0f );
g_pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );


}

// 渲染场景
void Render()
{
if (g_pd3dDevice)
{
LPDIRECT3DSURFACE9 pRenderTarget;
// 保存渲染表面
g_pd3dDevice -> GetRenderTarget( 0 , & pRenderTarget);
// 设置我们的贴图表面
g_pd3dDevice -> SetRenderTarget( 0 , g_pRenderSurface);
// 清空场景,渲染到贴图的背景是蓝色的
g_pd3dDevice -> Clear( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0 , 0 , 0xFF ) , 1 , 0 );
// 开始渲染到贴图
if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
{
// 设置通常的矩阵
SetTransform();
D3DXMATRIX matWorld;
// 旋转茶壶
D3DXMatrixRotationAxis( & matWorld , & D3DXVECTOR3( 1 , 0 , 1 ) , D3DX_PI * 2.0f * (timeGetTime() % 5000 ) / 5000.0f );
g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);

// 设置渲染到表面的投影矩阵(这里可有可无,因为我们的窗口创建是512?12的)
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , 1.0f , 1.0f , 100.0f );
g_pd3dDevice -> SetTransform( D3DTS_PROJECTION, & matProj );

// 设置贴图
g_pd3dDevice -> SetTexture( 0 , g_pTexture);
g_pd3dDevice -> SetSamplerState( 0 , D3DSAMP_ADDRESSU , D3DTADDRESS_MIRROR);
g_pd3dDevice -> SetSamplerState( 0 , D3DSAMP_ADDRESSV , D3DTADDRESS_MIRROR);
// 自动生成纹理坐标
g_pd3dDevice -> SetTextureStageState( 0 , D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
g_pd3dDevice -> SetTextureStageState( 0 , D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_SPHEREMAP);
g_pd3dDevice -> SetRenderState(D3DRS_LIGHTING , FALSE);
// 渲染茶壶
g_pMeshTeapot -> DrawSubset( 0 );
g_pd3dDevice -> EndScene();
}


// 恢复渲染表面为显示器
g_pd3dDevice -> SetRenderTarget( 0 , pRenderTarget);

// 清空场景,真实场景是红色背景的
g_pd3dDevice -> Clear( 0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0xFF , 0xFF , 0 ) , 1 , 0 );
// 开始渲染真实场景
if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
{
SetTransform();
D3DXMATRIX matWorld;
// 旋转表面
D3DXMatrixRotationAxis( & matWorld , & D3DXVECTOR3( 1 , 1 , 0 ) , sinf(D3DX_PI * 2.0f * (timeGetTime() % 5000 ) / 5000.0f ));
// 设置世界矩阵
g_pd3dDevice -> SetTransform(D3DTS_WORLD , & matWorld);
// 设置已经渲染到表面的贴图
g_pd3dDevice -> SetTexture( 0 , g_pRenderTexture);
g_pd3dDevice -> SetTextureStageState( 0 , D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
g_pd3dDevice -> SetTextureStageState( 0 , D3DTSS_TEXCOORDINDEX, 0 );

g_pd3dDevice -> SetSamplerState( 0 , D3DSAMP_ADDRESSU , D3DTADDRESS_MIRROR);
g_pd3dDevice -> SetSamplerState( 0 , D3DSAMP_ADDRESSV , D3DTADDRESS_MIRROR);
g_pd3dDevice -> SetRenderState(D3DRS_LIGHTING , FALSE);
// g_pd3dDevice->SetRenderState(D3DRS_FILLMODE , D3DFILL_WIREFRAME);
g_pd3dDevice -> SetStreamSource( 0 , g_pVB , 0 , sizeof (CUSTOMVERTEX));
g_pd3dDevice -> SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice -> DrawPrimitive(D3DPT_TRIANGLESTRIP , 0 , 2 );
g_pd3dDevice -> EndScene();
}
// 显示
g_pd3dDevice -> Present( 0 , 0 , 0 , 0 );
}
}

// 初始化 D3D 设备
HRESULT InitD3D(HWND hWnd)
{
// 创建 D3D Driver
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
{
D3DErr( " 无法创建Direct3D9设备 " );
return E_FAIL;
}
// 获取当前显示模式
D3DDISPLAYMODE d3ddm;
if (FAILED(g_pD3D -> GetAdapterDisplayMode(D3DADAPTER_DEFAULT , & d3ddm)))
{
D3DErr( " 无法获取D3D显示器模式 " );
return E_FAIL;
}

RECT rect;
::GetClientRect(hWnd , & rect);

// 填充参数
D3DPRESENT_PARAMETERS d3dpp;
memset( & d3dpp , 0 , sizeof (d3dpp));
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.BackBufferWidth = rect.right;
d3dpp.BackBufferHeight = rect.bottom;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = true ;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.EnableAutoDepthStencil = TRUE;

// 获取帽子
if (FAILED(g_pD3D -> GetDeviceCaps(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , & g_Caps)))
{
D3DErr( " 获取D3D 帽子时发生错误 " );
return E_FAIL;
}

// 创建D3D设备
if (FAILED(g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT
, D3DDEVTYPE_HAL
, hWnd
// 检查是否支持硬件顶点处理
, g_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING
, & d3dpp
, & g_pd3dDevice
)
))
{
D3DErr( " 创建D3D设备时发生错误 " );
return E_FAIL;
}
g_pd3dDevice -> SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
g_pd3dDevice -> SetRenderState( D3DRS_ZENABLE, TRUE );

if (FAILED(InitGeometry()))
return E_FAIL;
return S_OK;
}

// 清空所有占用的资源
void CleanUp()
{
SAFE_RELEASE(g_pTexture);
SAFE_RELEASE(g_pIB);
SAFE_RELEASE(g_pVB);
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pD3D);
}


// 消息处理
LRESULT WINAPI MsgProc(HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
CleanUp();
PostQuitMessage( 0 );
break ;
}
return :efWindowProc(hWnd, message , wParam , lParam);
}

// Windows 入口
int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
WNDCLASS wndClass;
memset( & wndClass , 0 , sizeof (wndClass));
wndClass.hInstance = hInstance;
wndClass.lpszClassName = " 渲染到纹理 " ;
wndClass.lpfnWndProc = MsgProc;
RegisterClass( & wndClass);

// 创建窗口
HWND hWnd = CreateWindow( " 渲染到纹理 " , " 渲染到纹理! "
, 0 , 0 , 0 , 640 , 480 , GetDesktopWindow()
, 0 , wndClass.hInstance , 0 );
// 显示窗口
ShowWindow(hWnd , SW_SHOWDEFAULT);
UpdateWindow(hWnd);

// 初始化 D3D 设备
if (SUCCEEDED(InitD3D(hWnd)))
{
// 消息处理循环
MSG msg;
memset( & msg , 0 , sizeof (msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage( & msg , 0 , 0 , 0 , PM_REMOVE))
{
TranslateMessage( & msg);
DispatchMessage( & msg);
}
else
{
Render();
}
}
}
// 清空场景
CleanUp();

UnregisterClass( " 渲染到纹理 " , wndClass.hInstance);

return 0 ;
}

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 06:49

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表