原始作者:Clay Culver 中文譯者:Antking OGRE教程(一) OGRE教程(二)
1)前提 2)簡介 3)開始 4)攝象機 4.1 OGRE 攝象機 4.2 建立攝象機 5)視口(viewports) 5.1 OGRE 視口 5.2 建立一個視口 6)燈光和陰影 6.1 OGRE支援的陰影類型 6.2 在OGRE中使用陰影 6.3 燈光的種類 6.4 建立燈光 7)嘗試 7.1 不同的陰影類型 7.2 燈光漸淡 7.3 SceneManager::setAmbientLight 7.4 視口背景顏色 7.5 Camera::setFarClipDistance 7.6 Planes(程度) 8)你的想法?
1)前提 這篇文章是假設你有C++編程知識並在編譯器中安裝和設定了OGRE。這篇文章是建立在第一篇教程的基礎上的。 2)簡介 在這篇教程中,我們將講解更多的關於OGRE的結構。這篇教程主要是關於燈光物體的,並講解了他們在OGRE中是如何建立陰影的。我們也將複習一下關於攝象機的知識。 通過這篇教程的學習,你將添加更多的代碼到你的程式中,並看見他們的結果。 3)開始 和第一篇教程一樣,我們將使用一些準備好了的代碼。我們將在我們的TutorialApplication 類中添加兩個方法:createViewport and createCamera。這兩個函數也是在基本的ExampleApplication中定義了的,但是,在這篇教程中,我們將看一下攝象機和視口在實際中是如何工作的。 在編譯器中建立一個工程,添加下面的代碼到裡面: #include "ExampleApplication.h" class TutorialApplication : public ExampleApplication { protected: public: TutorialApplication()
{
}
~TutorialApplication()
{
} protected:
virtual void createCamera(void)
{
}
virtual void createViewports(void)
{
}
void createScene(void)
{
Entity *ent;
Light *light;
} };
#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 occured!", MB_OK | MB_IConERROR | MB_TASKMODAL); #else
fprintf(stderr, "An exception has occured: %s/n", e.getFullDescription().c_str()); #endif
}
return 0; }
如果你在WINDOWS下使用OGRE SDK,請添加"[OgreSDK_DIRECTORY]/samples/include" 下的目錄到這個工程。如果你使用OGRE原始碼,請更換成下面的路徑"[OgreSource_DIRECTORY]/Samples/Common/include" 。請在繼續下一段時,確信你的程式能運行,運行時,顯示一個黑色的視窗。如果你在這裡有問題,請參考《OGRE初學者引導》。 程式控制: 用WASD鍵移動,滑鼠能環繞四周。ESCAPE鍵退出。 4)攝象機 4.1 OGRE 攝象機 下面,我們來建立查看情境的攝象機。攝象機是一個特別的物體,有點象SceneNode 。攝象機有setPosition,yaw,roll ,pitch4個函數,你能把他給予任何一個SceneNode 。和SceneNode 一樣,攝象機的位置和他的父節點有關。對於移動和旋轉攝象機,你應該象考慮SceneNode 一樣考慮他。 值得注意的是,你可能想只能在情境中建立一個攝象機,這就是說,我們不能建立一個用於情境一部分的攝象機,而另一個用於情境的另一部分,然後根據情境的顯示來確定使用哪個攝象機。相反,OGRE能建立很多的攝象機,把這些攝象機建立到SceneNode 中,然後根據情境顯示時,根據他的SceneNode 點中的攝象機來決定情境的顯示。我們將在FrameListener 教程中詳細討論他。 4.2 建立攝象機 我們將改變在ExampleApplication 中關於攝象機的方法。 找到TutorialApplication::createCamera 函數,因為攝象機是SceneManager 中的功能,因此,我們用SceneManager 來建立他們。添加下面的代碼到程式中: // create the camera mCamera = mSceneMgr->createCamera("PlayerCam"); 我們建立一個名叫PlayerCam"的攝象機。你能通過攝象機的名字,使用SceneManager 中的getCamera函數來得到攝象機,如果你不想把攝象機的指標給SceneManager 的話。 下面,我們將設定攝象機的位置和他的方向。因為物體初始時是在原點,因此我們的攝象機應該在+Z軸上變換,並使攝象機面向原點。添加下面代碼到程式中: // set its position, direction mCamera->setPosition(Vector3(0,10,500)); mCamera->lookAt(Vector3(0,0,0)); 你能使攝象機面向你調用yaw, rotate, and pitch 函數後的任何位置。 lookAt()在遊戲中精確定位很重要。 它使SceneNodes在遊戲中調整攝象機的方向很容易。最後,我們設定剪下距離為5。攝象機的剪下距離是指在你面前,你能看見的近處的或遠處的物 體。如果你把剪下距離的值設定的很小,你靠近物體,你不能全部看見,你只能看見物體的一小部分,相反,你將看見物體的全部。這在你將渲染大量的物體時很有 用。下面代碼設定最近的剪下距離: mCamera->setNearClipDistance(5); 設定最遠的剪下距離可以用setFarClipDistance。 5)視口(viewports) 5.1 OGRE 視口 當我們開始處理多個攝象機時,視口的概念就顯的很重要。我認為明白OGRE是如何用攝象機來渲染情境是很重要。在OGRE中,多個SceneManagers 一起運行是可能的。他們也可能把螢幕分成多個方塊,並且在螢幕上分別用攝象機渲染他們(例如,可以想象成有兩個人在玩遊戲)。關於這些是如何完成的,我們將在後面的教程中講解。 要明白OGRE是如何渲染情境的,要明白OGRE的三個結構:the Camera, the SceneManager, and the RenderWindow。RenderWindow 我們以前沒有講過,但非常的簡單,就是顯示物體的視窗。 而SceneManager用於建立攝像機來顯示情境。你必須告訴RenderWindow應該在螢幕上顯示那個攝像機,在視窗中什麼部分顯示他。而 你告訴RenderWindow顯示攝像機的那個視窗部分就是你的視口。在OGRE的通常的用法中,你只需要建立一個攝像機,而這個攝像機就佔有整個 RenderWindow,這樣就只有一個視口。 而在這章中,我們會講解如何通過攝像機建立視口。我們能用這個視口去設定我們渲染的情境的背景顏色。 5.2 建立一個視口 讓我們回到用ExampleApplication建立視口這個部分,找到TutorialApplication::createViewports 這個方法。要建立視口,我們只需要簡單地調用RenderWindow中的addViewport方法,並用我們用的攝像機去支援它。mWindow類是從ExampleApplication類中派生出來的,因此,我們添加下面的代碼: // Create one viewport, entire window Viewport* vp = mWindow->addViewport(mCamera); 現在,我們有了我們自己的視口,我們能用它做什麼呢?最為重要的就是用它去調用setBackgroundColour方法去設定背景顏色。在這裡,因為我們要處理燈光,因此,我們設定背景顏色為黑色。 vp->setBackgroundColour(Colourvalue(0,0,0)); 注意顏色值是用紅,綠和藍來表示的,而這些值的取值範圍為0到1。最後,我們要做的最為重要的事是設定攝像機的高寬比 。如果你設定標準全螢幕視口以外的模式,將得到一個很奇怪的情境。在這裡,我們設定初始的高寬比: // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight())); 6)燈光和陰影 6.1 OGRE支援的陰影類型 OGRE當前支援三種陰影: 1。調整紋理陰影(SHADOWTYPE_TEXTURE_MODULATIVE) - 是用的最常用的。這個用於建立黑白紋理陰影。 2,調整模版陰影(SHADOWTYPE_STENCIL_MODULATIVE) - 這種技術用於渲染所有在情境中不透明的物體。這種方法和附加模板陰影一樣,不常用,但是很精確。 3,附加模板陰影 (SHADOWTYPE_STENCIL_ADDITIVE) - 這種技術用於渲染情境中、每個光線。這在圖形卡上是非常困難的。 OGRE不將軟陰影作為引擎的一部分。 6.2 在OGRE中使用陰影 在OGRE中使用陰影比較簡單,SceneManager 中提供setShadowTechnique成員來設定陰影的類型。你也能用seCastShadows成員來設定投射陰影。 在這裡,我們設定環境光線為黑色,然後設定陰影。找到TutorialApplication::createScene成員,添加下面的代碼: mSceneMgr->setAmbientLight( Colourvalue( 0, 0, 0 ) ); mSceneMgr->setShadowTechnique( SHADOWTYPE_STENCIL_ADDITIVE ); 現在 SceneManager用調整紋理陰影,下面,我們建立一個物體,並使它投射陰影: ent = mSceneMgr->createEntity( "Ninja", "ninja.mesh" ); ent->setCastShadows( true ); mSceneMgr->getRootSceneNode()->createChildSceneNode( )->attachObject( ent ); 在這裡,ninja.mesh被 ExampleApplication預先匯入。為了讓ninja.mesh能顯示投射陰影,我們必須為它建立一個支援陰影的面。 (譯者註:下面這段文字可能有問題,原文如下: Again, the ninja.mesh has been preloaded for us by the ExampleApplication. We also need something for the Ninja to stand on (so that he has something to cast shadows onto). To do this we will create a simple plane for him to stand on. This is not meant to be a tutorial on using MeshManager, but we will go over the very basics since we have to use it to create a plane. First we need to define the Plane (http://www.ogre3d.org/docs/api/html/classOgre_1_1Plane.html) object itself, which is done by supplying a normal and the distance from the origin. We could (for example) use planes to make up parts of world geometry, in which case we would need to specify something other than 0 for our origin distance. For now we just want a plane to have the positive y axis as its normal (that means we want it to face up), and no distance from the origin: ) 首先,我們必須為它建立一個PLANE對象,這個對象支援法線和來自原點的距離。我們可以使面成為世界幾何物體的一部分,在這種情況下,我們將表明我們到原點的距離。但是現在,我們使面的法線的軸指向正Y軸,沒有到原點的距離: Plane plane( Vector3::UNIT_Y, 0 ); 現在,我們將儲存這個面,以便宜我們在程式中用到它。而MeshManager 類用於保持我們匯入情境中的所有網格的路徑。createPlane方法用於產生Plane的定義,並按照這些定義值產生網格。代碼如下: MeshManager::getSingleton().createPlane("ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z); 現在,也許你想知道MeshManager是如何使用的,但我現在並不想講解。在這裡,我們儲存我們的面為1500X1500的網格,命名為“ground".下面建立這個網格並在情境中固定它: ent = mSceneMgr->createEntity( "GroundEntity", "ground" ); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent); 在我們完成地面之前,我們需要做兩件重要的事情。第一件事是告訴SceneManager 我們不想在不知道用什麼陰影的情況下投射陰影。第二件事是地面的紋理。我們的機器人肯ninja 已經有材質指令碼定義了。當我們建立我們的地面時,並沒有為他建立文理。在這裡我們用OGRE中的"Examples/Rockwall"中的材質指令碼: ent->setMaterialName("Examples/Rockwall"); ent->setCastShadows(false); 現在,我們在情境中有Ninja和地面,讓我們編譯和運行它。我們並沒有看見任何物體!WHY? 那是因為我們沒有添加燈光,下面讓我們添加燈光。 6.3 燈光的種類 在OGRE中提供了三種燈光: 1,點(LT_POINT) - 從一點發出,向四面發散。 2,點光(LT_SPOTLIGHT) - 點光有點象電筒光。光從一點開始,然後朝一個方向發散。你也能定義點光的圓的角度,分為光源部分和散射部分。 3,方向光(LT_DIRECTIONAL) - 方向光有點象鏡面反射光。例如,你建立了一個夜晚的情境,你想類比月光。在這裡,你能根據月亮的發射方向使用方向光來類比月光。 光有許多參數,其中最為重要的是diffuse 和specular.每個材質指令碼定義材質能反射多少diffuse 和specular光,在下面的章節中,我們將詳細學習。 6.4 建立燈光 在OGRE中建立燈光,我們需要調用SceneManager中createLight方法。建立了燈光後,我們能設定它的位置或將它和SceneNode 聯絡起來,以便於移動。燈光只有兩個函數用於設定:setPosition 和setDirection.因此,你想建立固定光,只需要調用setPosition方法。如果你想建立活動光,只需要將它和SceneNode聯絡起來。 下面,我們來建立點,第一步是建立燈光,設定類型和位置: light = mSceneMgr->createLight( "Light1" ); light->setType( Light::LT_POINT ); light->setPosition( Vector3(0, 150, 250) ); 我們已經建立了燈光,下面我們需要設定diffuse and specular顏色,這裡設定紅色: light->setDiffuseColour( 1.0, 0.0, 0.0 ); light->setSpecularColour( 1.0, 0.0, 0.0 ); 現在編譯,運行,這時你能看見Ninja和它的陰影。注意我們並不能看見光源,而只能看見光源產生的結果。 下面,我們將建立方向光,在這裡我們建立了黃色的方向光: light = mSceneMgr->createLight( "Light3" ); light->setType( Light::LT_DIRECTIONAL ); light->setDiffuseColour( Colourvalue( .25, .25, 0 ) ); light->setSpecularColour( Colourvalue( .25, .25, 0 ) ); 前面我們並沒有設定方向光的方向,而只設定了它的位置,下面,我們將設定它的方向:指向正Z軸和負Y軸: light->setDirection( Vector3( 0, -1, 1 ) ); 編譯和運行,你將在情境中得到兩個陰影。最後,我們來建立點光: light = mSceneMgr->createLight( "Light2" ); light->setType( Light::LT_SPOTLIGHT ); light->setDiffuseColour( 0, 0, 1.0 ); light->setSpecularColour( 0, 0, 1.0 ); 我們同樣需要設定點光的位置和方向: light->setDirection( -1, -1, 0 ); light->setPosition( Vector3( 300, 300, 0 ) ); 想象一下,電筒可以通過調節光圈來控制光的範圍。同樣點光可以通過setSpotlightRange方法來調節: light->setSpotlightRange( Degree(35), Degree(50) ); 7)嘗試 7.1 不同的陰影類型 在這篇文章中,我們只使用了陰影的SHADOWTYPE_STENCIL_ADDITIVE類型,請你試試其他兩種類型,看看發生了什麼。在SceneManager中還有許多其他關於陰影的函數。試試它們,看看你能否使用它們。 7.2 燈光漸淡 燈光中還提供了一個setAttenuation,用於減淡燈光。將這個函數加入你的點光中,設定不同的值,看看有什麼效果。 7.3 SceneManager::setAmbientLight 測試一下SceneManager中的setAmbientLight方法。 7.4 視口背景顏色 在createViewports函數中改變顏色值。學會如何去改變它,以便於更好的使用它。 7.6 Planes(程度) 在這章中,我們並沒有詳細講解Planes(程度),我們將在下一課講解它。在這裡,你主要是學會如何使用createPlane函數。 8)你的想法? 如果你對文中的一些東西不是很清楚,請到論壇中討論。關於這篇譯稿的問題,請發郵件給我 antking@gmail.cn 我的blog為:http://akinggame.gameres.com |