OGRE渲染对象
Ogre中的render target 只是共享AGP内存或显存的某个区域的抽象,这个区域中保存着全部或部分场景2D渲染结果。最普通的render target是主渲染窗口,这是应用程序的主窗口。使用这个render target不需要做太多另外的努力,ogre可以帮我们创建它。还可以把场景中的全部或部分(甚至是场景中不可见的部分)渲染到一个纹理,这个纹理可以被场景中的其他多边形使用。目标硬件缓冲在ogre中抽象为render target,它的物理显示可以为主渲染窗口,也可以是副窗口,也可以是非可视的:纹理。
渲染对象也是事件源,假如程序注册了这事件,ogre会在pre- 和 postrender时通知程序,这给程序改变设置,做出响应的机会。甚至在视口(viewport)级别上pre-,post- 渲染时也有上述通知机制。ogre提供了计算渲染状态信息的功能,如多长时间渲染一帧,渲染对象上有多少三角形等。
渲染窗口
窗口是由渲染系统的具体实现创建与维护的(D3D9下是个标准的Win32 Window)。Ogre允许对渲染窗口进行很少的配置,限于尺寸,标题栏文字等。假如希望开发的程序有菜单,工具栏等,把ogre的渲染输出到
窗口的客户区,这是可能的。ogre可以提供你系统相关的窗口句柄给渲染窗口,也允许你提供句柄给父窗口。第一个创建的ogre渲染窗口称为主窗口。另外创建的是副窗口。窗口不像主窗口那么重要。假如在程序中有三个窗口,那么为了正确的进行资源清理,必须在销毁主窗口前把另外两个副窗口销毁。
视口
渲染窗口包含一个或多个视口。视口是一个长方形区域,场景管理器把从一个相机中看到的场景可见内容
的透视图渲染到这个区域中。视口创建时会引用一个相机,但这不是视口的静态属性,可以随时改变用于
渲染视口的相机。每个视口拥有一个z序数,z序高的位于Z序低之上。z序0,总是被一个能覆盖整个渲染对象的视口所拥有。缺省,ogre会清理视口的颜色与深度缓冲。然而,可以关闭这些缓冲清理。视口是渲染对象(也就是特定的渲染系统,如OpenGL)与相机(也就是特定场景管理器与它的内容)之间的唯一交互点。视口不必占用整个渲染对象的表面。3D渲染相机不是真正的相机,所有的几何LoD计算是以相机的位置算的,因此不能简单的改变相机的焦点属性来达到“更近”的渲染效果。
渲染到纹理
使用步骤是:创建一个纹理渲染对象,配置它的渲染属性,加纹理到渲染对象列表,设置纹理到被使用的材质。纹理对象先于其他渲染对象类型更新,这就保证了使用了渲染纹理的对象正确地被渲染。渲染纹理可以像其他普通纹理一样被处理。对于那些不需要每帧都更新的渲染纹理,可以关闭自动逐帧更新而采用手动更新。从底层看,纹理对象就是一块硬件缓冲。为了性能考虑,认为它们是只写与静态的。渲染到纹理会渲染场景中的几何,需要一些时间执行,会降低应用程序帧率。但是很多有用的技术现在离不开渲染到纹理的使用。实时阴影,实时反射等。ogre支持渲染到多个纹理,唯一的限制是它们就具有相同的寸。
渲染对象类
RenderTarget是RenderWindow,MultiRenderTarget,与RenderTexture的基类。
RenderWindow通过子类化来实现:D3D9RenderWindow,GLXWindow等。在windows操作系统中,由于可以使用Direct3D 9或是OpenGL,于是可以分别使用D3D9RenderWindow,Win32Window。
RenderSystem::createRenderWindow()来创建窗口。
virtual RenderWindow* Ogre::RenderSystem::createRenderWindow ( const String & name,
unsigned int width,
unsigned int height,
bool fullScreen,
const NameValuePairList * miscParams = 0
)
通过最后一个参数,可以设置窗口的一些属性。
将渲染窗口嵌入外部窗口的代码
NameValuePairList params; // is just a typedef std::map<std::string, std::string>
// set external window handle -- assume that you have
// already created a window to embed the Ogre render window, and its handle is
// stored in an integer variable called "mParent"
params["externalWindowHandle"] = StringConverter::toString(mParent);
// window can be resized later to fit within parent client area if needed
RenderWindow* window = createRenderWindow("MyWindow", 800, 600, false, ¶ms);
渲染到纹理Demo
demo在原点创建了一个倾斜的平面,设置相机,把场景(场景由一个魔鬼脑袋与几个环面纽结组成)
相对于平面的倒影渲染到纹理中。渲染纹理与平面已经应用的静态纹理混合,这样就实现了反射效果。
创建渲染纹理:
TexturePtr texture = TextureManager::getSingleton().createManual( "RttTex",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
创建相机与视口用于渲染到纹理:
mReflectCam = mSceneMgr->createCamera("ReflectCam");
mReflectCam->setNearClipDistance(mCamera->getNearClipDistance());
mReflectCam->setFarClipDistance(mCamera->getFarClipDistance());
mReflectCam->setAspectRatio(
(Real)mWindow->getViewport(0)->getActualWidth() /
(Real)mWindow->getViewport(0)->getActualHeight());
Viewport *v = rttTex->addViewport( mReflectCam );
v->setClearEveryFrame( true );
v->setBackgroundColour( ColourValue::Black );
创建使用渲染纹理的材质:
MaterialPtr mat = MaterialManager::getSingleton().create("RttMat",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
TextureUnitState* t = mat->getTechnique(0)->getPass(0)->createTextureUnitState("RustedMetal.jpg");
t = mat->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");
// Blend with base texture
t->setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT, ColourValue::White,
ColourValue::White, 0.25);
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
t->setProjectiveTexturing(true, mReflectCam);
rttTex->addListener(this);
材质名为RttMat,包含一个技术,后者有一个通道。通道有两个纹理单元,一个为静态纹理(RustedMetal.jpg)
,另一个纹理单元为渲染纹理,两个纹理按比例混合。设置了合适的纹理寻址模式,开启了透视纹理支持。
并为渲染纹理(它是渲染对象)注册了侦听器。
相机倒置使用材质:
// set up linked reflection
mReflectCam->enableReflection(mPlane);
// Also clip
mReflectCam->enableCustomNearClipPlane(mPlane);
}
// Give the plane a texture
mPlaneEnt->setMaterialName("RttMat");
相机这样设置后,渲染出的将是场景的倒影,这是以指定平面为参照的。定制最近裁剪平面的作用是:
那些低于反射面的对象将不会再被渲染。渲染纹理时,并不想把平面也渲染进去,可以在上边已经注册
侦听器做点手脚:
void preRenderTargetUpdate(const RenderTargetEvent& evt)
{
// Hide plane
mPlaneEnt->setVisible(false);
}
void postRenderTargetUpdate(const RenderTargetEvent& evt)
{
// Show plane
mPlaneEnt->setVisible(true);
}
最后要提的是,在每一帧,都要使两个相机的位置,朝向保持一致:
frameStarted:
mReflectCam->setOrientation(mCamera->getOrientation());
mReflectCam->setPosition(mCamera->getPosition());