(D3D)dx9实现渲染到纹理(Render To Texture, RTT)

渲染到纹理,顾名思义就是把渲染目标从帧缓存变成一个纹理。这样就可以把一个场景渲染后在进行Post Process,做出现在流行的各种特效。另外在利用GPU做通用计算的时候程序也是通过RTT和GPU交换数据的。

实现步骤:

  1. 声明变量
    LPDIRECT3DTEXTURE9 pRenderTexture = NULL; // 目标纹理
    LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL, pTempSurface;
    // pRenderSurface是pRenderTexture 对应的Surface
    // pBackBuffer用于保存原来的Render Target
  2. 创建一个纹理作为渲染目标(Render Target)
    //注意这里的第三个参数必须为
    D3DUSAGE_RENDERTARGET
    //第四个参数决定纹理的格式,不同的场景会要求不同的格式

    pd3dDevice->CreateTexture(TEX_WIDTH,TEX_HEIGHT,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&pRenderTexture,NULL);

    //获得
    pRenderTexture对应的Surface
    pRenderTexture->GetSurfaceLevel(0,&pRenderSurface);
  3. 渲染场景
    //这里保存下原来的Render target,在做完RTT后再恢复
    pd3dDevice->GetRenderTarget(0,&pBackBuffer);
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
    //设置我们的纹理为render target
    pd3dDevice->SetRenderTarget(0, pRenderSurface);
    pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR(0.0f,0.00f,0.00f,1.00f), 1.0f, 0);


    //重新将render target设置为帧缓存
    pd3dDevice->SetRenderTarget(0, pBackBuffer);

    pd3dDevice->EndScene();
    pBackBuffer->Release();
    }
  4. 善后
    SAFE_RELEASE(pRenderSurface);
    SAFE_RELEASE(pRenderTexture);

这里需要注意的几点:

  • 渲染的时候要选择正确的纹理格式。如果你要在纹理里面保存高精度浮点数的话。通常所用的A8R8G8B8格式每一个颜色分量只有8位,只能表示0-255。详情可以参考DirectX SDK Help中关于D3DFORMAT的说明。
  • 如果你的纹理长宽比和帧缓存的不同的话,那么你需要在切换RenderTarget以后重新设置投影矩阵。否则渲染出来的图像会被拉伸。
  • 纹理的大小不能太大。经过试验发现是在窗口模式下面窗口和纹理的大小不能超过屏幕减去任务栏的大小。如果超过的话似乎对纹理的任何操作都不会有效果。
  • 如果想要验证自己渲染出来的纹理是否正确,可以用D3DXSaveTextureToFile把纹理保存为图像。

 

==========代码部分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,欢迎交流讨论

 

 

 

你可能感兴趣的:(null,callback,include,float,Direct3D,winapi)