教程介绍
本篇短教程中,我们将涉及如何在多个场景管理器之间切换。
预备知识
略
目录
预备知识
开始
初始化代码
设置应用
创建场景管理器
创建摄像机
创建视口
创建场景
添加功能
双场景管理器
切换场景管理器
总结
覆盖
最后说明
开始
初始化代码
像这样,编辑你的 BasicTutorial8 类的头文件:
#ifndef __BasicTutorial8_h_
#define __BasicTutorial8_h_
#include "BaseApplication.h"
class BasicTutorial8 : public BaseApplication
{
public:
BasicTutorial8(void);
virtual ~BasicTutorial8(void);
protected:
virtual void createScene(void);
virtual void chooseSceneManager(void);
virtual void createCamera(void);
virtual void createViewports(void);
virtual void createFrameListener(void);
virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
// OIS::KeyListener
virtual bool keyPressed( const OIS::KeyEvent &arg );
virtual bool keyReleased( const OIS::KeyEvent &arg );
// OIS::MouseListener
virtual bool mouseMoved( const OIS::MouseEvent &arg );
virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
private:
Ogre::SceneManager* mPrimarySceneMgr;
Ogre::SceneManager* mSecondarySceneMgr;
bool mDual;
virtual void setupViewport(Ogre::SceneManager *curr);
virtual void dualViewport(Ogre::SceneManager *primarySceneMgr, Ogre::SceneManager *secondarySceneMgr);
};
#endif // #ifndef __BasicTutorial8_h_
确保你的基础教程8的实现文件如下所示:
#include "BasicTutorial8.h"
#define CAMERA_NAME "SceneCamera"
//-------------------------------------------------------------------------------------
BasicTutorial8::BasicTutorial8(void)
:mPrimarySceneMgr(0),
mSecondarySceneMgr(0),
mDual(false)
{
}
//-------------------------------------------------------------------------------------
BasicTutorial8::~BasicTutorial8(void)
{
}
//-------------------------------------------------------------------------------------
//Local Functions
void BasicTutorial8::setupViewport(Ogre::SceneManager *curr)
{
}
void BasicTutorial8::dualViewport(Ogre::SceneManager *primarySceneMgr, Ogre::SceneManager *secondarySceneMgr)
{
}
static void swap(Ogre::SceneManager *&first, Ogre::SceneManager *&second)
{
Ogre::SceneManager *tmp = first;
first = second;
second = tmp;
}
//-------------------------------------------------------------------------------------
void BasicTutorial8::createScene(void)
{
}
void BasicTutorial8::chooseSceneManager(void)
{
}
void BasicTutorial8::createCamera()
{
}
void BasicTutorial8::createViewports()
{
}
void BasicTutorial8::createFrameListener(void)
{
Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
OIS::ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
mInputManager = OIS::InputManager::createInputSystem( pl );
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));
mMouse->setEventCallback(this);
mKeyboard->setEventCallback(this);
//Set initial mouse clipping size
windowResized(mWindow);
//Register Window/Frame listener
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);
mRoot->addFrameListener(this);
}
bool BasicTutorial8::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if(mWindow->isClosed())
return false;
if(mShutDown)
return false;
//Need to capture/update each device
mKeyboard->capture();
mMouse->capture();
return true;
}
bool BasicTutorial8::keyPressed( const OIS::KeyEvent &arg )
{
if (arg.key == OIS::KC_ESCAPE)
{
mShutDown = true;
}
return true;
}
bool BasicTutorial8::keyReleased( const OIS::KeyEvent &arg )
{
return true;
}
bool BasicTutorial8::mouseMoved( const OIS::MouseEvent &arg )
{
return true;
}
bool BasicTutorial8::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}
bool BasicTutorial8::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
return true;
}
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char *argv[])
#endif
{
// Create application object
BasicTutorial8 app;
try {
app.go();
} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " <<
e.getFullDescription().c_str() << std::endl;
#endif
}
return 0;
}
#ifdef __cplusplus
}
#endif
在继续之前,请确定你可以编译这些代码;运行这个程序将仅展示一个全黑的屏幕。按下Esc来退出。
设置应用
创建场景管理器
我们已经讲解过,如何选择你的场景管理器,所以不在解释此函数的细节。唯一需要我们改变的是我们创建两个。找到chooseSceneManager函数,并且添加下面的代码:
mPrimarySceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "primary");
mSecondarySceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "secondary");
创建摄像机
需要做的下一件事是为两个场景管理器各创建一个摄像机。与之前教程唯一不同的是,我们创建了两个有相同名称的摄像机。找到createCamera函数,并且添加以下代码:
mPrimarySceneMgr->createCamera(CAMERA_NAME);
mSecondarySceneMgr->createCamera(CAMERA_NAME);
创建视口
为这个应用创建视口的过程里,我们将与前面教程有一点小改动。当你创建一个视口时,你必须做两件事:设置视口自己,然后设置你在使用的摄像机的纵横比。首先,添加以下代码到createViewports函数中:
setupViewport(mPrimarySceneMgr);
设置视口的实际代码在setupViewport函数中,因为我们将在其它地方复用这些。要做的第一件事,是移除之前创建的视口。暂时并没有已经创建的视口,但当我们未来再次调用这个函数时,我们需要确保在创建新的之前,它们被全部移除。在那之后,我们将设置视口,就像我们在之前教程里已经做的那样。添加以下内容到文件顶部的setupViewport函数中:
mWindow->removeAllViewports();
Ogre::Camera *cam = curr->getCamera(CAMERA_NAME); //The Camera
Ogre::Viewport *vp = mWindow->addViewport(cam); //Our Viewport linked to the camera
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
cam->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
创建场景
最后,我们需要为每个场景管理器创建一个场景。我们不需要做任何复杂工作,仅是 当在两个场景管理器之间切换时,让我们能够知晓的一些不同的事情。找到createScene函数,添加以下代码:
// Set up the space SceneManager
mPrimarySceneMgr->setSkyBox(true, "Examples/SpaceSkyBox");
// Set up the Cloudy SceneManager
mSecondarySceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
在继续之前,确保你的代码能编译。运行程序将会展示一个空间天空盒,目前这并不令人兴奋。
添加功能
双场景管理器
我们希望添加到程序的第一个功能,是允许用户一起渲染两个场景管理器。当V键被按下,我们将切换成双视口模式。基本的打算很简单。为了关闭双视口模式,我们仅需调用setupViewport(我们在前面的部分创建的)用主场景管理器以单视口模式来重新创建视口。当我们想要开启它时,我们将调用一个名为dualViewport的新函数。我们将用mDual变量追踪视口的状态。添加以下代码到keyPressed函数末尾:
else if(arg.key == OIS::KC_V){
mDual = !mDual;
if (mDual)
dualViewport(mPrimarySceneMgr, mSecondarySceneMgr);
else
setupViewport(mPrimarySceneMgr);
}
现在我们可以切换mDual变量,并且基于我们正处于的模式来调用合适的函数。下一步是定义dualViewport函数,它实际包含了同时展示两个视口的代码。
为了同时显示两个场景管理器,我们主要做的就是已经在setupViewport函数中进行过的相同工作。唯一不同的是,我们将创建两个视口,分别对应在我们两个场景管理器中各自的摄像机。添加代码到dualViewport函数:
mWindow->removeAllViewports();
Ogre::Viewport *vp = 0;
Ogre::Camera *cam = primarySceneMgr->getCamera(CAMERA_NAME);
vp = mWindow->addViewport(cam, 0, 0, 0, 0.5, 1);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
cam->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
cam = secondarySceneMgr->getCamera(CAMERA_NAME);
vp = mWindow->addViewport(cam, 1, 0.5, 0, 0.5, 1);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
cam->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
所有这些应该都很熟悉,除了我们在addViewport函数调用时,添加的额外参数。函数的第一个参数仍然是我们要使用的摄像机。
第二个参数是视口的Z顺序(z order)。一个更高的Z顺序会排在低的Z顺序之上。注意,你不能拥有两个Z顺序值相同的视口,即使它们并不重叠。随后两个参数是视口的左部和顶部位置,必须在0到1之间。最后两个参数是视口的宽度和高度占屏幕的百分比(它们也必须在0~1之间)。因此在这里的情形中,我们创建的第一个视口在位置(0,0),占据屏幕水平方向的一半以及垂直方向的全部。 第二个视口在(0.5,0)会占据一半的水平空间和整个垂直空间。
编译运行。通过按下V,现在你可以同时显示两个场景管理器。
切换场景管理器
我们要添加到程序中的而最后一个功能,是每当C被按下时,切换场景。我们将首先切换primarySceneMgr和secondarySceneMgr两个变量,这样当setupViewport()或dualViewport()函数被调用时,我们不需要担心哪个场景管理器在哪个变量中。主场景管理器将一直在单一模式中显示,并且在双视口模式中一直占据左边。添加以下代码到keyPressed()函数中:
else if(arg.key == OIS::KC_C){
swap(mPrimarySceneMgr, mSecondarySceneMgr);
if (mDual)
dualViewport(mPrimarySceneMgr, mSecondarySceneMgr);
else
setupViewport(mPrimarySceneMgr);
}
在交换了场景管理器变量后,我们执行想要的变更。我们要做的是,依赖于我们是否在双或单模式,调用合适的视口设置函数。
就是这样了!编译并运行。现在我们可以用C键切换场景管理器,并且用V键切换单双模式。
总结
覆盖
我相信,在你的程序中你已经注意到,当运行在双视口模式时,Ogredebug覆盖在两边显示。使用Viewport::setOverlayEnabled函数来开启或关闭它们。
最后说明
记住,视口类,尽管自身并没有很多功能,但却是所有Ogre渲染的关键。不管你创建多少个场景管理器,或在场景管理器中创建了多少摄像机,除非你为每个要展示的摄像机设置了一个视口,否则它们都不会被渲染到窗口上。也不要忘记,在创建视口前,先清理你不再使用的那些视口。