您的位置:首页 > 其它

OGRE中Demo_Water程序注释(2)

2011-04-02 11:19 399 查看
//主听筒
class WaterListener: public ExampleFrameListener
{
protected:
WaterMesh *waterMesh ;
Entity *waterEntity ;
int materialNumber ;
bool skyBoxOn ;
Real timeoutDelay ;

#define RAIN_HEIGHT_RANDOM 5
#define RAIN_HEIGHT_CONSTANT 5

typedef std::vector<WaterCircle*> WaterCircles ;
WaterCircles circles ;

void processCircles(Real timeSinceLastFrame) //处理水圈
{
for(unsigned int i=0;i<circles.size();i++) { //根据水圈数量,逐个动画处理
circles[i]->animate(timeSinceLastFrame);
}
bool found ;
do {
found = false ;
for(WaterCircles::iterator it = circles.begin() ;
it != circles.end();
++it)
if ((*it)->lvl>=16) { //如果环的模板为16,即周期为16,结束并删除它
delete (*it);
circles.erase(it);
found = true ;
break ;
}
} while (found) ; //循环直到所有的死环删除
}

//粒子雨水处理,雨滴掉进水中,引发一个圆环,并推动水面
void processParticles()
{
static int pindex = 0 ;
ParticleIterator pit = particleSystem->_getIterator() ;
while(!pit.end()) {
Particle *particle = pit.getNext();
Vector3 ppos = particle->getPosition(); //取得一个雨滴粒子的位置
if (ppos.y<=0 && particle->mTimeToLive>0) { // 雨滴粒子掉水中了!
// delete particle
particle->mTimeToLive = 0.0f; //结束雨滴

// push the water
//在水中生成一个水波
float x = ppos.x / PLANE_SIZE * COMPLEXITY ;
float y = ppos.z / PLANE_SIZE * COMPLEXITY ;
float h = rand() % RAIN_HEIGHT_RANDOM + RAIN_HEIGHT_CONSTANT ;//波高加一定的随机数,避免太规则机械

//范围检测,道理上应该是掉在池子外的不管它了,这里都收归池子了
if (x<1) x=1 ;
if (x>COMPLEXITY-1) x=COMPLEXITY-1;
if (y<1) y=1 ;
if (y>COMPLEXITY-1) y=COMPLEXITY-1;

//按压水的waterMesh,产生变形
waterMesh->push(x,y,-h) ; //!!!打击到水面,产生一个圆波,这是water.cpp的关键之处

//加一个闪动的水圈图
WaterCircle *circle = new WaterCircle(
"Circle#"+StringConverter::toString(pindex++),
x, y);
circles.push_back(circle); //存进队列
}
}
}

/** Head animation */
//游动Ogre鬼头,劈开水流向前进
Real headDepth ;
void animateHead(Real timeSinceLastFrame)
{
if(!headNode) return;

// sine track? :)
static double sines[4] = {0,100,200,300};
static const double adds[4] = {0.3,-1.6,1.1,0.5};
static Vector3 oldPos = Vector3::UNIT_Z;
for(int i=0;i<4;i++) {
sines[i]+=adds[i]*timeSinceLastFrame;
}
//计算曲线轨迹,取得当前位置;不必细看,可采用自己的曲线。
Real tx = ((sin(sines[0]) + sin(sines[1])) / 4 + 0.5 ) * (float)(COMPLEXITY-2) + 1 ;
Real ty = ((sin(sines[2]) + sin(sines[3])) / 4 + 0.5 ) * (float)(COMPLEXITY-2) + 1 ;

waterMesh->push(tx,ty, -headDepth); //!!!!压迫水面,产生波浪
Real step = PLANE_SIZE / COMPLEXITY ;
headNode->resetToInitialState();
headNode->scale(3,3,3); //为什么要放大鬼头?没明白

Vector3 newPos = Vector3(step*tx, headDepth, step*ty); //沿轨迹前进,改变方向
Vector3 diffPos = newPos - oldPos ;
Quaternion headRotation = Vector3::UNIT_Z.getRotationTo(diffPos);
oldPos = newPos ;
headNode->translate(newPos);
headNode->rotate(headRotation);
}

//根据面板参数,改变各元素的GUI显示的文字,没多少技术内容,用CTRL+C与CTRL+V而已
// GUI updaters
void updateInfoParamC()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Param_C") /
->setCaption("[1/2]Ripple speed: "+StringConverter::toString(waterMesh->PARAM_C));
}
void updateInfoParamD()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Param_D") /
->setCaption("[3/4]Distance: "+StringConverter::toString(waterMesh->PARAM_D));
}
void updateInfoParamU()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Param_U") /
->setCaption("[5/6]Viscosity: "+StringConverter::toString(waterMesh->PARAM_U));
}
void updateInfoParamT()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Param_T") /
->setCaption("[7/8]Frame time: "+StringConverter::toString(waterMesh->PARAM_T));
}
void updateInfoNormals()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Normals") /
->setCaption(String("
Normals: ")+((waterMesh->useFakeNormals)?"fake":"real"));
}
void switchNormals()
{
waterMesh->useFakeNormals = !waterMesh->useFakeNormals ;
updateInfoNormals() ;
}
void updateInfoHeadDepth()
{
GuiManager::getSingleton().getGuiElement("Example/Water/Depth") /
->setCaption(String("[U/J]Head depth: ")+StringConverter::toString(headDepth));
}
void updateInfoSkyBox()
{
GuiManager::getSingleton().getGuiElement("Example/Water/SkyBox")
->setCaption(String("[B]SkyBox: ")+String((skyBoxOn)?"On":"Off") );
}

//水的材料更换,由用户选择
void updateMaterial()
{
//可更换的名字为"Examples/Water0"、"Examples/Water1"......
//Example-Water.material脚本定义了该例子的8个材料
//这涉及到材料脚本的编写,产生环境反射等
//因我的老电脑不能看全8种效果,在此暂不分析各材料脚本,有感兴趣的可分析
String materialName = MATERIAL_PREFIX+StringConverter::toString(materialNumber); //由序号组合材料名字
Material *material = static_cast<Material*> (MaterialManager::getSingleton().getByName(materialName));
if (!material){
if(materialNumber){
materialNumber = 0 ;
updateMaterial(); //超过回0
return ;
} else {
Except(Exception::ERR_INTERNAL_ERROR,
"Material "+materialName+"doesn't exist!",
"WaterListener::updateMaterial");
}
}
waterEntity->setMaterialName(materialName); //更换材料

GuiManager::getSingleton().getGuiElement("Example/Water/Material") /
->setCaption(String("[M]Material: ")+materialName); //改变面板显示
}

//根据用户指示,改变水的材料
void switchMaterial()
{
materialNumber++;
updateMaterial();
}

//开关天空的渲染
void switchSkyBox()
{
skyBoxOn = !skyBoxOn;
sceneMgr->setSkyBox(skyBoxOn, "Examples/SceneSkyBox2");
updateInfoSkyBox();
}

public:
//水听筒的处理初始化
WaterListener(RenderWindow* win, Camera* cam,
WaterMesh *waterMesh, Entity *waterEntity)
: ExampleFrameListener(win, cam)
{
this->waterMesh = waterMesh ; //水面Mesm
this->waterEntity = waterEntity ;
materialNumber = 8; //选择的材料序号
timeoutDelay = 0.0f; //延时
headDepth = 2.0f; //鬼头吃水深度
skyBoxOn = false ; //天空默认关闭

updateMaterial();
updateInfoParamC();
updateInfoParamD();
updateInfoParamU();
updateInfoParamT();
updateInfoNormals();
updateInfoHeadDepth();
updateInfoSkyBox();
}

//结束处理
virtual ~WaterListener ()
{
// If when you finish the application is still raining there
// are water circles that are still being processed
unsigned int activeCircles = this->circles.size ();

// Kill the active water circles
for (unsigned int i = 0; i < activeCircles; i++)
delete (this->circles[i]);
}

//帧处理
bool frameStarted(const FrameEvent& evt)
{
bool retval = ExampleFrameListener::frameStarted(evt); //父功能调用

mAnimState->addTime(evt.timeSinceLastFrame); //动画器计时,用于移动灯光等外围动画处理

// process keyboard events
// 键盘输入处理
mInputDevice->capture();
Real changeSpeed = evt.timeSinceLastFrame ;

//SHIFT加速,CTRL键减速
// adjust keyboard speed with SHIFT (increase) and CONTROL (decrease)
if (mInputDevice->isKeyDown(KC_LSHIFT) || mInputDevice->isKeyDown(KC_RSHIFT)) {
changeSpeed *= 10.0f ;
}
if (mInputDevice->isKeyDown(KC_LCONTROL)) {
changeSpeed /= 10.0f ;
}

// rain
//水圈处理
processCircles(evt.timeSinceLastFrame);

//雨水粒子处理,空格键下雨
if (mInputDevice->isKeyDown(KC_SPACE)) {
particleEmitter->setEmissionRate(20.0f);
} else {
particleEmitter->setEmissionRate(0.0f);
}
processParticles(); //水粒子处理

// adjust values (some macros for faster change
//键盘输入处理
#define ADJUST_RANGE(_value,_keyPlus,_keyMinus,_minVal,_maxVal,_change,_macro) {/
if (mInputDevice->isKeyDown(_keyPlus)) /
{ _value+=_change ; if (_value>=_maxVal) _value = _maxVal ; _macro ; } ; /
if (mInputDevice->isKeyDown(_keyMinus)) /
{ _value-=_change; if (_value<=_minVal) _value = _minVal ; _macro ; } ; /
}
//U,J 键盘改变鬼头吃水深度
ADJUST_RANGE(headDepth, KC_U, KC_J, 0, 10, 0.5*changeSpeed, updateInfoHeadDepth()) ;

//1-8改变水波的各钟幅度参数,参见后面的waterMesh
ADJUST_RANGE(waterMesh->PARAM_C, KC_2, KC_1, 0, 10, 0.1f*changeSpeed, updateInfoParamC()) ;

ADJUST_RANGE(waterMesh->PARAM_D, KC_4, KC_3, 0.1, 10, 0.1f*changeSpeed, updateInfoParamD()) ;

ADJUST_RANGE(waterMesh->PARAM_U, KC_6, KC_5, -2, 10, 0.1f*changeSpeed, updateInfoParamU()) ;

ADJUST_RANGE(waterMesh->PARAM_T, KC_8, KC_7, 0, 10, 0.1f*changeSpeed, updateInfoParamT()) ;

timeoutDelay-=evt.timeSinceLastFrame ;
if (timeoutDelay<=0)
timeoutDelay = 0;

#define SWITCH_VALUE(_key,_timeDelay, _macro) { /
if (mInputDevice->isKeyDown(_key) && timeoutDelay==0) { /
timeoutDelay = _timeDelay ; _macro ;} }

SWITCH_VALUE(KC_N, 0.5f, switchNormals()); //N键切换真伪法线

SWITCH_VALUE(KC_M, 0.5f, switchMaterial()); //M键换水的材料

SWITCH_VALUE(KC_B, 0.5f, switchSkyBox()); //B键开关天空

animateHead(evt.timeSinceLastFrame); //移动鬼头

waterMesh->updateMesh(evt.timeSinceLastFrame); //水波变形

// check if we are exiting, if so, clear static HardwareBuffers to avoid
// segfault
if (!retval)
WaterCircle::clearStaticBuffers(); //如结束清除缓存

// return result from default
return retval ;
}
};

//终于到主程序入口了!
class WaterApplication : public ExampleApplication
{
public:
WaterApplication() {

}

~WaterApplication() {
delete waterMesh;
}

protected:
WaterMesh *waterMesh ;
Entity *waterEntity ;

// Just override the mandatory create scene method
void createScene(void) //建立场景
{
sceneMgr = mSceneMgr ;
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.75, 0.75, 0.75)); //打开均匀的环境光照

// Create a light
//建立一个点光源,在水面上按随机路线飞舞运动,加强波光效果(见后面)
//但实际中看不出灯的效果,不知道哪里出问题了
Light* l = mSceneMgr->createLight("MainLight"); //缺省的灯光为点光,白色
// Accept default settings: point light, white diffuse, just set position
// NB I could attach the light to a SceneNode if I wanted it to move automatically with
// other objects, but I don't
l->setPosition(200,300,100);

// Create water mesh and entity
waterMesh = new WaterMesh(MESH_NAME, PLANE_SIZE, COMPLEXITY); //建立一个水的Mesh对象,见WaterMesh.cpp
waterEntity = mSceneMgr->createEntity(ENTITY_NAME,
MESH_NAME);
//~ waterEntity->setMaterialName(MATERIAL_NAME);
SceneNode *waterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
waterNode->attachObject(waterEntity); //加入场景

// Add a head, give it it's own node
headNode = waterNode->createChildSceneNode();
Entity *ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
headNode->attachObject(ent); //载入Ogre鬼头,加入场景

// Make sure the camera track this node
//~ mCamera->setAutoTracking(true, headNode);

// Create the camera node, set its position & attach camera
//将摄影机加入场景节点,其实这个例子不加也应该可以用。加上的好处是可以便于程序控制
//你可以尝试将摄影机节点附加到鬼头脑袋上,跟着鬼头在波浪里滑行,效果一定很震撼!
SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
camNode->translate(0, 500, PLANE_SIZE);
camNode->yaw(Degree(-45));
camNode->attachObject(mCamera);

// Create light node
SceneNode* lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
lightNode->attachObject(l); //运动灯光加入场景

// set up spline animation of light node
//给灯光加随机位置随机曲线
Animation* anim = mSceneMgr->createAnimation("WaterLight", 20);
AnimationTrack *track ;
KeyFrame *key ;
// create a random spline for light
track = anim->createTrack(0, lightNode);
key = track->createKeyFrame(0);
for(int ff=1;ff<=19;ff++) {
key = track->createKeyFrame(ff);
Vector3 lpos (
rand()%(int)PLANE_SIZE , //- PLANE_SIZE/2,
rand()%300+100,
rand()%(int)PLANE_SIZE //- PLANE_SIZE/2
);
key->setTranslate(lpos);
}
key = track->createKeyFrame(20); //曲线路径:由上边随机定义的20个关键帧确定

// Create a new animation state to track this
mAnimState = mSceneMgr->createAnimationState("WaterLight");//建立一个动画器,驱动灯的运动
mAnimState->setEnabled(true); //允许动画
//灯光效果没太看出来

// Put in a bit of fog for the hell of it
// mSceneMgr->setFog(FOG_EXP, ColourValue::White, 0.0002); //作者本想做个白雾,加强效果。不过,Ogre里雾与雨的粒子系统有冲突,所以在此删掉了。

// show overlay //overlay是个什么东西?还没学到。删掉这两句,演示似乎也没有什么变化。
waterOverlay = (Overlay*)OverlayManager::getSingleton().getByName("Example/WaterOverlay");
waterOverlay->show();

// Let there be rain
//建立粒子雨
particleSystem = ParticleSystemManager::getSingleton().createSystem("rain",
"Examples/Water/Rain"); //建立
particleEmitter = particleSystem->getEmitter(0);
SceneNode* rNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
rNode->translate(PLANE_SIZE/2.0f, 3000, PLANE_SIZE/2.0f); //Node放大确定降雨范围
rNode->attachObject(particleSystem); //将粒子系统附加到节点上
// Fast-forward the rain so it looks more natural
particleSystem->fastForward(20); //雨的方向为快速向下
// It can't be set in .particle file, and we need it ;)
particleSystem->setBillboardOrigin(BBO_BOTTOM_CENTER); //面向屏幕的转片做的雨效,设转动轴心

prepareCircleMaterial(); //制作水圈材料
}

// Create new frame listener
void createFrameListener(void) //新建听筒,便于实时处理过程
{
mFrameListener= new WaterListener(mWindow, mCamera, waterMesh, waterEntity);
mRoot->addFrameListener(mFrameListener);
}

};

#if OGRE_PLATFORM == 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
WaterApplication app;

srand(time(0)); //初始化随机数种子,免得每次老面孔

try {
app.go(); //开动场景
} catch( Exception& e ) {
#if OGRE_PLATFORM == 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; //完了
}

转自:http://hi.baidu.com/ytxr/blog/item/a1c6a4512e4de38c8c5430b7.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: