??xml version="1.0" encoding="utf-8" standalone="yes"?> PagedGeometry?/span>OGRE引擎的一个插Ӟ它对Q无IP大区域的量|格的渲染提供优化策略。它非常适合于稠密的林和室外场景,那里有v量的树,草,岩石Q灌木丛{场景对象?/span> 2, PagedGeometry理 PagedGeometry class
该类负责加蝲那些需要立卻I或很快)可见的场景几何,而不加蝲其他的场景以节约内存I间?/span>PagedGeometry引擎可以通过诸如静态几何,imposters{方法去昄实体对象Q?/span>EntitiesQ。这些方法是与实体和场景相机的距,以及你的配置相关的?/span>
寚w面的加蝲是通过用户定义?/span>PageLoader来完成的。这P用户可以~程实现加蝲面Q无论它是来自硬盘上的文ӞE序产生的或是其他地斏V?/span> GeometryPageManager ?/span>PagedGeometrycM使用Q用于管理分页面,在需要的时候做cacheing, deleting{工作。它通过分析摄像d计算面cathe的速度Qƈdelete那些已经l过了设定时间的不可见页面?/span> 调用PagedGeometry::addDetailLevel(), 创徏 GeometryPageManager ?/span> addDetailLevel() returns a pointer to this page manager, allowing you access to some useful functions, documented below. cL员函C有些注释?/span>DO NOT USE的,不能被用户用,它们是在PagedGeometry中被使用的?/span> addDetailLevel() Adds a detail level to the PagedGeometry object. PageType 对该detail levelQ用h使用的页面类型。它不是一个函数参敎ͼ而是一个模板参数?/span> maxRange q个detail level使用的最大距(摄像机的视距Q?/span> transitionLength 期望的衰减{变长?/span> - Q可选) CZQ?/font> pagedTrees->addDetailLevel<BatchPage>(100); //Use batched geometry from 0-100 pagedTrees->addDetailLevel<ImpostorPage>(500); //Use impostors from 100-500 名叫pagedTrees?/span>PagedGeometry 的对象会?/span>0Q?/span>100单位摄像ȝ范围内?/span>batchedQ分批几何,静态几何)Q?/span>100Q?/span>500单位距离范围内?/span>imposters 如果已有的页面类型不合适,用户可以很轻杄d自定义的GeometryPage子类 transitionLength 参数在默认情况下是没有的Q但是用户可以自己添加,它的作用是ɾl节层次转变更^滑。但是注意,使用参数可能会是渲染的效率下?/span>10Q-30Q?/span>
3,面cd Class GeometryPage 如上所_该类是一个虚基类Q用户可以扩展承该cd实现不同的替代被渲染实体的方式,?/span>batchedQ?/span>imposters{。如果你需要其他的面cdQ你可以自己实现一些?/span> 以下是用户必d子类中实现的虚函敎ͼ virtual void init(SceneManager *mgr, Camera *cam) = 0; virtual void setRegion(Real left, Real top, Real right, Real bottom) = 0; virtual void addEntity(Entity *ent, const Vector3 &position, const Quaternion &rotation, const Vector3 &scale, const Ogre::ColourValue &color) = 0; virtual void build() {} virtual void removeEntities() = 0; virtual void setVisible(bool visible) = 0; virtual void setFade(bool enabled, Real visibleDist, Real invisibleDist) = 0; virtual void update() {} 以下是页面管理器Q?/span>page managerQ如何去使用上面的函敎ͼ 1Q当PagedGeometry首先create一?/span>GeometryPageQ马上调用它?/span>initQ)Q该函数好像构造函C栗?/span> 2Q准备一个几何页面给待渲染实体,讄面区域?/span> 3Q添加实体对象到该页面,q初始化位置Q方向等?/span> 4Q添加实体到场景中的最后一步。在d完所有实体对象后自动调用?/span> 5Q从面完全删除实体对象?/span> 6Q整个面变ؓ可见?/span> 7Q设|页面的消减属性?/span> 8Q在帧@环中保证面几何的更新?/span> class BatchPage The BatchPage class把实体当作静态几何体来渲染?/span>
静态几何体Q?/span>StaticGeometryQ:在场景中有许多实体是从它们加入场景开始就不会Ud的,如房屋,树等Q?/span>OgreU情冉|供了StaticGeometryc?/span>,它允怽Ҏ?/strong>很多物体.q个通常要比手动?/span>SceneNodesd要快多了?/span>
class ImposterPage the ImpostorPage class.把实体当?/span>impostorsQ一U布告版囑փQ看h像真实的实体Q来渲染 所?/span>pagecd中,q个是最快的Q它使用ImpostorsM替要渲染?/span>entitiesQ这P昑֍只要L染一pd?/span>2d imageQ而不?/span>3d mesh
class GrassPage A custom page type designed specifically for use with GrassLoader. GrassPage面cd是被设计来配?/span>GrassLoader使用?/span> q种cd是没有做q优化的Q它只是Ҏl的entityq行克隆Q然后绑定到一个新的场景节点之上。这意味着性能很差?/span>
4Q?/span>BatchedGeometryQ一U静态几何的版本 class BatchedGeometry 它是Ogre::StaticGeometry的一个轻量版本?/span> staticGeometry?/span>ogre提供l用LҎ染的c,它可以一ơ性渲染那些在场景中保?#8220;静态的”实体Q?/span>entitiesQ,如,房屋Q树{?/span> 它给用户提供多一些的?/span>batch材质{的控制?/span> class SubBatch: public Ogre::Renderable subBatchl承?/span>RenderableQ是BatchedGeometry的内部类Q它的构造函C传入BatchedGeometry指针?/span>submesh的指针,该类包含?/span>BatchedGeometry中?/span>
5Q?/span>Loading Entities class PageLoader 虚基cR用户可以扩展它L供负责加载页面(PageQ的回调函数?/span> PagedGeometry预装了几U不同的LoaderQ承于PageLoaderQ跟很多实体理器不同的是,PagedGeometry不允许用户一ơ性向objectd所有的entitiesQ由于它是用于大规模的游戏场景,所以它会对世界几何q行分页Q然后调度,只加载需要绘制的面?/span> 只要引擎需要确定世界几何的那一块区域需要被加蝲Q就要调?/span>PageLoader的成?/span>loadPage()。在函数中的PageInfol构体,提供了页面的包围体信息。在函数中,用户通过 addEntityQ)来添加实体到该页面中Q还可以定义实体的尺度,位置Q旋转等属性?/span> 当用户创Z自己?/span>loader对象后,必须其attatch?/span>PagedGeometry对象上去。如下: pagedGeometry->setPageLoader(yourPageLoader); PageInfo: l构体。提供给PageLoader的有用的面信息。基本的信息是定义被加蝲的区域,q有一些该区域的其他信息?/span> l构体内包含了一?/span>TBoundQ?/span>typedef Ogre::TRect<Ogre::Real> TBoundsQ,所有在该页面内的实体都必须攄在这个矩形包围体之中?/span> 具体?/span>loadersQ?/span> Q?/span>1Q?/span>GrassLoader l承?/span>PageLoaderQ用于和PagedGeometry一起生真实的草地场景。所谓真实的草地模拟Q?/span>GrassLoader成员函数addLayerQ)来添加草Q?/span>updateAnimation()来驱动动甅R?/span> 当用户创ZGrassloader对象后,必须其attatch?/span>PagedGeometry对象上去。如下: pagedGeometry->setPageLoader(GrassLoader); 草地loader在用几何页面类型的时候,被推荐ؓ使用GrassPageQ这L渲染效率较高Q而采用其他类型则效率很低?/span> 同时提供了一个数据结构来完全控制Grass的属?/span> class GrassLayerQ它是通过addLayerQ)来添加的Q该cL供了一pd?#8220;set”ҎQ用于用户配|草地的材质Q密度,大小{属性信息?/span> Q?/span>2Q?/span>TreeLoader2Dl承?/span>PageLoaderQ用于和PagedGeometry一赯易的实现在地形上攄树木的功能?/span> 使用Ҏ和前qC_使用ӞaddTreesQ)Ҏ向场景中d树木。需要注意的是,loader加蝲树木时ƈ不知道该地Ş的高度,而是假设高度?/span>0Q这需要设定获得当前(即给?/span>xQ?/span>z值时Q的地Ş高度?/span>Loader提供了这些方法?/span> Q?/span>3Q?/span>TreeLoader3D?/span>2D的情况差不多Q只是效率大概低40Q左叟?/span>TreeLoader3D树在内存中打包的效率很高,大约10Bytes一|Q相当于100万棵树只?/span> 引擎?/span>2DQ?/span>3Dloader提供了一些公用的工具c,?/span>class TreeRefQ以内联函数的性质?/span>loader提供了位|,旋{Q尺寸,方向{的“get”数学q算。?/span>TreeIterator2DQ?span>TreeIterator3D则ؓloader提供了树指针的操作?/span> WorldTexture=terrain_texture.jpg //地ŞU理 下列参数用于提供自己的着色程序时使用Q这会提供自己定义的materialQ那么先前定义的 MorphLODFactorParamName=morphFactor 上述配置文g定义了基于高度图的地形?/p>
q些参数定义可概括ؓ两类QOgre使用W一cM高度图生地?br>mesh与材质?/p>
W二cL定制材质与GPU点E序Q这可以代替ogre自动产生的着色程序?br>另外的说明:
DetailTexture=terrain_detail.jpg //地Şl节U理(相机距离地面很近旉用细节纹?
DetailTile=3 //l节U理在一个地形小块中的^铺数
PageSource=Heightmap //高度图数据源
Heightmap.image=terrain.png //高度囑U?灰度图文件名),W合2^n+1
PageSize=513 //高度囑֤?br>TileSize=65 //地Ş块大小
MaxPixelError=3 //军_使用层次l节时充许误?br>PageWorldX=1500 //地Ş在世界中的范围x方向
PageWorldZ=1500 //z方向
MaxHeight=100 //世界中地形最大映高?br>MaxMipMapLevel=5 //层次l节上限
#VertexNormals=yes //在缓冲中计算点法线Q计机光照或GPUE序用到时打开
#VertexColors=yes //在缓冲中讄点颜色Q假如有GPUE序需要时打开
#UseTriStrips=yes //对于现在的硬Ӟx
VertexProgramMorph=yes //使用点E序q行LOD融合处理
LODMorphStart=0.2 //LOD融合开始点Q高Q低LOD之间距离之比
WorldTexture ?DetailTexture的设|不再用到?/p>
//假设VertexProgramMorph被设为yes,定制的material中包括一个高U顶点程序。它指定了一个顶?br>//E序的参数名Q这个参数用于融合LOD,参数g0Q?Q?表示不调_1表示完全调整C一ULOD
MorphLODFactorParamIndex //用于materail中包含低U顶点程序的情况Q意义同?br>CustomMaterialName //指定的materail名字
TerrainScenceManager会把高度囑ֈ为多个page,每个page由几个tilel成.它们都定义了在生的mesh中一l构成正方Ş的顶炚w?br>WorldTexture定义的纹理不必与目标地Ş一样大?br>PageWorldXQPageWorldZ可以~放世界中的地Ş?br>MaxHeight 在Y方向~放地Ş?br>DetailTexture 只用一个纹理,如用多层纹理,应该使用自定义materail?br>
从程序加载地?/span>
setWorldGeometry()有重载Ş式,一U用于加载配|文Ӟ另一U我们可在程序中使用Q以
辑ֈ手工加蝲的功能。这里,SceneData?typedef 为std:map,它存储了如我们在terrain.cfg
中看到那些值对。假设我们已l从某个二进制文件读入我们想要的内容到SceneData中。我们要?br>的就是把d的内容{换成setWorldGeometry()需要的cd?/p>
一Q清除地形分U烦引缓冲及地Ş分页Q根据地形信息数据流加蝲地Ş信息配置文gQ?/span>
void TerrainSceneManager::loadConfig(DataStreamPtr& stream)Q其先将地Ş配置信息从数据流中逐一d到map中,然后通过void TerrainSceneManager::selectPageSource(const String& typeName, TerrainPageSourceOptionList& optionList)讄地Ş数据?目前只有高度图数据源)。在地Ş信息配置文g中可以配|多个地形数据源Q然后根据一U数据源cd生成地ŞQ参?typeNameq来指定数据源cdQ目前就是HeightMapQ找到指定的数据源后Q对指定的数据源q行初始化,
void HeightmapTerrainPageSource::initialise(TerrainSceneManager* tsm, ushort tileSize, ushort pageSize, bool asyncLoading, TerrainPageSourceOptionList& optionList)。初始化的过E主要是调用void HeightmapTerrainPageSource::loadHeightmap(void)高度图灰度囑փ数据加蝲到内存中Q如果是Raw数据Q就加蝲到mRawData中,否则加蝲到mImage中。整个加载过E其实完成了两大工作Q首先加载地形配|信息,然后加蝲高度图数据?
二:初始化分U烦引缓Ԍvoid TerrainSceneManager::initLevelIndexes()Q?
三:void OctreeSceneManager::resize( const AxisAlignedBox &box )
四:讄地Ş材质Qvoid TerrainSceneManager::setupTerrainMaterial(void)Q?
五:讄地Ş分页Q?void TerrainSceneManager::setupTerrainPages(void)
首先创徏一个名为Terrain的场景根节点的子节点
mTerrainRoot = getRootSceneNode() -> createChildSceneNode( "Terrain" );
然后初始化TerrainPage2D mTerrainPagesQ?/span>
最后调?void HeightmapTerrainPageSource::requestPage(ushort x, ushort y)requestPage只支持一个PageQ首先将囑փ数据q行~放
然后调用 “TerrainPageSource::firePageConstructedQ)”通知ListenerQ然后调?#8220;TerrainPage* TerrainPageSource::buildPage(Real*heightData, const MaterialPtr& pMaterial)”创徏一个新的TerrainPage对象?/span>
buildPage()是一个比较核心的函数。它首先构造一?TerrainPage对象Q然后创Z个用于容UTerrainPage对象的场景节点:“page->pageSceneNode = mSceneManager->createSceneNode(name);”Q然后根据对地Ş的分Ԍ循环创徏子SceneNodeQƈ且创建子场景节点对应的可渲染体TerrainRenderableQ将该可渲染体attach到这个子节点上。通过 “TerrainRenderable::initialiseQ)”来创建顶Ҏ据、渲染方式等?
然后调用void TerrainSceneManager::attachPage(ushort pageX, ushort pageZ, TerrainPage* page)加入到mTerrainPages中;
然后在attachPage中调?#8220;mTerrainRoot->addChild(page->pageSceneNode);”加入到SceneGraph中?
注:当前只支持一个PageQ该分页被挂接到一个称谓Terrain的场景节点上Q该场景节点下面又创Z很多子场景节点,每一个子场景节点对应一个tileQ也是一个独立的可渲染体TerrainRenderable
U理好像q有些问?...
模型贴花Q根据脓花所在的|格自动生成模型Q一般脓图)
投媄贴花Q利用投q理的方式实现的脓花(frustumQ?/p>
|格贴花Q创建指定大的|格贴花Q然后自动调整网格的位置QmeshQ脓图)
#include "ExampleApplication.h"
class TutorialFrameListener : public ExampleFrameListener, public OIS::MouseListener, public OIS::KeyListener
{
public:
TutorialFrameListener(RenderWindow* win, Camera* cam, SceneManager *sceneMgr)
: ExampleFrameListener(win, cam, true, true)
{
// Populate the camera and scene manager containers
mCamNode = cam->getParentSceneNode();
mSceneMgr = sceneMgr;
// set the rotation and move speed
mRotate = 0.13;
mMove = 250;
// continue rendering
mContinue = true;
mMouse->setEventCallback(this);
mKeyboard->setEventCallback(this);
mDirection = Vector3::ZERO;
}
bool frameStarted(const FrameEvent &evt)
{
if(mMouse)
mMouse->capture();
if(mKeyboard)
mKeyboard->capture();
mCamNode->translate(mDirection * evt.timeSinceLastFrame, Node::TS_LOCAL);
return mContinue;
}
// MouseListener
bool mouseMoved(const OIS::MouseEvent &e)
{
if (e.state.buttonDown(OIS::MB_Right))
{
mCamNode->yaw(Degree(-mRotate * e.state.X.rel), Node::TS_WORLD);
mCamNode->pitch(Degree(-mRotate * e.state.Y.rel), Node::TS_LOCAL);
}
return true;
}
bool mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
Light *light = mSceneMgr->getLight("Light1");
switch (id)
{
case OIS::MB_Left:
light->setVisible(! light->isVisible());
break;
}
return true;
}
bool mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id) { return true; }
// KeyListener
bool keyPressed(const OIS::KeyEvent &e)
{
switch (e.key)
{
case OIS::KC_ESCAPE:
mContinue = false;
break;
case OIS::KC_1:
mCamera->getParentSceneNode()->detachObject(mCamera);
mCamNode = mSceneMgr->getSceneNode("CamNode1");
mCamNode->attachObject(mCamera);
break;
case OIS::KC_2:
mCamera->getParentSceneNode()->detachObject(mCamera);
mCamNode = mSceneMgr->getSceneNode("CamNode2");
mCamNode->attachObject(mCamera);
break;
case OIS::KC_UP:
case OIS::KC_W:
mDirection.z -= mMove;
break;
case OIS::KC_DOWN:
case OIS::KC_S:
mDirection.z += mMove;
break;
case OIS::KC_LEFT:
case OIS::KC_A:
mDirection.x -= mMove;
break;
case OIS::KC_RIGHT:
case OIS::KC_D:
mDirection.x += mMove;
break;
case OIS::KC_PGDOWN:
case OIS::KC_E:
mDirection.y -= mMove;
break;
case OIS::KC_PGUP:
case OIS::KC_Q:
mDirection.y += mMove;
break;
}
return true;
}
bool keyReleased(const OIS::KeyEvent &e)
{
switch (e.key)
{
case OIS::KC_UP:
case OIS::KC_W:
mDirection.z += mMove;
break;
case OIS::KC_DOWN:
case OIS::KC_S:
mDirection.z -= mMove;
break;
case OIS::KC_LEFT:
case OIS::KC_A:
mDirection.x += mMove;
break;
case OIS::KC_RIGHT:
case OIS::KC_D:
mDirection.x -= mMove;
break;
case OIS::KC_PGDOWN:
case OIS::KC_E:
mDirection.y += mMove;
break;
case OIS::KC_PGUP:
case OIS::KC_Q:
mDirection.y -= mMove;
break;
} // switch
return true;
}
protected:
Real mRotate; // The rotate constant
Real mMove; // The movement constant
SceneManager *mSceneMgr; // The current SceneManager
SceneNode *mCamNode; // The SceneNode the camera is currently attached to
bool mContinue; // Whether to continue rendering or not
Vector3 mDirection; // Value to move in the correct direction
};
class TutorialApplication : public ExampleApplication
{
public:
void createCamera(void)
{
// create camera, but leave at default position
mCamera = mSceneMgr->createCamera("PlayerCam");
mCamera->setNearClipDistance(5);
}
void createScene(void)
{
mSceneMgr->setAmbientLight(ColourValue(0.25, 0.25, 0.25));
// add the ninja
Entity *ent = mSceneMgr->createEntity("Ninja", "ninja.mesh");
SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("NinjaNode");
node->attachObject(ent);
// create the light
Light *light = mSceneMgr->createLight("Light1");
light->setType(Light::LT_POINT);
light->setPosition(Vector3(250, 150, 250));
light->setDiffuseColour(ColourValue::White);
light->setSpecularColour(ColourValue::White);
// Create the scene node
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1", Vector3(-400, 200, 400));
node->yaw(Degree(-45));
node->attachObject(mCamera);
// create the second camera node/pitch node
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2", Vector3(0, 200, 400));
}
void createFrameListener(void)
{
// Create the FrameListener
mFrameListener = new TutorialFrameListener(mWindow, mCamera, mSceneMgr);
mRoot->addFrameListener(mFrameListener);
// Show the frame stats overlay
mFrameListener->showDebugOverlay(true);
}
};
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif
{
// Create application object
TutorialApplication app;
try {
app.go();
} catch(Exception& e) {
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
fprintf(stderr, "An exception has occurred: %s\n",
e.getFullDescription().c_str());
#endif
}
return 0;
}
按照理论来说
unbufferedQ不断的响应按键信息Q直到按键放开。例如,按下上下左右Q得角色持l移动?
一般来讲适合?D场景漫游q程Q当在每帧渲染之前,pȝ捕获输入讑֤状态,q根据这些状态对场景中的物体和摄象机q行控制?
bufferedQ在一个按键放开之前Q只处理一ơ输入信息?
例如呼出主菜单。适合于GUI界面的情况(如设|菜单)Q输入设备状态可以被发送到各GUI元素q行处理Q如按钮被按下)?br>
q个例子试图说明~冲输入和非~冲输入的区别,但是让我困惑的是Z么采用了~冲输入pȝq能响应持箋按键呢?~译后运行按住WSAD照样Ud摄像机?/pre>
Code Knight 2009-12-06 19:44 发表评论]]>