Ogre基础教程8:多个以及双场景管理器

教程介绍

本篇短教程中,我们将涉及如何在多个场景管理器之间切换。

预备知识

目录

预备知识
开始
初始化代码
设置应用
创建场景管理器
创建摄像机
创建视口
创建场景
添加功能
双场景管理器
切换场景管理器
总结
覆盖
最后说明

开始

初始化代码

像这样,编辑你的 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渲染的关键。不管你创建多少个场景管理器,或在场景管理器中创建了多少摄像机,除非你为每个要展示的摄像机设置了一个视口,否则它们都不会被渲染到窗口上。也不要忘记,在创建视口前,先清理你不再使用的那些视口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值