渲染到目标,通俗地说就是把特定场景的物体放在目标上显示。这个目标可以是纹理,窗口等。本文介绍的是把场景渲染到纹理,并以图片的形式保存起来。
一 其原理如下:
在初始化时创建一纹理Texture,获取指向该纹理的指针,接着创建深度表面,并获取指向其的指针DepthSurface。在渲染时先获取系统的默认的渲染目标和深度模板表面,再设置Texture的表面为渲染目标,并通过DepthSurface设置深度模板表面,接着渲染场景中的物体,并保存该纹理到制定路径,最后恢复系统的默认的渲染目标和深度模板表面。
二 具体步骤:
设计一渲染目标类RenderTarget,负责纹理,深度表面的创建,以及设置渲染目标,深度表面等。现介绍其实现:
初始化函数:该函数接收外界传入的width和height作为纹理的宽和高,
其功能有:1 是根据width和height创建纹理,调用IDirect3DDevice9接口的
CreateTexture(width,height,1,D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,&mpRTT,NULL);
mpRTT为指向该纹理的指针。
2 根据width和heigh创建深度表面,调用IDirect3DDevice9接口的
CreateDepthStencilSurface(width,height,D3DFMT_D24S8,
D3DMULTISAMPLE_NONE,0,TRUE,&mpDepthSurface,NULL);
mpDepthSurface为指向该深度表面的指针
渲染函数:首先要获取一个系统设备指针device,定义并初始化IDirect3DSurface9类型指针 pOldZBuffer, pRenderSurface ,pBackBuffer。
接着获取系统默认的渲染目标device->GetRenderTarget(0,&pBackBuffer);
获取系统d3d默认深度表面device->GetDepthStencilSurface(&pOldZBuffer);
设置mpRTT纹理的表面作为渲染目标
mpRTT->GetSurfaceLevel(0,&pRenderSurface);
device->SetRenderTarget(0,pRenderSurface);
再设置深度表面 device->SetDepthStencilSurface(mpDepthSurface);
执行场景物体的渲染操作后,再恢复系统默认设置
device->SetRenderTarget(0,pBackBuffer);
device->SetDepthStencilSurface(pOldZBuffer);
最后释放引用 SAFE_RELEASE(pBackBuffer);SAFE_RELEASE(pRenderSurface);
三 监听器模式实现:
现讨论一下场景物体的渲染部分:
因某些场景的不同而需要进行特殊的渲染操作,这样就要求根据不同场景调用不同的渲染流程。这样需用到一设计模式:监听器模式。
其原理如下:先设置调用哪一种监听器,再根据不同的监听器执行其相应的渲染操作。
实现如下:
1 先定义一虚基类:Listener,定义两个纯虚函数:
virtual void Execute()=0; virtual void AfterExecute()=0;
再定义两个Listener的子类:ReflectListener,CurrentSceneListener 并改写其纯虚函数,可在Execute()里进行场景物体模型的渲染操作,AfterExecute()执行相关的重置操作。
2 在场景类Scene的私有成员列表中定义:
RenderTarget *mpReflectTarget;
ReflectListener *mpSceneRenderer;
RenderTarget *m_pCurrentSceneTarget;
CurrentSceneListener *m_pCurrentListener;
即一个监听器对应一个渲染目标。
3 在RenderTarget类私有成员列表中定义:Listener *mpRenderListener;
并添加对应的设置监听器的接口函数 SetRenderEvent(Listener *pListener);
再添加一成员函数__Rend(),其在RenderTarget类的Rend()中调用,__Rend()首先要进行清理操作:执行IDirect3DDevice9接口的
Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(255,255,255),1.0f, 0);
再执行:mpRenderListener->Execute();mpRenderListener->AfterExecute();
这样可根据不同的监听器执行不同的渲染流程。
4 在场景类的初始化函数执行:
m_pCurrentListener=new CurrentSceneListener();
m_pCurrentSceneTarget=new RenderTarget();
m_pCurrentSceneTarget->Initial("currentsceneTarget",1024,1024);
m_pCurrentSceneTarget->SetRenderEvent(m_pCurrentListener);
同理可使用ReflectListener监听器。
5 因本文描述的是渲染目标到纹理,并以图片的格式保存,那可在Scene的析构函数里执行场景物体的渲染操作: m_pCurrentSceneTarget->Render();
这样保存的是运行界面关闭时的那个场景画面。
四 概括一下流程:
在Scene的初始化函数执行RenderTarget的Initial(),接着设置监听器SetRenderEvent(),再在Scene的析构函数里执行RenderTarget的Render(),而Render()调用RenderTarget的__Render(), __Render()调用相应监听器的 Execute()和 AfterExecute(),在Execute()进行场景物体的渲染操作。