bool mDeform; // stores which mode we are in (deform or paint)
uint mChosenTexture; // which of the four splatting textures is to be used?
// movement
Vector3 mDirection;
bool mMove;
SceneNode* mCamNode;
bool mContinue;
ET::TerrainManager* mTerrainMgr;
const ET::TerrainInfo* mTerrainInfo;
ET::SplattingManager* mSplatMgr;
};
class DemoETSM : public ExampleApplication
{
private:
ET::TerrainManager* mTerrainMgr;
ET::SplattingManager* mSplatMgr;
protected:
CEGUI::OgreCEGUIRenderer *mGUIRenderer;
CEGUI::System *mGUISystem; // cegui system
public:
DemoETSM()
{
mTerrainMgr = 0;
mSplatMgr = 0;
}
~DemoETSM()
{
delete mTerrainMgr;
delete mSplatMgr;
}
protected:
void chooseSceneManager(void)
{
// Create instance of the Editable Terrain Scene Manager
mSceneMgr = mRoot->createSceneManager("OctreeSceneManager", "ETInstance");
}
void createScene(void)
{
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
//mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
// create terrain manager
mTerrainMgr = new ET::TerrainManager(mSceneMgr);
mTerrainMgr->setLODErrorMargin(2, mCamera->getViewport()->getActualHeight());
mTerrainMgr->setUseLODMorphing(true, 0.2, "morphFactor");
// create a fresh, mid-high terrain for editing
ET::TerrainInfo terrainInfo (129, 129, vector<float>(129*129, 0.5f));
// set position and size of the terrain
terrainInfo.setExtents(AxisAlignedBox(0, 0, 0, 1500, 300, 1500));
// now render it
mTerrainMgr->createTerrain(terrainInfo);
// create the splatting manager
mSplatMgr = new ET::SplattingManager("ETSplatting", "ET", 128, 128, 3);
// specify number of splatting textures we need to handle
mSplatMgr->setNumTextures(6);
// create a manual lightmap texture
TexturePtr lightmapTex = TextureManager::getSingleton().createManual(
"ETLightmap", "ET", TEX_TYPE_2D, 128, 128, 1, PF_BYTE_RGB);
Image lightmap;
ET::createTerrainLightmap(terrainInfo, lightmap, 128, 128, Vector3(1, -1, 1),
ColourValue::White,
ColourValue(0.3, 0.3, 0.3));
lightmapTex->getBuffer(0, 0)->blitFromMemory(lightmap.getPixelBox(0, 0));
// load the terrain material and assign it
MaterialPtr material (MaterialManager::getSingleton().getByName("ETTerrainMaterial")); mTerrainMgr->setMaterial(material);
// Set camera look point
SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
camNode->setPosition( 40, 300, 580 );
camNode->attachObject(mCamera);
mCamera->pitch( Degree(-30) );
mCamera->yaw( Degree(-45) );
// CEGUI setup
mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false,
3000, mSceneMgr);
mGUISystem = new CEGUI::System(mGUIRenderer);
CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme"); CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
}
void createFrameListener(void)
{
mFrameListener= new DemoListener(mWindow, mCamera, mSceneMgr, mGUIRenderer, mTerrainMgr, mSplatMgr);
mFrameListener->showDebugOverlay(true);
mRoot->addFrameListener(mFrameListener);
}
};
#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
DemoETSM app;
try {
app.go();
} catch( 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
fprintf(stderr, "An exception has occured: %sn",
e.getFullDescription().c_str());
#endif
}
return 0;
}
另外, ETSM使用自己文件系统,所以如果自己使用它作为插件,别忘了在resources.cfg中加上
[ET]
FileSystem=../../media/ET
MAX插件ofusion
Ofusion是很强大的插件工具,除了可以导出MESH,动画,材质,场景,还可以导出GPU高级材质,而且使用也是很简单的,oFusionPro是ofusion的使用文档,具体内容可以参考它。下面分析如何将ofusion的场景导入到OGRE中。oSceneLoader_demo_dagon就是这样一个导入的例子,可以到OFUSION的网站下载。因为这是个老的例子,可能有时候和新的OGRE版本有冲突,如果有这样的情况,可以到OGRE中文论坛来,我们修改以后上传给你。
/**********************************************************************
*<
*> Copyright (c) 2006, All Rights Reserved.
**********************************************************************/
#include "ExampleApplication.h" HISTORY: CREATED BY: Andres Carrera DESCRIPTION: Scene Loader Demo header FILE: oSceneLibDemo.h oFusion Scene Loader CE Demo Application (see License.txt)
OGRE周边版块
OGRE本身作为图形引擎是非常强大的,但是如果要想只用它来做游戏还是不够的,我们必须有声音,界面,物理,输入,人工智能等等。很幸运OGRE现在有着庞大的社群支持(OGRE中文GAMERES是中文网站中人最多的),在几乎各个可能需要的领域都有许多优秀人才做着基础的工作,而且绝大多数是免费或者近乎免费的提供使用。在这么多前人的努力只下,使用OGRE做游戏|虚拟现实已经变的容易的多了。
1、 声音
在OGRE添加声音有很多选择,比如:DXSOUND、DXMUSIC、FMOD、OPENAL、AUDIERE等等,这完全看个人爱好以及对这些SDK的熟悉程度来选择了。
DXSOUND、DXMUSIC都是DIRECTX组件,会使用的人也很多,很容易能找到相关的书籍,所以我主要介绍后面几个声音引擎在OGRE中的使用。
1.1 FMOD
The FMOD Ex声音系统是一个针对多种音频开发人员的解决方案,包括游戏开发人员、多媒体开发者、声音设计师、甚至是音乐家、音频引擎的开发者,它是基于Firelight多年在声音引擎开发方面的经验研发而成。官方网站:http://www.fmod.org,提供FMOD的免费下载,当然如果商用的话还是要购买使用权,不过价格还是很便宜的,100美元。现在有很多游戏公司已经选择它作为自己声音库,搜狐的天龙八部,还有暴雪公司也放弃了自己原来做的声音库并购买了FMOD的使用权等等就不多说了。
FMOD支持几乎所有的声音格式:.MOD, .S3M, .XM, .IT or .MID……而且可以运行在windows,winCE,Linux,GameCube Xbox等平台上。
下面介绍简要FMOD的使用的方法
首先下载API(OGRE的API、FMOD的API)并且安装配置环境,需要注意的是使用不同的IDE需要舔加不同的LIB文件:
fmodvc.lib 用于 Microsoft Visual C++ 和 Codewarrior
fmodbc.lib 用于 Borland
fmodwc.lib 用于 Watcom
fmodcc.lib 用于 LCC-Win32
libfmod.a 用于 MingW and CygWin
fmod-3-7.lib 用于 GCC
以Microsoft Visual C++2005为例,舔加fmodvc.lib,然后加如入fmod.hpp头文件后就可以使用了.以Demo_ParticleFX这个例子为原型,向其中加FMOD代码实现简单的声音效果。
Demo_ParticleFX原代码如下:(
头文件
#include "ExampleApplication.h"
/*加入必要的头文件*/
#include "../../api/inc/fmod.hpp" //*******************************
#include "../../api/inc/fmod_errors.h"//*******************************
#include <windows.h>//*******************************
#include <stdio.h>//*******************************
#include <conio.h>//*******************************
/*定义初始化常用的参数*/
FMOD::System *system = 0; //*******************************
//FMO系统,也算是最根本的部分
FMOD::Sound *sound = 0; //*******************************
//声音,和一个声音文件关联,比如**.wave
FMOD::Channel *channel = 0; //*******************************
//声道
FMOD_RESULT result; //*******************************
//结果,主要是根据函数返回的结果,做出相应的处理。
unsigned int version; //*******************************
//版本
// Event handler to add ability to alter curvature
class ParticleFrameListener : public ExampleFrameListener
{
protected:
SceneNode* mFountainNode;
public:
ParticleFrameListener(RenderWindow* win, Camera* cam, SceneNode* fountainNode) : ExampleFrameListener(win, cam)
{
mFountainNode = fountainNode;
}
bool frameStarted(const FrameEvent& evt)
{
if( ExampleFrameListener::frameStarted(evt) == false )
return false;
// Rotate fountains
mFountainNode->yaw(Degree(evt.timeSinceLastFrame * 30));
// Call default
return true;
}
};
class ParticleApplication : public ExampleApplication
{
public:
ParticleApplication() {}
protected:
SceneNode* mFountainNode;
// Just override the mandatory create scene method
void createScene(void)
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
Entity *ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
// Add entity to the root scene node
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
// Green nimbus around Ogre
//mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(
// mSceneMgr->createParticleSystem("Nimbus", "Examples/GreenyNimbus"));
// Create some nice fireworks
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(
mSceneMgr->createParticleSystem("Fireworks", "Examples/Fireworks"));
// Create shared node for 2 fountains
mFountainNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
// fountain 1
ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("fountain1",
"Examples/PurpleFountain");
// Point the fountain at an angle
SceneNode* fNode = mFountainNode->createChildSceneNode();
fNode->translate(200,-100,0);
fNode->rotate(Vector3::UNIT_Z, Degree(20));
fNode->attachObject(pSys2);
// fountain 2
ParticleSystem* pSys3 = mSceneMgr->createParticleSystem("fountain2",
"Examples/PurpleFountain");
// Point the fountain at an angle
fNode = mFountainNode->createChildSceneNode();
fNode->translate(-200,-100,0);
fNode->rotate(Vector3::UNIT_Z, Degree(-20));
fNode->attachObject(pSys3);
// Create a rainstorm
ParticleSystem* pSys4 = mSceneMgr->createParticleSystem("rain",
"Examples/Rain");
SceneNode* rNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
rNode->translate(0,1000,0);
rNode->attachObject(pSys4);
// Fast-forward the rain so it looks more natural
pSys4->fastForward(5);
// Aureola around Ogre perpendicular to the ground
ParticleSystem* pSys5 = mSceneMgr->createParticleSystem("Aureola",
"Examples/Aureola");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pSys5);
/*下面是FMOD的使用部分*/
result = FMOD::System_Create(&system);
//创建系统
if (result != FMOD_OK)
{
//在这里也可以使用LOG文件输出错误内容以便出错时确定出错位置。下面可能出错的地方也可以这样做。
exit(-1);
}
//处理返回的结果
result = system->getVersion(&version);
//创建版本
if (result != FMOD_OK) // Set nonvisible timeout ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);
exit(-1);
}
//处理返回的结果
if (version < FMOD_VERSION)
{
return 0;
}
//如果版本低,报错。
result = system->init(32, FMOD_INIT_NORMAL, 0);
//系统初始化,参数分别代表最大声道数,播放的FLAG,额外的设备数据
if (result != FMOD_OK)
{
exit(-1);
}
result = system->createSound("../media/playlist.m3u", FMOD_DEFAULT, 0, &playlist);
//创建声音,参数分别代表声音文件(其实是声音的绝对路径),模式,额外信息,声音(以备后用) if (result != FMOD_OK)
{
exit(-1);
}
result = sound->setMode(FMOD_LOOP_NORMAL);
//设置声音模式,这里是普通循环。
if (result != FMOD_OK)
{
exit(-1);
}
result = system->playSound(FMOD_CHANNEL_FREE, sound, false, &channel);
//播放声音,当然也可以放在其他你认为合适的地方播放
if (result != FMOD_OK)
{
exit(-1);
}
/*FMOD部分至此*/
}
// Create new frame listener
void createFrameListener(void)
{
mFrameListener= new ParticleFrameListener(mWindow, mCamera, mFountainNode); mRoot->addFrameListener(mFrameListener);
};
源文件:
#include "ParticleFX.h"
#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
ParticleApplication 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();
#endif
}
return 0;
}
#ifdef __cplusplus
}
#endif
是不是很简单好用啊,编译下听听效果把,当然这只是简单的使用。另外FMOD的退出时的内存释放工作可以这么写
if (sound)
{
result = sound->release();
if (result != FMOD_OK)
{
exit(-1);
}
}
result = system->close();
if (result != FMOD_OK)
{
exit(-1);
}
result = system->release();
if (result != FMOD_OK)
{
exit(-1);
}
1.2 Audiere使用
Audiere是个轻量级的声音引擎,功能虽然没FMOD那么强大,但是简单、易用。 可以到http://sourceforge.net/projects/audiere/下载。其实OGRE的DEMO中有个是使用了audiere的(Magic of Stonehenge demo ),虽然从代码来看并没有很复杂的技术,但是作者巧妙的构思、完美的搭配以及使用audiere实现的声音给人一种很震撼的艺术效果。
下面分析这个DEMO是如何使用AUDIERE的。原代码如下: /*
Magic of Stonehenge demo v1.0
Programming:
Arsen Gnatkivsky "Troglodit"
e-mail: trogl@inbox.ru
used engines:
OGRE : http://www.ogre3d.org
audiere : http://audiere.sourceforge.net/
*/
#include "ExampleApplication.h"
#include <audiere.h>//添加头文件,别忘了自己链接audiere.lib
ParticleSystem *pThrusters;
AnimationState* mAnimState;
SceneNode* camNode;
Overlay* mBlackOverlay;
audiere::AudioDevicePtr device(audiere::OpenDevice());//设备
audiere::OutputStreamPtr stream(audiere::OpenSound(device, "music.wav", false));
//输出流,和声音文件相关联。参数分别为设备,声音文件,是否是流文件
std::ofstream posLog("position.log");
class SkyBoxFrameListener : public ExampleFrameListener
{
private:
static float fDefDim;
static float fDefVel;
public:
SkyBoxFrameListener(RenderWindow* win, Camera* cam) : ExampleFrameListener( win, cam ) {
}
bool frameStarted( const FrameEvent& evt )
{
// This peace op code you need when you capture the camera motion
// it will generate c++ code for keyframes in separate file
/*
posLog << "key = track->createKeyFrame(animDelay*"<<tim<<"+timOffset);n"; posLog <<"key->setTranslate(Vector3("<< pos.x << "," << pos.y << "," << pos.z Quaternion ori=mCamera->getOrientation(); Vector3 pos=mCamera->getPosition(); nothold=false; mWindow->setDebugText("!!!!!"); { if (nothold==true){ if( mInputDevice->isKeyDown( KC_SPACE ) ) static Real tim=0; tim+=evt.timeSinceLastEvent; static bool nothold=true; bool bOK = ExampleFrameListener::frameStarted( evt ); mAnimState->addTime(evt.timeSinceLastFrame); showDebugOverlay(false); << "));n";
posLog <<"key->setRotation(Quaternion("<< ori.w << "," << ori.x << "," << ori.y << "," << ori.z << "));n";
*/
}
};
} else { } nothold=true; static int nohide=3; static bool isTest=true; if (isTest){ } if (nohide<1) { } else nohide--; mBlackOverlay->hide(); isTest=false; return bOK;
float SkyBoxFrameListener::fDefDim = 25.0f; float SkyBoxFrameListener::fDefVel = 50.0f;
class SkyBoxApplication : public ExampleApplication {
public:
SkyBoxApplication() {}
protected:
virtual void createFrameListener(void)
{
}
// Just override the mandatory create scene method void createScene(void)
{
stream->setRepeat(true);//设置流是否循环播放 stream->setVolume(0.5f); // 声音大小 stream->play();//播放 mFrameListener= new SkyBoxFrameListener(mWindow, mCamera); mRoot->addFrameListener(mFrameListener);
mSceneMgr->getRootSceneNode()->attachObject(ground); mSceneMgr->getRootSceneNode()->attachObject(s1); mSceneMgr->getRootSceneNode()->attachObject(s2); mSceneMgr->getRootSceneNode()->attachObject(s3); mSceneMgr->getRootSceneNode()->attachObject(s4); mSceneMgr->getRootSceneNode()->attachObject(s5); mSceneMgr->getRootSceneNode()->attachObject(s6); mSceneMgr->getRootSceneNode()->attachObject(s7); mSceneMgr->getRootSceneNode()->attachObject(s8); mSceneMgr->getRootSceneNode()->attachObject(s9); mSceneMgr->getRootSceneNode()->attachObject(s10); mSceneMgr->getRootSceneNode()->attachObject(s11); mSceneMgr->getRootSceneNode()->attachObject(s12); mSceneMgr->getRootSceneNode()->attachObject(s13); mSceneMgr->getRootSceneNode()->attachObject(s14); mSceneMgr->getRootSceneNode()->attachObject(s15); //------------------------------------------ Entity *ground = mSceneMgr->createEntity( "ground", "Plane01.mesh" ); Entity *s1 = mSceneMgr->createEntity( "s1", "s1.mesh" ); Entity *s2 = mSceneMgr->createEntity( "s2", "s2.mesh" ); Entity *s3 = mSceneMgr->createEntity( "s3", "s3.mesh" ); Entity *s4 = mSceneMgr->createEntity( "s4", "s4.mesh" ); Entity *s5 = mSceneMgr->createEntity( "s5", "s5.mesh" ); Entity *s6 = mSceneMgr->createEntity( "s6", "s6.mesh" ); Entity *s7 = mSceneMgr->createEntity( "s7", "s7.mesh" ); Entity *s8 = mSceneMgr->createEntity( "s8", "s8.mesh" ); Entity *s9 = mSceneMgr->createEntity( "s9", "s9.mesh" ); Entity *s10 = mSceneMgr->createEntity( "s10", "s10.mesh" ); Entity *s11 = mSceneMgr->createEntity( "s11", "s11.mesh" ); Entity *s12 = mSceneMgr->createEntity( "s12", "s12.mesh" ); Entity *s13 = mSceneMgr->createEntity( "s13", "s13.mesh" ); Entity *s14 = mSceneMgr->createEntity( "s14", "s14.mesh" ); Entity *s15 = mSceneMgr->createEntity( "s15", "s15.mesh" ); l->setPosition(20,80,50); // Create a light Light* l = mSceneMgr->createLight("MainLight"); // Set ambient light mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
ParticleSystem* pSys2 =
ParticleSystemManager::getSingleton().createSystem("fountain1", "PEExamples/stoneh2");
ParticleSystem* pSys3 =
ParticleSystemManager::getSingleton().createSystem("fountain2", "PEExamples/stoneh2_small");
ParticleSystem* pSys4 = mSceneMgr->getRootSceneNode()->attachObject(pSys2); Entity *pilon = mSceneMgr->createEntity( "pilon", "pilon.mesh" ); mSceneMgr->getRootSceneNode()->attachObject(pilon); Entity *cast1 = mSceneMgr->createEntity( "cast1", "cast1.mesh" ); mSceneMgr->getRootSceneNode()->attachObject(cast1);
ParticleSystemManager::getSingleton().createSystem("fountain3", "PEExamples/stoneh2_small");
Entity *cast3 = mSceneMgr->createEntity( "cast3", "cast1.mesh" ); SceneNode* cast3_node=mSceneMgr->getRootSceneNode()->createChildSceneNode(); spout_node1->setPosition(triSpoutPos1); spout_node2->setPosition(triSpoutPos2); spout_node3->setPosition(triSpoutPos3); Real max2ogre=0.025; Vector3 triSpoutPos1=Vector3(-0.084/max2ogre,0.354/max2ogre,-7.047/max2ogre); Vector3 triSpoutPos2=Vector3(5.872/max2ogre,0.354/max2ogre,3.461/max2ogre); Vector3 triSpoutPos3=Vector3(-5.787/max2ogre,0.354/max2ogre,3.351/max2ogre); spout_node1->attachObject(pSys3); spout_node2->attachObject(pSys4); spout_node3->attachObject(pSys5); ParticleSystem* pSys5 = SceneNode* spout_node1=mSceneMgr->getRootSceneNode()->createChildSceneNode(); SceneNode* spout_node2=mSceneMgr->getRootSceneNode()->createChildSceneNode(); SceneNode* spout_node3=mSceneMgr->getRootSceneNode()->createChildSceneNode(); ParticleSystemManager::getSingleton().createSystem("fountain4", "PEExamples/stoneh2_small");
cast3_node->setScale(5,1,5); cast3_node->setPosition(0,100,0); cast3->setMaterialName("cast3"); Entity *cast4 = mSceneMgr->createEntity( "cast4", "cast1.mesh" ); SceneNode* cast4_node=mSceneMgr->getRootSceneNode()->createChildSceneNode(); cast4_node->attachObject(cast4); cast4_node->setScale(2,1,2); cast4_node->setPosition(0,200,0); cast4->setMaterialName("cast4"); Entity *castTri1 = mSceneMgr->createEntity( "castTri1", "cast1.mesh" ); SceneNode* castTriNode1=mSceneMgr->getRootSceneNode()->createChildSceneNode(); castTriNode1->attachObject(castTri1); castTriNode1->setScale(0.5,0.1,0.5); castTriNode1->setPosition(triSpoutPos1-Vector3(0,-10,0)); castTri1->setMaterialName("castTri"); Entity *castSun2 = mSceneMgr->createEntity( "castSun2", "cast1.mesh" ); SceneNode* castSunNode2=mSceneMgr->getRootSceneNode()->createChildSceneNode(); castSunNode2->attachObject(castSun2); castSunNode2->setScale(1.5,0.1,1.5); //castSunNode1->setPosition(triSpoutPos1-Vector3(0,-10,0)); castSunNode2->setPosition(0,10,0); castSun2->setMaterialName("castsun1"); for (int sc=1;sc<20;sc++) { Entity *castSun1 =
mSceneMgr->createEntity( "castSun1"+StringConverter::toString(sc), "cast1.mesh" );
SceneNode* castSunNode1=mSceneMgr->getRootSceneNode()->createChildSceneNode(); castSunNode1->attachObject(castSun1); castSunNode1->setScale(2.5-sc*0.05,0.1,2.5-sc*0.05); //castSunNode1->setPosition(triSpoutPos1-Vector3(0,-10,0)); castSunNode1->setPosition(0,40+sc*10,0); castSunNode1->yaw(Radian(0.5)); castSunNode1->pitch(Radian(rand()%5)); castSunNode1->roll(Radian(rand()%5));
}; Entity *castTri2 = mSceneMgr->createEntity( "castTri2", "cast1.mesh" ); SceneNode* castTriNode2=mSceneMgr->getRootSceneNode()->createChildSceneNode(); castTriNode2->attachObject(castTri2); castTriNode2->setScale(0.5,0.1,0.5); castTriNode2->setPosition(triSpoutPos2-Vector3(0,-10,0)); castTriNode2->yaw(Radian(-90.0)); castTri2->setMaterialName("castTri"); Entity *castTri3 = mSceneMgr->createEntity( "castTri3", "cast1.mesh" ); SceneNode* castTriNode3=mSceneMgr->getRootSceneNode()->createChildSceneNode(); castTriNode3->attachObject(castTri3); castTriNode3->setScale(0.5,0.1,0.5); castTriNode3->setPosition(triSpoutPos3-Vector3(0,-10,0)); castTriNode3->yaw(Radian(90.0)); castTri3->setMaterialName("castTri"); Entity *gorizont = mSceneMgr->createEntity( "gorizont", "gorizont.mesh" ); mSceneMgr->getRootSceneNode()->attachObject(gorizont); Entity *barier = mSceneMgr->createEntity( "barier", "barier.mesh" ); mSceneMgr->getRootSceneNode()->attachObject(barier); //----------------------------------------- SceneNode* lookNode= mSceneMgr->getRootSceneNode()->createChildSceneNode(); lookNode->setPosition(0,200,0); camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); camNode->attachObject(mCamera); mCamera->setPosition(0,0,0); camNode->setPosition(-244.852,392.682,-357.77); camNode->setOrientation(Quaternion(0.345054,-0.0821347,0.909552,0.216516)); camNode->needUpdate(); // set up spline animation of node Animation* anim = mSceneMgr->createAnimation("CameraTrack",319.382-28.307);// 319.382-28.5128
// Spline it for nice curves anim->setInterpolationMode(Animation::IM_SPLINE);
// Create a track to animate the camera's node AnimationTrack* track = anim->createTrack(0, camNode); // Setup keyframes KeyFrame* key; key = track->createKeyFrame(0); // startposition unsigned fr=0; Real animDelay=1; Real timOffset=-28.8307*animDelay; key = track->createKeyFrame(animDelay*28.8307+timOffset); key->setTranslate(Vector3(-244.852,392.682,-357.77)); key->setRotation(Quaternion(0.345054,-0.0821347,0.909552,0.216516)); key = track->createKeyFrame(animDelay*35.2817+timOffset); key->setTranslate(Vector3(-393.737,294.394,-113.343)); key->setRotation(Quaternion(-0.306394,0.0508652,0.937698,0.155653)); key = track->createKeyFrame(animDelay*40.6439+timOffset); key->setTranslate(Vector3(-422.293,349.852,173.018)); key->setRotation(Quaternion(-0.800221,0.201077,0.547927,0.137671)); key = track->createKeyFrame(animDelay*49.6474+timOffset); key->setTranslate(Vector3(-79.646,349.852,560.048)); key->setRotation(Quaternion(-0.896801,0.294858,0.313268,0.102994)); key = track->createKeyFrame(animDelay*58.5187+timOffset); key->setTranslate(Vector3(501.429,267.73,432.065)); key->setRotation(Quaternion(-0.993273,0.115458,-0.000865597,-0.000100481)); key = track->createKeyFrame(animDelay*67.743+timOffset); key->setTranslate(Vector3(640.836,323.694,-73.3012)); key->setRotation(Quaternion(-0.605509,0.0523376,-0.79111,-0.0683883)); key = track->createKeyFrame(animDelay*82.8461+timOffset); key->setTranslate(Vector3(169.581,523.395,-738.473)); key->setRotation(Quaternion(-0.153773,0.0488329,-0.940583,-0.298618)); key = track->createKeyFrame(animDelay*94.9738+timOffset); key->setTranslate(Vector3(-544.202,335.46,-620.324)); key->setRotation(Quaternion(-0.0808456,0.0166631,-0.976055,-0.200973)); key = track->createKeyFrame(animDelay*114.848+timOffset); key->setTranslate(Vector3(-1279.63,1060.58,186.159)); key->setRotation(Quaternion(0.734783,-0.290591,-0.569856,-0.22537)); key = track->createKeyFrame(animDelay*129.583+timOffset); key->setTranslate(Vector3(-892.411,1131.63,999.012)); key->setRotation(Quaternion(0.837642,-0.232815,-0.47594,-0.132303)); key = track->createKeyFrame(animDelay*141.035+timOffset);
key->setRotation(Quaternion(0.905332,-0.191741,-0.370559,-0.0785072)); key = track->createKeyFrame(animDelay*154.269+timOffset); key->setTranslate(Vector3(528.32,321.039,1093.36)); key->setRotation(Quaternion(0.949058,-0.24763,0.188184,0.0490821)); key = track->createKeyFrame(animDelay*167.148+timOffset); key->setTranslate(Vector3(245.522,66.4289,417.204)); key->setRotation(Quaternion(0.969895,-0.00327889,0.243174,0.000821591)); key = track->createKeyFrame(animDelay*180+timOffset); key->setTranslate(Vector3(74.5456,161.762,229.612)); key->setRotation(Quaternion(0.919624,-0.37099,0.119602,0.048247)); key = track->createKeyFrame(animDelay*200+timOffset); key->setTranslate(Vector3(99.7407,953.843,310.485)); key->setRotation(Quaternion(0.815697,-0.560923,0.116455,0.0800779)); key = track->createKeyFrame(animDelay*213.003+timOffset); key->setTranslate(Vector3(740.743,158.305,165.596)); key->setRotation(Quaternion(0.461686,-0.0305725,0.884463,0.0582964)); key = track->createKeyFrame(animDelay*231.324+timOffset); key->setTranslate(Vector3(1889.01,281.073,89.9274)); key->setRotation(Quaternion(0.723468,0.00313488,0.690157,-0.00313797)); key = track->createKeyFrame(animDelay*249.487+timOffset); key->setTranslate(Vector3(2872.93,118.85,-472.164)); key->setRotation(Quaternion(0.657661,0.0386955,0.750839,-0.0443189)); key = track->createKeyFrame(animDelay*264.965+timOffset); key->setTranslate(Vector3(2613.98,169.808,-1362.87)); key->setRotation(Quaternion(0.515329,0.0279485,0.855113,-0.0465596)); key = track->createKeyFrame(animDelay*278.284+timOffset); key->setTranslate(Vector3(2000.71,209.627,-1909.93)); key->setRotation(Quaternion(0.39415,0.0271869,0.916301,-0.0634344)); key = track->createKeyFrame(animDelay*292.262+timOffset); key->setTranslate(Vector3(844.269,282.555,-1766.07)); key->setRotation(Quaternion(0.227154,0.00503583,0.973453,-0.0220159)); key = track->createKeyFrame(animDelay*308.494+timOffset); key->setTranslate(Vector3(34.4144,291.87,-1023.65)); key->setRotation(Quaternion(0.0827656,-0.00208207,0.996139,0.023802)); key = track->createKeyFrame(animDelay*319.382+timOffset); key->setTranslate(Vector3(-244.852,392.682,-357.77)); key->setRotation(Quaternion(0.345054,-0.0821347,0.909552,0.216516));
}
}; mAnimState = mSceneMgr->createAnimationState("CameraTrack"); mAnimState->setEnabled(true); mBlackOverlay = OverlayManager::getSingleton().getByName("BLACK"); mBlackOverlay->show();
代码很多,把和AUDIERE有关的代码列如下:
#include "audiere.h"
audiere::AudioDevicePtr device(audiere::OpenDevice());
audiere::OutputStreamPtr stream(audiere::OpenSound(device, "music.wav", false));
stream->setRepeat(true);
stream->setVolume(0.5f); // 50% volume
stream->play();
是不是比FMOD还要简单啊,好好享受这个DEMO带给你震撼效果吧。
2、物理
物理引擎有很多,业界霸主HAVOK、新生领袖PHYSX、开源名角ODE、另外还有各方面都稳定的NEWTON、快如子弹的BULLET、还有TOKMAKA、国产物理引擎SPE,真可谓群英会萃。但是已经和OGRE绑定完成并广泛使用是以下四款:OGRENEWT(OGRE和NEWTON的绑定)、OGREODE(OGRE和ODE的绑定)、NXOGRE(OGRE和PHYSX的绑定)、OGREBULLET(OGRE和BULLET的绑定)。下面主要介绍OGRENEWT的简单使用以及一些各个物理引擎中都有的物理概念。
2.1常用的物理概念
WORLD 物理世界
RIGID BODY 刚体 固体 实体(有质量 ,形状等物理属性)
SOFTBODY 软体
COLLISION 碰状
JOINT 接点
Velocity/Force 力
TORQUE 转力矩
Mass 质量
Contact 接触
Collision detection 碰撞检测
AABB 轴对齐包围盒
MATERIAL 材质(和摩擦力有关)
2.2 OGRENEWT
下面介绍OGRENEWT的使用:
编译:要将目录做成以下的样子
< some_dir >/OGRE/ogrenew <- ogre 安装目录(不是OGRESDK啊) <some_dir>/OGRE/ogreaddons/OgreNewt/ <- OgreNewt 安装目录
<some_dir>/NewtonSDK <- Newton SDK 安装目录
<some_dir>/tinyxml <- Tinyxml库 (只在 demo08用到, OgreNewt自身不需要用)
NEWTON的下载网站
OGRENEWT可以到OGRE官网的ADDONS里面下载,或者用CVS下载。
网上已经有篇网友翻译的OGRENEWT的初级文章,可以到里面找找,这里介绍碰撞回调,因为这很有用,比如你可以让物体和地面碰撞的时候发出碰撞声,当然这还要利用前面介绍声音引擎来完成,关键是要知道在什么地方播放。
下面是Demo03_CollisionCallbacks的代码,很多,但是慢慢看并不会难理解。
Demo2.cpp文件
/*
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "OgreNewtonApplication.h"
//和OGRE的源文件框架没太大区别,只是头文件名字换成了OgreNewtonApplication.h
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) {
// Create application object
OgreNewtonApplication app;
try {
app.go();
} catch( Ogre::Exception& e ) {
return 0;
} printf( "An Error HAS OCCURED: %s", e.getFullDescription() ); } by walaber//作者名字啦,大牛,哈哈。 Demo03_CollisionCallbacks
下面是OgreNewtonApplication.h文件
#pragma once
#include <ExampleApplication.h>
#include <OgreNewt.h>
#include "conveyorBelt.h"//传送带的头文件
#include "conveyorMatCallback.h"//材质回调的头文件
class OgreNewtonApplication :
{
public:
protected:
private:
}; std::vector<conveyorBelt*> mBelts; Ogre::FrameListener* mNewtonListener; Ogre::SceneNode* msnCam;//摄影机节点 OgreNewt::World* m_World;//牛顿世界 ,物理世界 const OgreNewt::MaterialID* mMatDefault;//材质ID const OgreNewt::MaterialID* mMatConveyor;//传送带ID OgreNewt::MaterialPair* mMatPairDefaultConveyor;//传送带 conveyorMatCallback* mConveyorCallback;//回调 void createMaterials(); void createFrameListener(); void createScene(); OgreNewtonApplication(void); ~OgreNewtonApplication(void); enum BodType { BT_BASIC, BT_CONVEYOR };//枚举两种BODY类型,一是基本的,一是传送带 public ExampleApplication
下面是OgreNewtonApplication.cpp文件
/*
Demo03_CollisionCallbacks - the material system in Newton is extremely powerful. by materials to bodies, you can define all kinds of specific behavior when objects collide. assigning OgreNewt library - connecting Ogre and Newton! you can use
material callbacks to create hot spots, or make sound effects, or spawn particles, etc. this uses a conveyor belt as an example. look at the conveyorMatCallback to see how it's example
implemented.
*/
//OGRENEWT提供了很强大材质支持,可以用来处理摩擦的火花,声音等
#include ".OgreNewtonApplication.h"
#include ".OgreNewtonFrameListener.h"
#include <OgreNewt.h>
OgreNewtonApplication::OgreNewtonApplication(void)
{
}
OgreNewtonApplication::~OgreNewtonApplication(void)
{
}
void OgreNewtonApplication::createScene()
{
createMaterials(); // shadows on. mSceneMgr->setShadowTechnique( Ogre::SHADOWTYPE_STENCIL_MODULATIVE ); // sky box. mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox"); // de-initialize the debugger. OgreNewt::Debugger::getSingleton().deInit(); delete m_World; std::vector<conveyorBelt*>::iterator it; for (it=mBelts.begin(); it!=mBelts.end(); it++) { } conveyorBelt* belt = (*it); delete belt; m_World = new OgreNewt::World();
conveyorBelt* belt = new conveyorBelt(); belt->init( Ogre::String("ConveyorBelt1"), mSceneMgr, m_World, Ogre::Vector3(15,0.3,3), Ogre::Quaternion(Ogre::Quaternion::IDENTITY), mMatConveyor, BT_CONVEYOR ); Ogre::Vector3(1,0,0), 2.0, Ogre::Vector3(0,2,0), mBelts.push_back( belt );//将带子PUSH到队列中 belt = new conveyorBelt();//另一个带子 belt->init( Ogre::String("ConveyorBelt2"), mSceneMgr, m_World, Ogre::Vector3(23,0.3,4), Ogre::Vector3(-1,0,0), 6.0, Ogre::Vector3(3,-1,0),
型
// position camera msnCam = mSceneMgr->getRootSceneNode()->createChildSceneNode(); msnCam->attachObject( mCamera ); mCamera->setPosition(0.0, 0.0, 0.0); msnCam->setPosition( 0.0, 2.0, 22.0); //Ogre::Vector3 siz(100.0, 10.0, 100.0); OgreNewt::Collision* col = new OgreNewt::CollisionPrimitives::TreeCollision( m_World, OgreNewt::Body* bod = new OgreNewt::Body( m_World, col );//根据形状来创建body //floornode->setScale( siz ); bod->attachToNode( floornode );//绑定到节点,物理和图形结合处 bod->setPositionOrientation( Ogre::Vector3(0.0,-10.0,0.0), Ogre::Quaternion::IDENTITY ); //设置位置和方向 floor->setCastShadows( false ); // floor object! Entity* floor; SceneNode* floornode; floor = mSceneMgr->createEntity("Floor", "simple_terrain.mesh" ); floornode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "FloorNode" ); floornode->attachObject( floor ); floor->setMaterialName( "Simple/BeachStones" ); Ogre::Quaternion(Ogre::Quaternion::IDENTITY), mMatConveyor, BT_CONVEYOR ); mBelts.push_back( belt ); //init的参数分别代表 带子名、场景管理器、物理世界、大小、方向参数、位置、方向、材质ID、带子类floornode, true );//树型Collision主要用与静态的场景物体
//绑定摄影机
//make a light Ogre::Light* light;
}
light->setType( Ogre::Light::LT_POINT ); light->setPosition( Ogre::Vector3(0.0, 100.0, 100.0) );
void OgreNewtonApplication::createMaterials()
{
}
void OgreNewtonApplication::createFrameListener()
{
mFrameListener = new OgreNewtonFrameListener( mWindow, mCamera, mSceneMgr, m_World, msnCam );
mRoot->addFrameListener(mFrameListener); mMatPairDefaultConveyor = new OgreNewt::MaterialPair( m_World, mMatDefault, mMatConveyor ); mConveyorCallback = new conveyorMatCallback( BT_CONVEYOR );//new一个回调函数 mMatPairDefaultConveyor->setContactCallback( mConveyorCallback );//设置回调 mMatPairDefaultConveyor->setDefaultFriction( 1.5, 1.4 );//摩擦力 mMatDefault = m_World->getDefaultMaterialID(); mMatConveyor = new OgreNewt::MaterialID( m_World );//新建材质ID
//自己在下面实现的framelistener
} mNewtonListener = new OgreNewt::BasicFrameListener( mWindow, mSceneMgr, m_World, 60 ); mRoot->addFrameListener(mNewtonListener);//基本framelistener,OGRENEWT已经实现的。
下面是conveyorBelt.h文件
#pragma once
#include <OgreNewt.h>
// conveyorBelt - simple class for creating conveyor belt objects!
class conveyorBelt
{
public:
void init( Ogre::String& name, Ogre::SceneManager* mgr, OgreNewt::World* world, conveyorBelt(void); ~conveyorBelt(void);
Ogre::Vector3& size, Ogre::Vector3& dir, Ogre::Real speed,
private:
}; Ogre::SceneManager* mSceneMgr; Ogre::SceneNode* mNode; OgreNewt::Body* mBody; Ogre::Vector3 mDir; Ogre::Real mSpeed; void killme(); Ogre::Vector3 getGlobalDir(); Ogre::Real getSpeed() { return mSpeed; } Ogre::Vector3& pos, Ogre::Quaternion& orient, const OgreNewt::MaterialID* conveyorMat, int conveyorType );
下面是conveyorBelt.cpp文件
#include ".conveyorbelt.h"
conveyorBelt::conveyorBelt(void)
{
}
conveyorBelt::~conveyorBelt(void)
{
}
void conveyorBelt::init( Ogre::String& name, Ogre::SceneManager* mgr, OgreNewt::World* world, Ogre::Vector3& size, Ogre::Vector3& dir, Ogre::Real speed,
{
// build a conveyor belt object. first create the basic visual object. mSceneMgr = mgr; mDir = dir; mSpeed = speed; Ogre::Vector3& pos, Ogre::Quaternion& orient, const OgreNewt::MaterialID* conveyorMat, int conveyorType ) if (mBody) killme();//销毁BODY
}
Ogre::Vector3 conveyorBelt::getGlobalDir()
{
}
void conveyorBelt::killme()
{
//now destroy the scene node and entity. while (mNode->numAttachedObjects() > 0) { } Ogre::Entity* ent = (Ogre::Entity*)mNode->getAttachedObject(0); mSceneMgr->destroyEntity( ent ); // first destroy the rigid body. delete mBody; mBody = NULL; Ogre::Vector3 ret = mNode->getWorldOrientation() * mDir; return ret; mBody->setPositionOrientation( pos, orient );//位置方向 mNode->setPosition( pos ); mNode->setOrientation( orient ); mBody->setUserData( this );//这是关键奥,说明该body将来会在回调函数中被调用 // create the collision object for the conveyor belt. OgreNewt::Collision* col = new OgreNewt::CollisionPrimitives::Box( world, size ); mBody = new OgreNewt::Body( world, col, conveyorType ); delete col; mBody->setMassMatrix( 0.0, Ogre::Vector3(0,0,0) );//设置质量 mBody->attachToNode( mNode ); mBody->setMaterialGroupID( conveyorMat );//设置材质组ID Ogre::Entity* ent = mSceneMgr->createEntity(name, "box.mesh"); ent->setMaterialName(name); ent->setNormaliseNormals(true); mNode->attachObject(ent); mNode->setScale( size ); mNode = mgr->getRootSceneNode()->createChildSceneNode(); //传送带的Collision是BOX
}
下面是conveyorMatCallback.h文件
#pragma once
/*
creating a collision callback is simple. make a class that inherits from the
OgreNewt::ContactCallback class.
int userBegin() int userProcess() //碰撞前,可以接受碰撞(返回1),也忽略碰撞(返回0) this class has 3 virtual functions that the user can implement: Demo03_CollisionCallback mNode = NULL; mSceneMgr->getRootSceneNode()->removeAndDestroyChild( mNode->getName() );
//碰撞时,可以用来记录碰撞中一些数据,比如碰撞的位置,力等或者对碰撞的双方做特殊处理,比如这//里带子给物体施加了力
void userEnd() these 3 functions work together to create a collision callback. basically it works like //碰撞结束时,做特殊的处理,比如播放声音,做碰撞的火花等。 this: when two rigid bodies are about to collide
(their bounding boxes have overlapped), the "userBegin()" function gets called. at this and decide if you want to reject or continue with the collision. return "1" to accept point you can check which bodies are involved, collision, or "0" to ignore it.
after that, the "userProcess" function gets called for each contact that happens between physics, there may be more than one contact. you can use this function to perform many things, the 2 bodies. depending on the timestep for the like recording positions and velocities, or
finally, after all collisions have been solved, the "userEnd" function gets called. this record all of the collisions and positions in the Process function, and then in the end can be a "cleanup function". for example you can applying special effects (like in this example). function you might play a sound effect, etc.
*/
#include <OgreNewt.h>
class conveyorMatCallback :
{
public:
private:
};
下面是conveyorMatCallback.cpp文件
#include ".conveyormatcallback.h"
#include ".conveyorBelt.h"
conveyorMatCallback::conveyorMatCallback( int conveyorID ) : OgreNewt::ContactCallback() {
}
conveyorMatCallback::~conveyorMatCallback(void)
{
}
int conveyorMatCallback::userProcess()//碰撞开始喽
{
if (m_body1->getType() == mConveyorID) { if (m_body0->getType() == mConveyorID) { } belt = (conveyorBelt*)m_body0->getUserData(); object = m_body1; // 找到哪个是带子,哪个是一般的盒子 conveyorBelt* belt; OgreNewt::Body* object; mConveyorID = conveyorID; int mConveyorID; // in this example we only need the Process() function. int userProcess(); conveyorMatCallback( int conveyorID ); ~conveyorMatCallback(void); public OgreNewt::ContactCallback
} belt = (conveyorBelt*)m_body1->getUserData(); object = m_body0; if (!belt) { return 0; } // okay, found the belt... let's adjust the collision based on this. Ogre::Vector3 thedir = belt->getGlobalDir(); rotateTangentDirections( thedir );//旋转 Ogre::Vector3 result_accel = (thedir * belt->getSpeed()) - object->getVelocity(); setContactTangentAcceleration( result_accel.length(), 0 );//加速 return 1;
}
3.OGRE周边的插件
OGRE周边有众多的插件库,比如: PAGEGEMOTRY、ETM、HYDRAX、 PLSM2……这里简要介绍PAGEGEMOTRY、ETM、HYDRAX的简单使用。
分页插件PAGEGEMOTRY
PAGEGEMOTRY是OGRE的一个扩展库,为需要渲染大量MESH的程序提供了很高效的方法,尤其是那些拥有成千上万的树木、灌木丛、草、石头的雨林和户外场景。它的最大优点就是大大的提高了拥有大型场景程序的速度,有时会有上百倍的提高。它的另一个优点就是分页,那么场景中的Entity除非立即需要加载它才会去这么做,这样就可以给玩家提供更大的世界范围。
PAGEGEMOTRY的DOC中有几篇用户手册,可以去参考学
习,这里直接分析它的DEMO代码。
//===============================================================================================================
//Example 1 - TreeLoader3D
//---------------------------------------------------------------------------------------------------------------
// This example demonstrates the basic use of PagedGeometry to display trees with TreeLoader3D. // Instructions: Move around with the arrow/WASD keys, hold SHIFT to move faster, and hold SPACE to fly.
// HINT: Search this source for "[NOTE]" to find important code and comments related to PagedGeometry.
//===============================================================================================================
#define AppTitle "PagedGeometry Example 1 - TreeLoader3D"
//Include windows/Ogre/OIS headers
#include <Ogre.h>
#include <OIS/OIS.h>
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include <windows.h>
#endif
using namespace Ogre;
//Include PagedGeometry headers that will be needed
#include "PagedGeometry.h"
#include "BatchPage.h"
#include "ImpostorPage.h"
#include "TreeLoader3D.h"
//上面的头文件是PagedGeometry的内部文件,下面是HeightFunction.h并不是PagedGeometry的一部分,只是提供在地形上获得某点地面高度功能,在使用自己的物理引擎后就可以使用物理引擎提供的相似功能的函数。
//Include "HeightFunction.h", a header that provides some useful functions for quickly and easily //getting the height of the terrain at a given point.
#include "HeightFunction.h"
//[NOTE] Remember that this "HeightFunction.h" file is not related to the PagedGeometry library itself
//in any way. It's simply a utility that's included with all these examples to make getting the terrain
//height easy. You can use it in your games/applications if you want, although if you're using a
//collision/physics library with a faster alternate, you may use that instead.
//Demo world class
//[NOTE] The main PagedGeometry-related sections of this class are load() and
//render. These functions setup and use PagedGeometry in the scene.
class World //定义World类
{
public:
private:
void render(); //Renders a single frame, updating PagedGeometry and Ogre void load(); //Loads the 3D scene //加载场景 void unload(); void run(); //Unloads the 3D scene cleanly//删除场景 //Runs the simulation//运行计算 World(); ~World(); //渲染一桢
bool running; //A flag which, when set to false, will terminate a simulation started with void processInput(); //Accepts keyboard and mouse input, allowing you to move around in //the world //run() 一个是否运行的标记
};
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow) //Pointers to PagedGeometry class instances: PagedGeometry *trees;// PagedGeometry类实例的指针,PagedGeometry的开始 //Variables used to keep track of the camera's rotation/etc. Radian camPitch, camYaw;//摄影机旋转的两个弧度角 //OIS input objects OIS::InputManager *inputManager;//输入管理器 OIS::Keyboard *keyboard;//键盘 OIS::Mouse *mouse;//鼠标 //Various pointers to Ogre objects are stored here: Root *root;//OGRE最早运行的类 RenderWindow *window;//渲染窗口 Viewport *viewport;//视口 SceneManager *sceneMgr;//场景管理器 Camera *camera;
#else
int main(int argc, char *argv[])
#endif
{
//Load appropriate plugins //[NOTE] PagedGeometry needs the CgProgramManager plugin to compile shaders //Initialize Ogre Root *root = new Ogre::Root("");//初始化OGRE //By default, Visual Studio sets the working directory to the project folder. This //sets the working directory to the exe's folder, as it should be. #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #ifdef _DEBUG SetCurrentDirectory("..\bin\debug");//设置exe的目录 #else SetCurrentDirectory("..\bin\release"); #endif #endif //根据不同的编译方式加载不同插件
//If the user clicks OK, continue //Show Ogre's default config dialog to let the user setup resolution, etc. bool result = root->showConfigDialog();//显示配置对话框 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #ifdef _DEBUG root->loadPlugin("Plugin_CgProgramManager_d"); root->loadPlugin("Plugin_OctreeSceneManager_d"); root->loadPlugin("RenderSystem_Direct3D9_d"); root->loadPlugin("RenderSystem_GL_d"); #else root->loadPlugin("Plugin_CgProgramManager"); root->loadPlugin("Plugin_OctreeSceneManager"); root->loadPlugin("RenderSystem_Direct3D9"); root->loadPlugin("RenderSystem_GL"); #endif #else #define STRINGIFY(x) #x #define EXPAND(x) STRINGIFY(x) root->loadPlugin(EXPAND(OGRE_PLUGINDIR) "Plugin_CgProgramManager"); root->loadPlugin(EXPAND(OGRE_PLUGINDIR) "Plugin_OctreeSceneManager"); root->loadPlugin(EXPAND(OGRE_PLUGINDIR) "RenderSystem_GL"); #endif
}
} World myWorld; myWorld.load(); myWorld.run(); //加载 //显示,运行 //Shut down Ogre delete root; return 0;
World::World()
{
//摄影机和视口 camera = sceneMgr->createCamera("MainCamera"); viewport = window->addViewport(camera); viewport->setBackgroundColour(ColourValue(0.47f, 0.67f, 0.96f)); //Blue sky background //Setup Ogre::Root and the scene manager root = Root::getSingletonPtr(); window = root->initialise(true, AppTitle); sceneMgr = root->createSceneManager(ST_EXTERIOR_CLOSE);//场景管理器的模式为//ST_EXTERIOR_CLOSE color
camera->setAspectRatio(Real(viewport->getActualWidth()) /
Real(viewport->getActualHeight()));
//Load media (trees, grass, etc.)//加载资源 ResourceGroupManager::getSingleton().addResourceLocation("../../media/trees", ResourceGroupManager::getSingleton().addResourceLocation("../../media/terrains", //Set up lighting Light *light = sceneMgr->createLight("Sun"); light->setType(Light::LT_DIRECTIONAL); light->setDirection(Vector3(0.0f, -0.5f, 1.0f)); sceneMgr->setAmbientLight(ColourValue(1, 1, 1)); camera->setNearClipDistance(1.0f); camera->setFarClipDistance(2000.0f); "FileSystem"); "FileSystem");
ResourceGroupManager::getSingleton().addResourceLocation("../../media/grass", ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); "FileSystem");
}
World::~World()
{
}
//[NOTE] In addition to some Ogre setup, this function configures PagedGeometry in the scene. void World::load()
{
//-------------------------------------- LOAD TERRAIN unload(); //Shut down OIS inputManager->destroyInputObject(keyboard); inputManager->destroyInputObject(mouse); OIS::InputManager::destroyInputSystem(inputManager); //Reset camera orientation//设置摄影机方向 camPitch = 0; camYaw = 0; keyboard = (Keyboard*)inputManager->createInputObject(OISKeyboard, false); mouse = (Mouse*)inputManager->createInputObject(OISMouse, false); //Initialize OIS//初始化OIS using namespace OIS; size_t windowHnd; window->getCustomAttribute("WINDOW", &windowHnd); inputManager = InputManager::createInputSystem(windowHnd);
--------------------------------------
//-------------------------------------- LOAD TREES //Start off with the camera at the center of the terrain camera->setPosition(700, 100, 700); //Load the terrain//世界几何体,一般是地面 sceneMgr->setWorldGeometry("terrain.cfg"); //Setup the fog up to 500 units away//雾 sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700);
--------------------------------------// PagedGeometry使用重点
//Create and configure a new PagedGeometry instance
//创建和配置PagedGeometry实例
trees->setCamera(camera); trees->setInfinite(); //摄影机和LOD有关,要让PagedGeometry知道摄影机 //Use infinite paging mode trees->setPageSize(80); //Set the size of each page of geometry//页面大小 trees->addDetailLevel<BatchPage>(150, 50);//Use batches up to 150 units away, and fade for 30 more units第一个参数是batches页的范围,第二个为衰减程度
//Setup the height function (so the Y values of trees can be calculated when they are placed //创建TreeLoader3D TreeLoader3D *treeLoader = new TreeLoader3D(trees, TBounds(0, 0, 1500, 1500)); trees->setPageLoader(treeLoader); //树的实体 Entity *myEntity = sceneMgr->createEntity("Tree", "tree2.mesh"); //指定"treeLoader" trees->addDetailLevel<ImpostorPage>(500, 50); //Use impostors up to 400 units, and for for 50 more units//第一个为Impostor页的范围,第二为衰减程度 //on the terrain)高度函数的初始化
}
void World::unload()
{
//删除new的资源,防止内存泄露
//Delete the PagedGeometry instance delete trees; //Delete the TreeLoader3D instance delete trees->getPageLoader(); } treeLoader->addTree(myEntity, position, yaw, scale);//种树 scale = Math::RangeRandom(0.5f, 0.6f); position.x = Math::RangeRandom(0, 1500); position.z = Math::RangeRandom(0, 1500); position.y = HeightFunction::getTerrainHeight(position.x, position.z); //随机20000份,但是速度还是很快的。 Vector3 position; Radian yaw; Real scale; for (int i = 0; i < 20000; i++){ yaw = Degree(Math::RangeRandom(0, 360)); HeightFunction::initialize(sceneMgr);
}
void World::run() {
}
void World::render() {
}
void World::processInput() {
//计算距上一frame的时间 Real timeScale = (currentTime - lastTime) * 0.001f; if (timeScale < 0.001f) timeScale = 0.001f; using namespace OIS; static Ogre::Timer timer; static unsigned long lastTime = 0; unsigned long currentTime = timer.getMilliseconds(); //OGRE本身的更新 root->renderOneFrame(); //每frame要更新 trees->update(); } //Exit immediately if the window is closed if (window->isClosed()) break; //Update frame processInput(); render(); //Render loop running = true; while(running) { //Handle windows events WindowEventUtilities::messagePump(); //Also delete the tree entity sceneMgr->destroyEntity("Tree");
//Get the current state of the keyboard and mouse keyboard->capture(); mouse->capture(); //Always exit if ESC is pressed if (keyboard->isKeyDown(KC_ESCAPE)) running = false; //重新加载 static bool reloadedLast = false; if (keyboard->isKeyDown(KC_R) && !reloadedLast){ } else { } reloadedLast = false; unload(); load(); reloadedLast = true; //捕获鼠标的移动 const OIS::MouseState &ms = mouse->getMouseState(); //更新摄影机的旋转 camYaw += Radian(-ms.X.rel / 200.0f); camPitch += Radian(-ms.Y.rel / 200.0f); camera->setOrientation(Quaternion::IDENTITY); camera->pitch(camPitch); camera->yaw(camYaw); //摄影机移动 Ogre::Vector3 trans(0, 0, 0); if (keyboard->isKeyDown(KC_UP) || keyboard->isKeyDown(KC_W)) trans.z = -1; if (keyboard->isKeyDown(KC_DOWN) || keyboard->isKeyDown(KC_S)) trans.z = 1; trans.x = 1; if (keyboard->isKeyDown(KC_RIGHT) || keyboard->isKeyDown(KC_D)) if (keyboard->isKeyDown(KC_LEFT) || keyboard->isKeyDown(KC_A)) trans.x = -1; if (keyboard->isKeyDown(KC_PGUP) || keyboard->isKeyDown(KC_E)) trans.y = 1; if (keyboard->isKeyDown(KC_PGDOWN) || keyboard->isKeyDown(KC_Q))
}
//Shift = speed boost if (keyboard->isKeyDown(KC_LSHIFT) || keyboard->isKeyDown(KC_RSHIFT)) trans *= 2; trans *= 100; camera->moveRelative(trans * timeScale); //使摄影机始终在地形之上 Ogre::Vector3 camPos = camera->getPosition(); float terrY = HeightFunction::getTerrainHeight(camPos.x, camPos.z); if (camPos.y < terrY + 2 || !keyboard->isKeyDown(KC_SPACE)){ } camPos.y = terrY + 2; camera->setPosition(camPos); //Space = fly
//下面是个高度函数,和pagegemotry无关,也可以自己实现,这里是基于射线查询做的。
#include "Ogre.h"
using namespace Ogre;
namespace HeightFunction
{
bool initialized = false; RaySceneQuery* raySceneQuery; }; float resultDistance; class MyRaySceneQueryListener: public RaySceneQueryListener { public: inline bool queryResult(SceneQuery::WorldFragment *fragment, Real distance) { } inline bool queryResult(MovableObject *obj, Real distance) { } resultDistance = distance; return false; resultDistance = distance; return false;
MyRaySceneQueryListener *raySceneQueryListener; // getTerrainHeight()之前初始化 void initialize(SceneManager *sceneMgr){ raySceneQuery->setWorldFragmentType(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION); } } raySceneQueryListener = new MyRaySceneQueryListener; if (!initialized){ initialized = true; updateRay.setOrigin(Vector3::ZERO); updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y); raySceneQuery = sceneMgr->createRayQuery(updateRay); raySceneQuery->setQueryTypeMask(Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK); //Gets the height of the terrain at the specified x/z coordinate //The userData parameter isn't used in this implementation of a height function, since //there's no need for extra data other than the x/z coordinates. inline float getTerrainHeight(const float x, const float z, void *userData = NULL){ updateRay.setOrigin(Vector3(x, 0.0f, z)); updateRay.setDirection(Vector3::UNIT_Y); raySceneQuery->setRay(updateRay); raySceneQuery->execute(raySceneQueryListener); }
} return raySceneQueryListener->resultDistance;
地形插件ETSM
OGRE本身的地形可以通过terrain.cfg这个配置文件来指定,但是并不是很直观,而ETSM则提供更为方便的方法来做地形,因为它并不是个编辑器,而只是个插件,所以把它做到自己的编辑器里面来实现自己特殊的地形,下面来分析DEMO的代码。
#include <OgreNoMemoryMacros.h>
#include <CEGUI/CEGUISystem.h>
#include <CEGUI/CEGUISchemeManager.h>
#include <OgreCEGUIRenderer.h>
#include "ExampleApplication.h"
//ETSM的几个头文件
#include "ETTerrainManager.h"
#include "ETTerrainInfo.h"
#include "ETBrush.h"
#include "ETSplattingManager.h"
using namespace std;
using Ogre::uint;
class DemoListener : public ExampleFrameListener, public OIS::MouseListener, public OIS::KeyListener
{
public:
DemoListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager, CEGUI::Renderer *renderer, ET::TerrainManager* terrainMgr, ET::SplattingManager* splatMgr)
: ExampleFrameListener(win, cam, true, true), mGUIRenderer(renderer),
mTerrainMgr(terrainMgr), mTerrainInfo(&terrainMgr->getTerrainInfo()), mSplatMgr(splatMgr) {
// Setup default variables
mPointer = NULL;
mLMouseDown = false;
mRMouseDown = false;
mMMouseDown = false;
mSceneMgr = sceneManager;
// Reduce move speed
mMoveSpeed = 320;
mRotateSpeed *= 0.008;
// Register this so that we get events.这里使用输入的回调,因为其实都是虚函数,就是自己实现的具体代码
mMouse->setEventCallback( this );
mKeyboard->setEventCallback(this);
// Create RaySceneQuery射线查询
mRaySceneQuery = mSceneMgr->createRayQuery( Ray() );
// 鼠标在3D场景中对应点,用模型来显示
Entity* pointer = mSceneMgr->createEntity("Pointer", "ogrehead.mesh");
mPointer = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mPointer->attachObject(pointer);
// 初始化CEGUI鼠标
CEGUI::MouseCursor::getSingleton().setPosition(CEGUI::Point(CEGUI::Vector2(0,0)));
createEditBrush();
mDeform = true;
mChosenTexture = 0;
mDirection = Vector3::ZERO;
mContinue = true;
mCamNode = mCamera->getParentSceneNode();
}
~DemoListener( )
{
delete mRaySceneQuery;
}
//画刷,更换gcanyon_height_4k2k.png为自己的图片,来实现特殊的画刷,
这里是凸型的
也可以换为不规则的
void createEditBrush()
{
// load the edit brush for terrain editing
Image image;
image.load("gcanyon_height_4k2k.png", "ET");
image.resize(16, 16);
mEditBrush = ET::loadBrushFromImage(image);
}
bool frameStarted(const FrameEvent &evt)
{
if (!ExampleFrameListener::frameStarted( evt ))
return false; ,
// 摄影机的移动
mCamNode->translate(mCamera->getOrientation()*mDirection*mMoveSpeed*evt.timeSinceLastFrame);
// Ensure we stay above terrain (somehow buggy still, doesn't work reliably)
Vector3 camPos = mCamNode->getPosition( );
// 获得摄影机高度
float terrainHeight = mTerrainInfo->getHeightAt(camPos.x, camPos.z);
if ((terrainHeight + 30.0f) > camPos.y)
mCamNode->setPosition(camPos.x, terrainHeight+30.0f, camPos.z);
//下面是具体实现地形起伏和贴图的关键
if (mLMouseDown || mRMouseDown)
{
// deform or paint terrain on mouse down
// left button raises, right button lowers
if (mDeform)//地形起伏
{
// choose a brush intensity, this determines
// how extreme our brush works on the terrain
float brushIntensity =
evt.timeSinceLastFrame * 0.4 * (mLMouseDown? 1 : -1);//左键凸右键凹
// translate our cursor position to vertex indexes
Vector3 deformPos = mPointer->getPosition();
int x = mTerrainInfo->posToVertexX(deformPos.x);
int z = mTerrainInfo->posToVertexZ(deformPos.z);
// now tell the ETM to deform the terrain真正起伏的函数
mTerrainMgr->deform(x, z, mEditBrush, brushIntensity);
}
else
{//贴图
// need to set our brush intensity larger for painting.
// for painting, all texture channels are only 1 byte
// large, so with a small intensity you won't get any
// effect at all.
float brushIntensity = evt.timeSinceLastFrame * 5.0 * (mLMouseDown? 1 : -1); // retrieve edit points
Vector3 paintPos = mPointer->getPosition();
int x = mTerrainInfo->posToVertexX(paintPos.x);
int z = mTerrainInfo->posToVertexZ(paintPos.z);
// now use the splatting manager to update the coverage maps
mSplatMgr->paint(mChosenTexture, x, z, mEditBrush, brushIntensity);
}
}
return mContinue;
}
virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) {
// Left mouse button down
if ( id == OIS::MB_Left )
{
mLMouseDown = true;
}
// Middle mouse button down
else if ( id == OIS::MB_Middle )
{//按滑轮旋转
CEGUI::MouseCursor::getSingleton().hide( );
mMMouseDown = true;
}
else if (id == OIS::MB_Right)
{
mRMouseDown = true;
}
return true;
}
virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) {
// Left mouse button up
if ( id == OIS::MB_Left )
{
mLMouseDown = false;
// after completed deformation steps, recalculate the lightmap
if (mDeform)

updateLightmap();//更新光图
}
// Middle mouse button up
else if ( id == OIS::MB_Middle )
{
CEGUI::MouseCursor::getSingleton().show( );
mMMouseDown = false;
}
else if (id == OIS::MB_Right)
{
mRMouseDown = false;
// after completed deformation steps, recalculate the lightmap
if (mDeform)
updateLightmap();
}
return true;
}
virtual bool mouseMoved( const OIS::MouseEvent &arg )
{
// Update CEGUI with the mouse motion
CEGUI::System::getSingleton().injectMouseMove( arg.state.X.rel, arg.state.Y.rel );
// whenever the mouse is moved, we update the position on the
// terrain to which the mouse is currently pointing更新射射线
Ray mouseRay = mCamera->getCameraToViewportRay(arg.state.X.abs/float(arg.state.width), arg.state.Y.abs/float(arg.state.height));
// since ETM is no longer a scene manager, we don't use a ray scene query,
// but instead query the terrain info directly
std::pair<bool, Vector3> result = mTerrainInfo->rayIntersects(mouseRay);
if (result.first)
{
// update pointer's position
mPointer->setPosition(result.second);
}
// If we are dragging the middle mouse button.
if ( mMMouseDown )
{
mCamera->yaw( Degree(-arg.state.X.rel * mRotateSpeed) );
mCamera->pitch( Degree(-arg.state.Y.rel * mRotateSpeed) );
}
return true;
}
virtual bool keyPressed(const OIS::KeyEvent& arg)
{
// we'll use the keys 1, 2, 3, 4 and E to switch between
// edit modes and select a paint texture
// WSAD is used for movement
// O will save the changes to disk
switch (arg.key)
{//以下更换贴图
case OIS::KC_1:
mDeform = false;
mChosenTexture = 0;
return true;
case OIS::KC_2:
mDeform = false;
mChosenTexture = 1;
return true;
case OIS::KC_3:
mDeform = false;
mChosenTexture = 2;
return true;
case OIS::KC_4:
mDeform = false;
mChosenTexture = 3;
return true;
case OIS::KC_5:
mDeform = false;
mChosenTexture = 4;
return true;
case OIS::KC_6:
mDeform = false;
mChosenTexture = 5;
return true;
case OIS::KC_E:
mDeform = true;
return true;
case OIS::KC_W:
mDirection.z += -1;
return true;
case OIS::KC_S:
mDirection.z += 1;
return true;
case OIS::KC_A:
mDirection.x += -1;
return true;
case OIS::KC_D:
mDirection.x += 1;
return true;
//O保存当前的地形
case OIS::KC_O:
saveTerrain();
return true;
//加载保存的地形,就刚才O保存的
case OIS::KC_P:
loadTerrain();
return true;
case OIS::KC_ESCAPE:
mContinue = false;
return true;
default:
return false;
}
}
virtual bool keyReleased(const OIS::KeyEvent& arg)
{
// not interested in this
switch (arg.key)
{
case OIS::KC_W:
mDirection.z -= -1;
return true;
case OIS::KC_S:
mDirection.z -= 1;
return true;
case OIS::KC_A:
mDirection.x -= -1;
return true;
case OIS::KC_D:
mDirection.x -= 1;
return true;
default:
return false;
}
}
void saveTerrain()
{
// just for demonstration, we'll save anything we can
// start with the terrain
//高度图
Image image;
ET::saveHeightmapToImage(*mTerrainInfo, image);
image.save("../../Media/ET/ETterrain.png");
// splatting图,这里是六张
// now save the splatting maps
for (uint i = 0; i < mSplatMgr->getNumMaps(); ++i)
{
mSplatMgr->saveMapToImage(i, image);
image.save("../../Media/ET/ETcoverage."+StringConverter::toString(i)+".png"); }
/* // now the lightmap
Image lightmap;
ET::createTerrainLightmap(*mTerrainInfo, lightmap, 512, 512, Vector3(1, -1, 1), ColourValue(1,1,1),
ColourValue(0.3, 0.3, 0.3));
lightmap.save("../../Media/ET/ETlightmap.png");
// generate a base texture for this terrain (could be used for older hardware instead of splatting)
// create an ImageList of our splatting textures.
ET::ImageList textures (6);
for (int i = 0; i < 6; ++i)
textures[i].load("splatting"+StringConverter::toString(i)+".png", "ET");
// create the base texture
Image baseTexture;
mSplatMgr->createBaseTexture(baseTexture, 512, 512, textures, 20, 20);
baseTexture.save("../../Media/ET/ETbase.png");
// finally create a minimap using the lightmap and the generated base texture
Image minimap = ET::createMinimap(baseTexture, lightmap);
minimap.save("../../Media/ET/ETminimap.png");
}
void loadTerrain()
{ */
// now we revert the process and load the data back from disk
// recreate terrain...
mTerrainMgr->destroyTerrain();
Image image;
image.load("ETterrain.png", "ET");//就是刚才保存的高度图
ET::TerrainInfo info;
ET::loadHeightmapFromImage(info, image);
info.setExtents(AxisAlignedBox(0, 0, 0, 1500, 300, 1500));
mTerrainMgr->createTerrain(info);
mTerrainInfo = & mTerrainMgr->getTerrainInfo();
// now load the splatting maps
for (uint i = 0; i < mSplatMgr->getNumMaps(); ++i)
{
image.load("ETcoverage."+StringConverter::toString(i)+".png", "ET"); mSplatMgr->loadMapFromImage(i, image);
}
// update the lightmap
updateLightmap();
}
void updateLightmap()
{
Image lightmap;
ET::createTerrainLightmap(*mTerrainInfo, lightmap, 128, 128, Vector3(1, -1, 1), ColourValue(1,1,1),
ColourValue(0.3, 0.3, 0.3));
// get our dynamic texture and update its contents
TexturePtr tex = TextureManager::getSingleton().getByName("ETLightmap"); tex->getBuffer(0, 0)->blitFromMemory(lightmap.getPixelBox(0, 0));
}
protected:
RaySceneQuery *mRaySceneQuery; //射线查询的指针
bool mLMouseDown, mRMouseDown; // 按键的标记
bool mMMouseDown;
SceneManager *mSceneMgr; // 场景管理器
SceneNode *mPointer; // Our "pointer" on the terrain
CEGUI::Renderer *mGUIRenderer; // cegui renderer
ET::Brush mEditBrush; // Brush for terrain editing
// oScene loader library header file
#include "OgreOSMScene.h"//ofusion的一个头文件
//回调
class oSceneCallback : public OSMSceneCallbacks {
public:
};
// 动画的事件句柄
class oSceneLibDemoFrameListener : public ExampleFrameListener
{
protected:
public:
oSceneLibDemoFrameListener(SceneManager* sceneMgr, RenderWindow* win, Camera* cam) : mSceneMgr(sceneMgr), ExampleFrameListener(win, cam)
{
}
bool frameStarted(const FrameEvent& evt)
{
timeDelay -= evt.timeSinceLastFrame;
if (mKeyboard->isKeyDown(OIS::KC_C) && timeDelay <= 0) { static Real timeDelay = 0; static Real currentTime = 0; SceneManager* mSceneMgr; // We override the OnCreate method for cameras (See IXMLSceneCallbacks class) void OnCameraCreate(Ogre::Camera* pCamera, TiXmlElement* pCameraDesc) { Ogre::Root::getSingleton().getAutoCreatedWindow()->getViewport(0)->setCamera(pCamera); } // If a camera of name "FirstCamera" is loaded, it will be set as the default current if(pCamera->getName() == "FirstCamera")
} for(; it != iend; ++it) { } currentTime += evt.timeSinceLastFrame; animation->apply(currentTime); const Ogre::NodeAnimationTrack* track = it->second; track->getAssociatedNode()->resetToInitialState(); while(animationIt.hasMoreElements()) { Animation* animation = animationIt.getNext(); const Animation::NodeTrackList& trackList = animation->_getNodeTrackList(); Animation::NodeTrackList::const_iterator it = trackList.begin(); Animation::NodeTrackList::const_iterator iend = trackList.end(); // 动画必须要自己更新 SceneManager::AnimationIterator animationIt = mSceneMgr->getAnimationIterator(); } timeDelay = 0.5f; } if(currentCam == cam) { } Ogre::Camera* camera = it.hasMoreElements() ? it.getNext() : firstCam; vp->setCamera(camera); while(it.hasMoreElements()) { Ogre::Camera* cam = it.getNext(); if(it.hasMoreElements()) firstCam = it.peekNextValue(); SceneManager::CameraIterator it = mSceneMgr->getCameraIterator(); Viewport* vp = mWindow->getViewport(0); Camera* firstCam; Camera* currentCam = mWindow->getViewport(0)->getCamera();
// 调用默认
return ExampleFrameListener::frameStarted(evt);
}
};
class oSceneLibApplication : public ExampleApplication {
public:
protected:
// Just override the mandatory create scene method oSceneLibApplication() {}
void createScene(void)
{
// 初始化 oScene.initialise("Boat.osm", &oe_Callback); // create and setup the scene in the root node oScene.createScene();//这里createScene其实有个父结点的参数,如果需要对它操作可以自 //创建 oE_Loader Callback,如果要想在场景加载创建时做些什么的话可以使用 oSceneCallback oe_Callback; // 创建场景加载 OSMScene oScene; //下面是加载的具体内容 // Boat.osm就是OFUSION导出的文件 //己创建保留使用,这里采用默认的。
// 默认的摄影机就是第一摄影机 mCamera = camList[0]; // 摄影机列表 OSMScene::CameraList camList = oScene.getCameraList(); if(!camList.empty()) { mSceneMgr = oScene.getSceneManager();
} // (The TSM needs it to initialize the terrain world geometry) else { // Create a default camera in case no cameras were saved in the scene //没有摄影机的话就自己创建个。
}
// Create new frame listener
void createFrameListener(void)
{
mFrameListener= new oSceneLibDemoFrameListener(mSceneMgr, mWindow, mCamera); mRoot->addFrameListener(mFrameListener);
}
};
// The scene manager will be created by the Scene Loader lib void chooseSceneManager(void) {} void createCamera(void) {} void createViewports(void) {} } // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio( Real(vp->getActualWidth()) / Real(vp->getActualHeight())); mCamera = mSceneMgr->createCamera("PlayerCam"); // Position it at 500 in Z direction mCamera->setPosition(Vector3(0,0,500)); // Look back along -Z mCamera->lookAt(Vector3(0,0,-300)); mCamera->setNearClipDistance(5); // If a viewport was not automatically created, (no cameras saved in the scene) // create a default viewport, entire window Viewport* vp = mWindow->addViewport(mCamera);//视口 vp->setBackgroundColour(ColourValue(0,0,0)); //这些都是纯虚函数,是保留有用户自己实现的
液面插件HYDRAX
Hydrax是OGRE的液面插件库,基于fresnel的折射反射,用perlin噪音实现的波涛起伏,大量shader应用做的光照材质,还有泡沫、船的轨迹等功能。
虽然这项工作还开始不久,可能并不是很成熟,但是因为所实现的效果实在非常漂亮,所以还是很令人期待的。而且有HYDRAX的编辑器
也将很快发布出来,更新速度也很快。
下面分析DEMO。
// ---------------------------------------------------------------------------- // Include the main OGRE header files
// Ogre.h just expands to including lots of individual OGRE header files
// ---------------------------------------------------------------------------- #include <Ogre.h>
// ---------------------------------------------------------------------------- // Include the OGRE example framework
// This includes the classes defined to make getting an OGRE application running // a lot easier. It automatically sets up all the main objects and allows you to // just override the bits you want to instead of writing it all from scratch. // ---------------------------------------------------------------------------- #include <ExampleApplication.h>
//hydrax的头文件
#include "Hydrax.h"
#include "Ogre.h"
#include "OIS.h"
Ogre::SceneNode* IslandSceneNode;//小岛的场景结点
Hydrax::Hydrax *mHydrax = 0;//hydrax指针
//四个天空盒
Ogre::String mSkyBoxes[4] = {"Sky/ClubTropicana",
"Sky/Stormy",
"Sky/EarlyMorning",
"Sky/Evening"};
//太阳位置
Ogre::Vector3 mSunPosition[4] = {Ogre::Vector3(100,1000,-9000),
Ogre::Vector3(1000,10000,-90000),
Ogre::Vector3(1000,1000,9000),
Ogre::Vector3(-5000,10000,50)};
//太阳颜色
Ogre::Vector3 mSunColor[4] = {Ogre::Vector3(1, 0.9, 0.6),
Ogre::Vector3(0.75, 0.65, 0.45),
Ogre::Vector3(1,0.6,0.4),
Ogre::Vector3(1,0.4,0.1)};
int mCurrentSkyBox = 0;//当前天空
class ExampleHydraxDemoListener : public ExampleFrameListener
{
public:
SceneManager *mSceneMgr;
Real mKeyBuffer;
ExampleHydraxDemoListener(RenderWindow* win, Camera* cam, SceneManager *sm)
: ExampleFrameListener(win,cam)
, mSceneMgr(sm)
, mKeyBuffer(-1)
{
}
bool frameStarted(const FrameEvent &e)
{
mHydrax->update(e.timeSinceLastFrame);//更新hydrax
mKeyboard->capture();//获得键盘
if (mKeyboard->isKeyDown(OIS::KC_M) && mKeyBuffer < 0)
{
return true;
}
void changeSkyBox()
{
// 改变天空
mSceneMgr->setSkyBox(true, mSkyBoxes[mCurrentSkyBox], 20000, true);
// 同时更新太阳颜色和位置
mHydrax->setSunPosition(mSunPosition[mCurrentSkyBox]);
mHydrax->setSunColor(mSunColor[mCurrentSkyBox]);
// 所谓的太阳只不过是个点光而已
mSceneMgr->getLight("Light0")->setPosition(mSunPosition[mCurrentSkyBox]); } mKeyBuffer -= e.timeSinceLastFrame; mKeyBuffer = 0.5f; if(mCurrentSkyBox > 3)//共四个,超过回到第一个,也可以用% { mCurrentSkyBox = 0; } changeSkyBox(); mCurrentSkyBox++;//M键换天空盒
mSceneMgr->getLight("Light0")->setSpecularColour(mSunColor[mCurrentSkyBox].x,mSunColor[mCurrentSkyBox].y,mSunColor[mCurrentSkyBox].z);
//在LOG记录
LogManager::getSingleton().logMessage("Skybox " + mSkyBoxes[mCurrentSkyBox] + " selected.
("+Ogre::StringConverter::toString(mCurrentSkyBox+1)+"/"+Ogre::StringConverter::toString(4)+")");
}
};
class SampleApp : public ExampleApplication
{
public:
// Basic constructor
SampleApp()
{
}
~SampleApp()
{
}
protected:
// Just override the mandatory create scene method
void createScene(void)
{
// Create the SkyBox
mSceneMgr->setSkyBox(true, mSkyBoxes[mCurrentSkyBox], 10000, true);
// 摄影机的一些参数
mCamera->setFarClipDistance(0);
mCamera->setPosition(0,0,0);
// 创建HYDRAX
mHydrax = new Hydrax::Hydrax(mSceneMgr, mCamera);
// perlin噪音的设置
mHydrax->setPerlinOptions(
Hydrax::PerlinOptions(// 纹理质量
Hydrax::TEX_QUA_128 ,
// 频率
21,
// 波距,两个连续octave间振幅amplitude递增的速度的度量
1,
// Octave,每一个coherent noise就称为一个octave. //具体内容可以找找perlin噪音的介绍
10,
// Lacunarity,两个连续octave间频率frequency递增的速度的度量 1,
// 法线位图的高度
0.5));
// 水网格的设置
mHydrax->setMeshOptions(
Hydrax::MeshOptions(// 水面大小
Hydrax::Size(20000,20000),
// 格子 complexity
256));
// 设置RTT(渲染到纹理)的质量
mHydrax->setRttOptions(
Hydrax::RttOptions(// 反射纹理质量
Hydrax::TEX_QUA_512,
// 折射文理质量
Hydrax::TEX_QUA_512,
// 深度图质量
Hydrax::TEX_QUA_512));
//HYDRAX支持的功能,太阳、泡沫、深度、平滑、CAUSTICS
mHydrax->setComponents(
static_cast<Hydrax::HydraxComponent>(Hydrax::HYDRAX_COMPONENT_SUN |
Hydrax::HYDRAX_COMPONENT_FOAM |
Hydrax::HYDRAX_COMPONENT_DEPTH |
Hydrax::HYDRAX_COMPONENT_SMOOTH |
Hydrax::HYDRAX_COMPONENT_CAUSTICS));
// 创建水
mHydrax->create();
// 其他的一些设置
mHydrax->setVelocity(10.0);//力
mHydrax->setStrength(10);//力度,水面起伏的设置
mHydrax->setPosition(Ogre::Vector3(-10000,-100,-10000));//水面位置
mHydrax->setPlanesError(100);//平面误差
mHydrax->setDepthLimit(70);//深度限制,主要处理水和地面、物体接触地方时用
mHydrax->setSunPosition(mSunPosition[mCurrentSkyBox]);//太阳位置
mHydrax->setSunColor(mSunColor[mCurrentSkyBox]);//太阳颜色
mHydrax->setNormalDistortion(0.0235);//法线Distortion
mHydrax->setDepthColor(Ogre::Vector3(0.04,0.135,0.185));//深度颜色,一般为灰 mHydrax->setSmoothPower(5);//平滑度
mHydrax->setGlobalTransparency(0.1);//全局Transparency
mHydrax->setFullReflectionDistance(10000*10000);//折射距离
mHydrax->setFoamScale(10);//泡沫大小
// Lights
// Island
Ogre::Entity* IslandEntity;
IslandEntity = mSceneMgr->createEntity( "Island", " Island.mesh " ); IslandEntity->setMaterialName("Examples/OffsetMapping/Specular"); IslandSceneNode = mLight->setSpecularColour(mSunColor[mCurrentSkyBox].x,mSunColor[mCurrentSkyBox].y,mSunColor[mCurrentSkyBox].z); mSceneMgr->setAmbientLight(ColourValue(1, 1, 1)); Ogre::Light *mLight = mSceneMgr->createLight("Light0"); mLight->setPosition(mSunPosition[mCurrentSkyBox]); mLight->setDiffuseColour(1, 1, 1);
mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(0,0,0));
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if 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 //IslandSceneNode->setScale(23, 13.5, 23); IslandSceneNode->attachObject(IslandEntity); // Add frame listener mRoot->addFrameListener(new ExampleHydraxDemoListener(mWindow, mCamera, mSceneMgr));
{
// Create application object
SampleApp 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();
#endif
}
return 0;
}
百度搜索“爱华网”,专业资料,生活学习,尽在爱华网