渲染到纹理,顾名思义就是把渲染目标从帧缓存变成一个纹理。这样就可以把一个场景渲染后在进行Post Process,做出现在流行的各种特效。另外在利用GPU做通用计算的时候程序也是通过RTT和GPU交换数据的。
实现步骤:
这里需要注意的几点:
==========代码部分Direct3d9Device.h=====================================
#ifndef __Include_Direct3d9Device_h__
#define __Include_Direct3d9Device_h__
#include <assert.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"d3d9.lib")
class Direct3d9Device
{
public:
static Direct3d9Device& getSingleton(){
assert(mSingleInstance);
return *mSingleInstance;
};
static Direct3d9Device* getSingletonPtr(){
assert(mSingleInstance);
return mSingleInstance;
};
public:
Direct3d9Device();
~Direct3d9Device();
bool initiliase(HWND hWnd);
const LPDIRECT3DDEVICE9& getDevice() const{ assert(md3dDeviceHandle); return md3dDeviceHandle;};
std::string getDeviceName() { return d3dadapteride.Description;};
const LPDIRECT3D9& getDirect3dInterface() const { assert(md3dInterface); return md3dInterface;};
const D3DDISPLAYMODE& getDisplayMode() const { return d3dmd;};
protected:
static Direct3d9Device* mSingleInstance;
private:
D3DDISPLAYMODE d3dmd;
LPDIRECT3D9 md3dInterface;
LPDIRECT3DDEVICE9 md3dDeviceHandle;
D3DADAPTER_IDENTIFIER9 d3dadapteride;
};
#endif
===============Direct3d9Device.cpp=========================
#include "Direct3d9Device.h"
Direct3d9Device* Direct3d9Device::mSingleInstance = 0;
Direct3d9Device::Direct3d9Device()
:md3dInterface(0)
,md3dDeviceHandle(0)
{
mSingleInstance = this;
}
Direct3d9Device::~Direct3d9Device()
{
if(md3dDeviceHandle)
{
md3dDeviceHandle->Release();
md3dDeviceHandle = 0;
}
if(md3dInterface)
{
md3dInterface->Release();
md3dInterface = 0;
}
CoUninitialize();
}
bool Direct3d9Device::initiliase( HWND hWnd )
{
CoInitialize(0);
HRESULT hr;
md3dInterface = Direct3DCreate9(D3D_SDK_VERSION);
if(!md3dInterface)
return false;
ZeroMemory(&d3dmd,sizeof(D3DDISPLAYMODE));
md3dInterface->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dmd);
md3dInterface->GetAdapterIdentifier(D3DADAPTER_DEFAULT,0,&d3dadapteride);
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.Windowed = true;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferFormat = d3dmd.Format;
d3dpp.hDeviceWindow = hWnd;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Flags = 0;
d3dpp.AutoDepthStencilFormat = D3DFMT_X8B8G8R8;
d3dpp.EnableAutoDepthStencil = FALSE;
d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
d3dpp.MultiSampleQuality = 0;
d3dpp.BackBufferHeight = 60;
d3dpp.BackBufferWidth = 990;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = 0;
hr = md3dInterface->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,&d3dpp,&md3dDeviceHandle);
if(hr != D3D_OK)
{
if(hr == D3DERR_DEVICELOST)
{
MessageBox(NULL,"创建渲染设备失败 原因是->/n设备丢失!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
else if(hr == D3DERR_INVALIDCALL)
{
MessageBox(NULL,"创建渲染设备失败 原因是->/n参数错误!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
else if(hr == D3DERR_NOTAVAILABLE)
{
MessageBox(NULL,"创建渲染设备失败 原因是->/n设备不支持!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}else if(hr == D3DERR_OUTOFVIDEOMEMORY)
{
MessageBox(NULL,"创建渲染设备失败 原因是->/n内存溢出!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
return false;
}
return true;
}
==========RenderLogic.h==========================
#ifndef __Include_RenderLogic_h__
#define __Include_RenderLogic_h__
#include "Direct3d9Device.h"
class RenderLogic
{
public:
static RenderLogic& getSingleton(){ assert(mSingletonInstance); return *mSingletonInstance;};
static RenderLogic* getSingletonPtr() {assert(mSingletonInstance); return mSingletonInstance;};
public:
RenderLogic();
~RenderLogic();
void setBackGroundColor(unsigned long color = 0xff000000){ mBackGroundColor = color;};
bool RenderOneFrame(float lastFrameTime);
bool save();
protected:
void setup();
void Set2DFont(char* str,RECT rect,D3DCOLOR color);
private:
unsigned long mBackGroundColor;
bool mDeviceLost;
LPDIRECT3DTEXTURE9 mSceneeTexture;
LPDIRECT3DSURFACE9 mBackFace;
LPDIRECT3DSURFACE9 textureLevel;
LPDIRECT3DSURFACE9 mBackBuffer;
static RenderLogic* mSingletonInstance;
LPD3DXFONT mFont;
};
#endif
===================RenderLogic.cpp===================
#include "RenderLogic.h"
#include "Direct3d9Device.h"
RenderLogic* RenderLogic::mSingletonInstance = 0;
RenderLogic::RenderLogic()
:mDeviceLost(0)
,mSceneeTexture(0)
,mBackFace(0),
textureLevel(0)
{
mSingletonInstance = this;
mBackGroundColor = 0xff000000;
setup();
}
RenderLogic::~RenderLogic()
{
if(mSceneeTexture)
{
mSceneeTexture->Release();
mSceneeTexture = 0;
}
}
bool RenderLogic::RenderOneFrame( float lastFrameTime )
{
if(mDeviceLost)
{
mDeviceLost = false;
}
const LPDIRECT3DDEVICE9 device = Direct3d9Device::getSingletonPtr()->getDevice();
device->Clear(0,NULL,D3DCLEAR_TARGET,mBackGroundColor,1.0f,0);
if(D3D_OK == device->BeginScene())
{
RECT rect;
rect.left = 0;
rect.right = 990;
rect.bottom = 60;
rect.top = 0;
Set2DFont("壹贰叁肆伍陆柒捌玖拾",rect,0xffff0000);
device->EndScene();
}
if(D3DERR_DEVICELOST == device->Present(NULL,NULL,NULL,NULL))
mDeviceLost = true;
if(!save())
return false;
return true;
}
void RenderLogic::setup()
{
HRESULT hr;
const LPDIRECT3DDEVICE9 device = Direct3d9Device::getSingletonPtr()->getDevice();
hr = device->CreateTexture(
990,
60,
1,D3DUSAGE_RENDERTARGET,
Direct3d9Device::getSingletonPtr()->getDisplayMode().Format,
D3DPOOL_DEFAULT,
&mSceneeTexture,NULL);
if(hr != D3D_OK)
{
if(hr == D3DERR_INVALIDCALL)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->参数错误!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}else if(hr == D3DERR_OUTOFVIDEOMEMORY)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->显存溢出!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}else if(hr == E_OUTOFMEMORY)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->内存溢出!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
}
assert(mSceneeTexture);
hr = D3DXCreateFont(device,60,0,700,0,false,0,0,0,0,"隶书",&mFont);
if(hr != D3D_OK)
{
if(hr == D3DERR_INVALIDCALL)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->参数错误!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}else if( hr == D3DXERR_INVALIDDATA)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->硬件不支持!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}else if( hr == E_OUTOFMEMORY)
{
MessageBox(NULL,"创建渲染目标失败:/n原因->内存溢出!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
}
if(FAILED(mSceneeTexture->GetSurfaceLevel(0,&textureLevel)))
MessageBox(NULL,"创建渲染目标失败:/n原因->未知!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
if(FAILED(device->SetRenderTarget(0,textureLevel)))
MessageBox(NULL,"创建渲染目标失败:/n原因->未知!","错误信息:",MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
bool RenderLogic::save()
{
if(FAILED(D3DXSaveTextureToFile("Scene.tga",D3DXIFF_TGA,mSceneeTexture,NULL)))
return false;
return true;
}
void RenderLogic::Set2DFont( char* str,RECT rect,D3DCOLOR color )
{
char m_strBuffer[256];
WCHAR m_STRBuffer[256];
sprintf(m_strBuffer,str);
MultiByteToWideChar(CP_ACP,0,m_strBuffer,-1,m_STRBuffer,256);
mFont->DrawTextW( 0, m_STRBuffer, -1, &rect, DT_TOP|DT_LEFT, color );
}
=================main.cpp==================
#include <Windows.h>
#include "Direct3d9Device.h"
#include "RenderLogic.h"
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground = NULL;
wcex.hCursor = LoadCursor(NULL,IDC_APPSTARTING);
wcex.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wcex.hIconSm = 0;
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WindowProc;
wcex.lpszClassName = "RenderToTexture";
wcex.lpszMenuName = NULL;
wcex.style = 0;
RegisterClassEx(&wcex);
HWND hWnd;
hWnd = CreateWindow("RenderToTexture","渲染到纹理测试!",WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,990,60,NULL,NULL,hInstance,NULL);
if(!hWnd)
return 1;
Direct3d9Device* displayHandle = new Direct3d9Device();
if(!displayHandle->initiliase(hWnd))
return false;
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
MSG msg;
RenderLogic rl;
ZeroMemory(&msg,sizeof(MSG));
while (msg.message != WM_QUIT)
{
if(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
static float lastTime = static_cast<float>(timeGetTime());
float currenttime = static_cast<float>(timeGetTime());
float lastFrameElapsedTime = currenttime - lastTime;
if(!rl.RenderOneFrame(lastFrameElapsedTime/1000))
MessageBox(NULL,"坏帧!","警告信息!",MB_OK | MB_ICONERROR | MB_TASKMODAL);
lastTime = currenttime;
}
}
delete Direct3d9Device::getSingletonPtr();
UnregisterClass("RenderToTexture",hInstance);
return 0;
}
LRESULT CALLBACK WindowProc( HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_KEYDOWN:
//RenderLogic::getSingletonPtr()->save();
break;
case WM_DESTROY:
DestroyWindow(hwnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return (int)wParam;
}
==========================================
这段知识从网络所得,因为最近在考虑玩家头顶名字广告版的问题,想了想感觉可以用这个方法实现,不过目前还没去试过,该代码到是可以实现将文字渲染到纹理,不过还有一些关于设置视图矩阵的还不是很清楚,详情可以参考http://blog.csdn.net/blade2001/archive/2007/06/11/1648271.aspx,欢迎交流讨论