Ogre参考手册(一)2 核心对象
说明
翻译自Ogre 1.81 manual,在不影响理解的情况下做了删减,以减小阅读的时间和翻译的工作量
这么做只是去掉了文字上修饰部分,并没有减少任何原文档中的知识点,可以作为对等的参考手册
另外对一些不易理解的部分做了修改,或通过“附”做了标注
如果你发现了不易理解的部分,可以跟帖回复,我会原文做修改或回复
Ogre参考手册前两章为为基本介绍,比较精简
最核心的内容是第三章,特别是3.1节
依次则是第七章和第五章,都值得花时间从头到尾读一遍
注:原文编写时间2006年第三季度,已经接近十年
所以里面所说的老显卡都已是古董,先进显卡也已是老显卡
1 介绍
略…
2 核心对象
下图是Ogre的主要类结构
最上面的是Root对象,这是使用Ogre的入口。通过该类可以创建所有顶层对象,如SceneManager、RenderSystem、RenderWindow以及加载插件等。如果你不知道从哪里开始,Root可以帮你做所有的事,通常Root通过提供另一个对象做实际的工作,Root更多是个组织者和服务对象。
Ogre主要的类可分为3部分:
场景管理
这里涉及场景的内容,如何组织,如何通过相机查看等等。这里的类提供了真实世界的直观展示接口。即,你不需要告诉Ogre:“设置这些渲染状态,然后渲染三个多边形”;你只需要说:“我需要在这里、这里和这里放个东西,使用它们的材质,然后从这个视角渲染”,其它都可以让Ogre自己处理
资源管理
所有的渲染都需要资源,无论是几何结构、纹理、字体等等。谨慎的管理这些资源的加载、复用以及卸载都很重要,这是此部分的处理内容
渲染
最终,这些都需要显示到屏幕上,这里涉及底层的渲染管线。渲染系统API特定的对象如缓冲区、渲染状态和类似的东西都推送到渲染管线。场景管理子系统通过使用此部分将高层场景渲染到屏幕
注意图中的边缘散布一些插件(plugins)。Ogre采用可扩展设计,这通常通过插件实现。Ogre的很多类可以被继承和扩展,无论是通过自定义场景管理器改变场景组织,增加新的渲染系统实现(即Direct3D或OpenGL),或者从其它来源加载资源(例如从网络或者数据库)等等。这里只是简单说了些插件能做什么,你将看到几乎系统的所有方面都可以使用插件。通过这种方式,Ogre不再是一个严格预定义问题的解决方案,你可以通过扩展解决你需要处理的所有问题
2.1 Root
Root对象是Ogre系统的入口点,必须第一个被创建,最后一个销毁。在示例程序中,我选择将Root作为MyApplication的一个成员,以保证创建的时候就创建Root,删除的时候删除Root。
Root对象允许你对系统进行配置,比如,通过showConfigDialg()方法。该方法可以检测所有渲染系统选项,并显示一个对话框用于用户定制分辨率、颜色深度、全屏选项等等。同时还会设置用户选择的选项,这样你可以后续直接初始化系统。
Root对象提供获取其它对象指针的方法,比如SceneManager\RenderSystem以及其它资源管理器等。
最终,如果你想以连续渲染模式运行Ogre,即你想一直以最快的速度刷新所有渲染目标(游戏或演示的标准做法,不适用于窗口化工具),你可以调用startRendering(),调用该方法将进入连续的渲染循环,直到所有渲染窗口关闭,或者任一FrameListener表示想要终止循环。
2.2 渲染系统RenderSystem
RenderSystem实际上是基础3D API抽象类。用于将渲染操作发送到3D API和设置各种渲染状态。设计为抽象类是因为实现是和渲染API相关的,每个渲染API对应特定的子类(例D3DRenderSystem用于D3D)。通过Root::initialise初始化后,可以使用Root::getRenderSystem()获取当前渲染API对应的RenderSyetem。
通常,应用程序不需要直接操作RenderSystem对象,所有渲染对象的需要和通常的设置都可以通过SceneManager\Material以及其它用于场景的类完成。仅当你需要创建多渲染窗口(完全独立的窗口,不是指可以通过RenderWindow实现的多视口类似的分屏效果)或者需要其它高级特性时才需要使用RenderSystem对象。
基于这个原因,本教程不会讨论RenderSystem对象,你可以认为SceneManager会在恰当的时候处理对RenderSystem的调用
2.3 场景管理器SceneManager
除了Root,这大概是最重要的对象,也是程序中最常使用的对象。场景管理器负责管理用于引擎渲染的场景内容。负责选择最合适的技术组织场景,创建和管理所有相机、可移动物体(实体entity)、灯光和材质(物体的表面属性)以及管理不规则伸展的静态几何体:世界地形(world geometry,通常用于表示场景中不可移动的部分)。
你需要使用场景管理器创建相机,以创建或移除灯光。你不需要维护所有物体的列表,场景管理器提供了一个命名的集合(map)用于管理所有场景对象,你可能会用到它。可参考getCamera,getLight,getEntity等方法
你与场景管理器之间的大部分交互工作会在场景创建阶段。你会调用(可能通过包含场景数据的输入文件驱动)大量的方法用于加载场景,如果你使用了FrameListener对象,你可以在渲染循环中动态修改场景内容
因为不同的场景需要不同的算法判断哪些对象需要发送到渲染系统,以获取较好的渲染性能;场景管理器设计为可被继承以用于不同的场景类型。默认的场景管理器虽可用于渲染场景,但仅做了很少甚至没有进行场景组织,你不能期望它在渲染大场景时有很高的性能。这么设计的目的是通过使用针对不同场景类型设计的特定子类进行场景组织以实现最佳的性能。比如可以使用基于空间二分树(Binary Space Partition,BSP)的BspSceneManager优化大型室内级场景渲染。
使用Ogre的应用程序不需要知道使用的是哪个子类。应用程序通过调用Root::createSceneManager并传递一个场景类型参数(ST_GENERIC/ST_INTERIOR),Ogre可以自动选择适合场景类型的子类,如果没有专门子类将采用默认的SceneManager。这允许开发人员在不修改任何代码的情况下通过添加新的专门优化的版本替换之前未优化的场景实现。
2.4 ResourceGroupManager
ResourceGroupManger是加载可复用资源比如纹理或者网格(mesh)的中心。可以为资源分组,以根据需要加载和卸载。这里包含一些ResourceManager用于管理各种类型资源,比如TextureManager\MeshManager。在这里,资源被看做是一组可以从某地方加载供Ogre使用的数据。
ResourceManager保证资源一次加载后可在整个Ogre引擎中共享,以及管理资源需要的内存。同时还可以在多个位置查找需要的资源,包括多重路径、压缩文档(zip文件)。
通常你不要直接与资源管理器交互。资源管理器可以在需要的时候由Ogre的其它部分自动调用,比如你访问材质的纹理,TextureManager将会自动调用。如果需要,你可以直接调用恰当的资源管理器重新加载资源
有一件你大概需要做的事是告诉资源管理器到哪里查找资源,可通过Root::getSingletion(). addResourceLocation(),这实际上将该信息传递到ResourceGroupManager。
因为每个资源管理器只有一个实例,你可以通过下面的方式引用资源管理器:
TextureManager::getSingleton().someMethod()
MeshManager::getSingleton().someMethod()
2.5 网格Mesh
Mesh对象代表一个分离的模型,一组完整的几何体,在世界尺度上通常很小,用于表示示可移动物体,不用于不规则伸展的几何体比如背景。
Mesh也是一种资源,通过MeshManager管理。一般通过Ogre自定义的.mesh格式文件加载。Mesh文件可以从建模工具导出,并可通过Mesh工具处理
你可以可用使用MeshManager::createManaual方法手动创建Mesh。
Mesh是世界中各个独立可移动物体的基础,这些可移动物体叫做Entity(实体)
可以对Mesh使用动画,参考8.1骨骼动画
2.6 实体Entity
实体是场景中一个可移动物体的实例。可以是一辆汽车、人、手里的剑等等。唯一的假定是其不需要在世界中占据固定的位置。
实体基于Mesh创建,多个实体可以基于同一Mesh,因为场景中经常需要创建同一类型物体的多个拷贝
可以调用SceneManager::createEntity方法创建实体,并指定使用的Mesh名称(a.mesh)。SceneManager通过调用MeshManager确保Mesh被加载。只有一份Mesh的拷贝会被加载。
实体仅在关联到场景节点(SceneNode)后才会被视为场景的一部分。通过关联到节点,可以在实体间建立复杂的位置和朝向关系。可通过修改节点的位置间接设置实体位置。
加载Mesh时,自动伴随着一些材质。Mesh可以关联多个材质(不同部分采用不同的材质)。创建实体时自动采用相应的材质,同时你可以改变实体的材质,从而允许相同Mesh创建的实体可使用不同的材质。
这实际是因为,Mesh由多个SubMesh组成,每个SubMesh作为Mesh一部分可使用不同的材质。如果Mesh只使用一个纹理,应该只使用一个SubMesh
当Entity基于Mesh创建时,同样由SubEntity组成,每个SubEntity对应一个SubMesh。可以通过Entity::getSubEntity获取SubEntity,可通过.setMaterialName改变材质。通过这种方式可以为每个实体创建不同的外观。
2.7 材质Material
材质控制场景中物体的渲染方式,指定了物体的表面属性,如颜色反射、高亮,使用多少纹理层,应用了多少图像以及如何混合,应用了什么特效如环境映射,什么裁剪方式,纹理如何过滤等等。基本上除了形状之外,物体的外观都通过材质控制
材质可通过SceneManager::createMaterial手动创建,也可通过脚本文件在运行时加载,参考3.1材质脚本
SceneManager管理了场景中可用材质列表。列表可通过SceneManager::createMaterial添加,也可在加载Mesh时添加。无论材质怎么添加到SceneManager,初始都有以下默认属性:
- ambient reflectance = ColourValue::White (full)
- diffuse reflectance = ColourValue::White (full)
- specular reflectance = ColourValue::Black (none)
- emissive = ColourValue::Black (none)
- shininess = 0 (not shiny)
- No texture layers (& hence no textures)
- SourceBlendFactor = SBF_ONE, DestBlendFactor = SBF_ZERO (opaque)
- Depth buffer checking on
- Depth buffer writing on
- Depth buffer comparison function = CMPF_LESS_EQUAL
- Culling mode = CULL_CLOCKWISE
- Ambient lighting in scene = ColourValue(0.5, 0.5, 0.5) (mid-grey)
- Dynamic lighting enabled
- Gourad shading mode
- Solid polygon mode
- Bilinear texture filtering
你可调用SceneManager::getDefaultMaterialSettings()修改返回的材质改变这些设置
实体通过Mesh创建时自动关联材质,因为通常Mesh都设置了所需要的材质。你可以改变实体的材质,参考2.7实体
2.8 表层 Overlay
Overlay允许在通常的场景内容之上显示2D或3D元素,用于实现HUD(抬头数字显示,heads-up display)、菜单系统、状态栏等等。Ogre提供的帧速统计面板就是一个Overlay的例子。Overlay可以包含2D或者3D元素,2D可用于HUD,3D可用于驾驶舱等需要在其它场景之前显示的内容。
你可通过SceneManager::createOverlay或者在.overlay脚本中定义创建Overlay。实际上,后一种更适合,因为很简单且不需要重新编译代码。你可以定义任意多个Overlay,其初始默认为隐藏,通过调用.show()显示。可以同时显示多个Overlay,zorder可通过Overlay::setZOrder设置。
创建2D元素
OverlayElement抽象了添加到Overlay中的2D元素的细节。所有能够添加到Overlay的元素都继承此类。用户可以(推荐)自定义子类以实现自定义的控制。OverlayElement包含一些的常用属性,包括size\position\materail等。子类可以扩展支持更复杂的属性和行为。
OverlayElement的一个重要的内置子类是OverlayContainer。OverlayContainer与OverlayElement类似,区别是可以包含其它OverlayElement,将它们分组,并提供便于排列的局部坐标源点。
第三个重要的类是OverlayManager。无论什么时候,应用程序需要创建2D元素以添加到Overlay(或Container),都需要调用OverlayManager::createOverlayElement。被创建元素的类型通过字符串标识,这是为了允许通过插件注册新的OverlayElement类型。比如创建一个Panel类型元素,你可以调用OverlayManager::getSingleton().createOverlayElement(“Panel”, “myNewPanel”);
将2D元素添加到Overlay
只有OverlayContainer(容器)可以直接添加到Overlay。这是因为每个容器都为内部元素建立了zorder,这样当你嵌套多个容器时,内部容器的zorder将比之外的更大,从而保证正确显示。可以简单的调用Overlay::add2D将容器添加到Overlay。
如果你希望将子元素添加到容器,可调用OverlayContainer::addChild。子元素可以是OvelayElement或者OverlayContainer。子元素的位置默认相对于其父容器的左上角。
2D坐标
Ogre可以使用两种2D坐标系设置元素大小和位置
像素模式(pixel)
像素模式很简单,左上角为(0,0),右下角依据屏幕的分辨率。
这种在需要为元素设置精确的大小时有用,如果你不介意调高分辨率会使元素在屏幕上变得更小的话(你可能希望这样)。在这种方式下,只有通过align选项才可以使元素在各种分辨率下保持居中或者居右,你可以通过align选项设置水平、垂直的坐标源点为右、下或中,以在不需要知道分辨率的情况下将元素放置到相应的位置;在相对模式下,你只要使用正确的相对坐标就可以了。
相对模式(relative)
在需要元素在各种分辨率下都在屏幕上保持同样的大小时有用。相对模式下左上角为(0,0),右下为(1,1)。如果你将元素放置到(0.5,0.5),则无论什么分辨率下,元素的左上角都正好在屏幕中心。同样的原则也适用于大小。注,因为屏幕纵横比典型为(1.333:1),大小为(0.25,0.25)的元素并不是正方形。
Overlay变换
Overlay一个很好的特性是支持整体旋转、滚动和缩放。参考Overlay::scroll/rotate/scale
Overlay脚本
Overlay可以通过脚本定义,参考3.4
GUI
Overlay实际上设计为非交互屏幕元素,尽管你也可以使用它做一个粗糙的GUI
如果需要使用完全的GUI解决方案,推荐CEGui (http://www.cegui.org.uk), MyGUI (http://mygui.info/) 或者 libRocket (http://librocket.com/)