OGRE中Demo_Water程序注释(2)

来源:互联网 发布:淘宝店铺背景设置 编辑:程序博客网 时间:2024/05/30 23:16

//主听筒
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("[N]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