在玩一些3D游戲的時候,經常會有畫中畫的功能,比如“跑跑卡丁車”、“殺手十三”等等,于是想自己動手試驗一下。
普通情況下,我們使用單一的攝像機,實現第一人稱或者第三人稱,有時我們用多個攝像機在單一的窗口中切換視角,比如從第一人稱切換到第三人稱視角(游戲中屢見不鮮),而畫中畫將會同時展現第一人稱和第三人稱(或者第三人稱與第三人稱),也就是說同時存在不同的觀察點,這就需要多窗口多攝像機分別進行渲染。
用Ogre實現畫中畫功能是件比較容易的事情,首先,搭建一個普通的場景,關于這方面的工作
www.ogre3d.org/wiki里有詳細的教程,不贅述了。
下面進入關鍵部分。
在Ogre里攝像機Camera和視口Viewport是一一對應的關系,普通情況下包含一個攝像機對應一個視口,我們只要添加攝像機和與之對應的視口就OK了!
我的窗口類里是這樣配置Ogre的,基本和教程示例里的一樣。
bool BaseApplication::setup(void)
{
mRoot = new Root();
// 設置資源
setupResources();
// 配置渲染窗口
bool carryOn = configure();
if (!carryOn)
return false;
// 創建場景管理器
chooseSceneManager();
// 創建攝像機
createCamera();
// 創建視口
createViewports();
// 設置缺省 mipmap 等級
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// 創建所有資源監聽器(為了加載屏幕)
createResourceListener();
// 加載資源
loadResources();
// 創建場景
createScene();
// 創建幀監聽器
createFrameListener();
return true;
}
其中,createCamera(); // 創建攝像機 和 createViewports(); // 創建視口 是我們需要關心的。
createCamera():
void BaseApplication::createCamera(void)
{
// 主窗口攝像機
mCamera_1 = mSceneMgr->createCamera("Cam_1");
mCamera_1->setPosition(Vector3(0,0,300));
mCamera_1->lookAt(Vector3(0,0,-300));
mCamera_1->setNearClipDistance(5);
// 畫中畫攝像機
mCamera_2 = mSceneMgr->createCamera("Cam_2");
mCamera_2->setPosition(Vector3(100,100,300));
mCamera_2->lookAt(Vector3(-100,-100,-300));
mCamera_2->setNearClipDistance(5);
}
createViewports():
void BaseApplication::createViewports(void)
{
// 主窗口
Viewport* vp_1 = mWindow->addViewport( mCamera_1 );
vp_1->setBackgroundColour( ColourValue(0,0,0) );
mCamera_1->setAspectRatio(
Real( vp_1->getActualWidth() ) / Real( vp_1->getActualHeight() ) );
// 畫中畫
Viewport* vp_2 = mWindow->addViewport( mCamera_2, 1, 0.7, 0.05, 0.25, 0.25 );
vp_2->setBackgroundColour( ColourValue(0,0,0) );
vp_2->setOverlaysEnabled(false);
mCamera_2->setAspectRatio(
Real( vp_2->getActualWidth() ) / Real(vp_2->getActualHeight() ) );
}
在addViewport中我們控制畫中畫視口在主窗口中的位置和大小(注意這里是0~1的取值范圍,類似于貼圖坐標)
這樣就實現了下圖所示效果的一半了。

是不是很酷?如果進一步設計成,當觸發某一事件時將畫中畫窗口動態的彈出,那就更酷了!有興趣的可以試一試:P
如圖所示,我另外還利用了CEGUI給畫中畫窗口加了個邊框,并且帶了一個combobox用來控制更多攝像機之間的切換,CEGUI是用腳本來定義界面的,實現也比較簡單。有關CEGUI部分的介紹,在ogre wiki上有更詳細的教程。
#end