OGRE中Demo_Water程序注释(1)

来源:互联网 发布:战争之王 知乎 编辑:程序博客网 时间:2024/05/18 00:49

//water.cpp

//水波的实现原理并不复杂:建立一个多格Mesh平面,加入多个水波种子,不断扩散,修改Mesm顶点,
//相互作用,形成水波效果。
//但是,Ogre的这个水波程序则搞得无比复杂,很有点Microsoft的风格,
//示例子里包含了Mesh变化,硬件缓存应用,天空,水材料更换,动态贴图,物体及灯光的曲线路径,
//及雨水的粒子特效,GUI图形显示,键盘输入控制多种选择,还有镜象反光,材料的折射等内容......
//完全不象irrlicht引擎那样,简简单单提供了一个水的材料,随便贴到哪里,那里就开始波涛翻滚了。
//不过,Ogre的水的效果也很出色,只好一点点细细读来。

//该演示程序包含三个文件:
//WaterMesh.h :定义了水波平面Mesh的类
//WaterMesh.cpp:水波平面Mesh类程序,如何建立Mesh,如何变形。
//Water.cpp: 主程序,所有效果都在这里实现

//    Water.cpp:

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
      (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright ?2000-2003 The OGRE Team
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/* Static water simulation by eru
* Started 29.05.2003, 20:54:37
*/
#include "ExampleApplication.h"
#include "WaterMesh.h"

#include <iostream>

AnimationState* mAnimState;

// Mesh stuff
#define MESH_NAME "WaterMesh"
#define ENTITY_NAME "WaterEntity"
#define MATERIAL_PREFIX "Examples/Water"
#define MATERIAL_NAME "Examples/Water0"
#define COMPLEXITY 64     // watch out - number of polys is 2*ACCURACY*ACCURACY !
#define PLANE_SIZE 3000.0f
#define CIRCLES_MATERIAL "Examples/Water/Circles"

/* Some global variables */
SceneNode *headNode ;
Overlay *waterOverlay ;
ParticleSystem *particleSystem ;
ParticleEmitter *particleEmitter ;
SceneManager *sceneMgr ;

//绘制一个圆环的图,做雨滴落水的环的贴图。
//这段算法看起来好象很复杂,其实原理很简单,你自己也可设计一种算法
//不过,将来自己的程序,还是用photoshop画一个带羽化的白圈更简单,不合适了重新画过。
//所以,该段只要明白其结果,不必细看算法。
void prepareCircleMaterial()
{
char *bmap = new char[256 * 256 * 4] ;    //图象缓存大小256x256,每元素4字节
memset(bmap, 127, 256 * 256 * 4);  

      //在数组里画圆环......

for(int b=0;b<16;b++) {   
    int x0 = b % 4 ;
    int y0 = b >> 2 ;
    Real radius = 4.0f + 1.4 * (float) b ;    //环开始的半径为4,结束为4+16*1.4
    for(int x=0;x<64;x++) {     
     for(int y=0;y<64;y++) {
      Real dist = Math::Sqrt((x-32)*(x-32)+(y-32)*(y-32));     //36
      dist = fabs(dist -radius -2) / 2.0f ;    //26
      dist = dist * 255.0f;
      if (dist>255)
       dist=255 ;
      int colour = 255-(int)dist ;    //0
      colour = (int)( ((Real)(15-b))/15.0f * (Real) colour );
    
      bmap[4*(256*(y+64*y0)+x+64*x0)+0]=colour ;
      bmap[4*(256*(y+64*y0)+x+64*x0)+1]=colour ;
      bmap[4*(256*(y+64*y0)+x+64*x0)+2]=colour ;
      bmap[4*(256*(y+64*y0)+x+64*x0)+3]=colour ;
     }
    }
}

SDDataChunk imgchunk(bmap, 256 * 256 * 4);    //数组转换为图象
//~ Image img;
//~ img.loadRawData( imgchunk, 256, 256, PF_A8R8G8B8 );
//~ TextureManager::getSingleton().loadImage( CIRCLES_MATERIAL , img );
TextureManager::getSingleton().loadRawData(CIRCLES_MATERIAL,
    imgchunk, 256, 256, PF_A8R8G8B8);        // A,R,G,B 格式将缓存数组生成的图象
Material *material = (Material*)
    MaterialManager::getSingleton().create( CIRCLES_MATERIAL );
TextureUnitState *texLayer = material->getTechnique(0)->getPass(0)->createTextureUnitState( CIRCLES_MATERIAL );
texLayer->setTextureAddressingMode( TextureUnitState::TAM_CLAMP );
material->setSceneBlending( SBT_ADD );   
material->setDepthWriteEnabled( false ) ;
      material->load();          //加载该圆圈材料
}


/* =========================================================================*/
/*                 WaterCircle class                                            */
/* =========================================================================*/
#define CIRCLE_SIZE 500.0
#define CIRCLE_TIME 0.5f

//雨滴落水的水圈处理的类
//这个近300条语句的过程做得异常复杂,费劲读完之后,发现其实只是一个圆圈图闪动几下而已,让人晕到 :-(
//可能是想用这个示例,讲解硬件缓存的使用方法吧

class WaterCircle   
{
private:
String name ;
SceneNode *node ;
Mesh *mesh ;
SubMesh *subMesh ;
Entity *entity ;
Real tm ;
static bool first ;
// some buffers shared by all circles
static HardwareVertexBufferSharedPtr posnormVertexBuffer ;
static HardwareIndexBufferSharedPtr indexBuffer ; // indices for 2 faces
static HardwareVertexBufferSharedPtr *texcoordsVertexBuffers ;

Real *texBufData;
void _prepareMesh()    //制作一个两个三角形组成的方片Mesh
{
    int i,lvl ;
  
    mesh= (Mesh*) MeshManager::getSingleton().createManual(name) ; //建立一个mesh对象

    subMesh = mesh->createSubMesh();    //建立一个子Mesh
    subMesh->useSharedVertices=false;

    int numFaces = 2 ;     //2个三角形
    int numVertices = 4 ;    //4个顶点

    if (first) { // first Circle, create some static common data     //这里初始化处理
     first = false ;    

     // static buffer for position and normals
     //建立4个点的只写硬件缓存            
     posnormVertexBuffer =
      HardwareBufferManager::getSingleton().createVertexBuffer(
       6*sizeof(Real), // size of one vertex data    //位置与法线各3个数据
       4, // number of vertices
       HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
       false); // no shadow buffer       //无需内存镜象

     Real *posnormBufData = (Real*) posnormVertexBuffer->
      lock(HardwareBuffer::HBL_DISCARD);      //锁定硬件缓存开始写入
     for(i=0;i<numVertices;i++) {
      //存位置
      posnormBufData[6*i+0]=((Real)(i%2)-0.5f)*CIRCLE_SIZE; // pos X
      posnormBufData[6*i+1]=0; // pos Y
      posnormBufData[6*i+2]=((Real)(i/2)-0.5f)*CIRCLE_SIZE; // pos Z
      //存法线,都向上
      posnormBufData[6*i+3]=0 ; // normal X
      posnormBufData[6*i+4]=1 ; // normal Y
      posnormBufData[6*i+5]=0 ; // normal Z
     }
     posnormVertexBuffer->unlock();      //解锁,格子Mesh在硬件缓存建立完成

     // static buffers for 16 sets of texture coordinates
     //建立16缓存索引段——记录各圈波UV贴图坐标
     texcoordsVertexBuffers = new HardwareVertexBufferSharedPtr[16];
     for(lvl=0;lvl<16;lvl++) {
      texcoordsVertexBuffers[lvl] =     //每段索引一个硬件缓存的贴图模板
       HardwareBufferManager::getSingleton().createVertexBuffer(
        2*sizeof(Real), // size of one vertex data, //只需x,y坐标两个数据记录UV
        numVertices, // number of vertices
        HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
        false); // no shadow buffer

      Real *texcoordsBufData = (Real*) texcoordsVertexBuffers[lvl]->
       lock(HardwareBuffer::HBL_DISCARD);    //给缓存赋值
      //小变大,大变小,多来几次
      float x0 = (Real)(lvl % 4) * 0.25 ;     //变化范围0-1
      float y0 = (Real)(lvl / 4) * 0.25 ;
      y0 = 0.75-y0 ; // upside down
      for(i=0;i<4;i++) {
       texcoordsBufData[i*2 + 0]=      //0
        x0 + 0.25 * (Real)(i%2) ;
       texcoordsBufData[i*2 + 1]=
        y0 + 0.25 * (Real)(i/2) ;
      }
      texcoordsVertexBuffers[lvl]->unlock();
     }

     // Index buffer for 2 faces
     //建立硬件面片缓存,将格子的二个三角写进去,每角对应前面的顶点
     unsigned short faces[6] = {2,1,0,    2,3,1};
     indexBuffer =
      HardwareBufferManager::getSingleton().createIndexBuffer(
       HardwareIndexBuffer::IT_16BIT,
       6,
       HardwareBuffer::HBU_STATIC_WRITE_ONLY);
     indexBuffer->writeData(0,
      indexBuffer->getSizeInBytes(),
      faces,
      true); // true?
    }
  
    // Initialize vertex data
    subMesh->vertexData = new VertexData();     //建立一个Vertex数据对象

    subMesh->vertexData->vertexStart = 0;
    subMesh->vertexData->vertexCount = 4;
    // first, set vertex buffer bindings
    VertexBufferBinding *vbind = subMesh->vertexData->vertexBufferBinding ;
    vbind->setBinding(0, posnormVertexBuffer);     //将硬件顶点缓存附加到位置0
    vbind->setBinding(1, texcoordsVertexBuffers[0]); //将硬件贴图缓存[0]附加到位置1

    // now, set vertex buffer declaration
    VertexDeclaration *vdecl = subMesh->vertexData->vertexDeclaration ;//通知数字格式为:
    vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);       //位置,3个值
    vdecl->addElement(0, 3*sizeof(Real), VET_FLOAT3, VES_NORMAL);    //法线,3个值
    vdecl->addElement(1, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);    //UV坐标,3个值
  
    // Initialize index data
    subMesh->indexData->indexBuffer = indexBuffer;        //指定面片索引缓存
    subMesh->indexData->indexStart = 0;
    subMesh->indexData->indexCount = 6;
  
    // set mesh bounds
    //设置mesh包围盒
    AxisAlignedBox circleBounds(-CIRCLE_SIZE/2.0f, 0, -CIRCLE_SIZE/2.0f,
     CIRCLE_SIZE/2.0f, 0, CIRCLE_SIZE/2.0f);
    mesh->_setBounds(circleBounds);
          mesh->load();         //mesh设置完成
          mesh->touch();         //不知道为什么要摸它一下
}
public:
int lvl ;
void setTextureLevel()
{
    //更换子Mesh的贴图坐标索引,
    subMesh->vertexData->vertexBufferBinding->setBinding(1, texcoordsVertexBuffers[lvl]);
}

//建立水圈
WaterCircle(const String& name, Real x, Real y)
{
    this->name = name ;
    _prepareMesh();        //初始化一个方片Mesm,产生硬件缓存,16个贴图坐标模板
    node = static_cast<SceneNode*> (sceneMgr->getRootSceneNode()->createChild(name));

    //放大到一个WaterMesh的格子大,10高
    node->translate(x*(PLANE_SIZE/COMPLEXITY), 10, y*(PLANE_SIZE/COMPLEXITY));
    entity = sceneMgr->createEntity(name, name);
    entity->setMaterialName(CIRCLES_MATERIAL);
    node->attachObject(entity);      //加入场景
    tm = 0 ;
    lvl = 0 ;          //初始时,lv1=0,强度最大,圈最小
    setTextureLevel();        //选用 0贴图模板
}

~WaterCircle()    //结束圈
{
    MeshManager::getSingleton().unload(mesh);
    delete mesh ; // nice, I think I don't have to delete any buffers here ;)
    sceneMgr->removeEntity(entity->getName());
    static_cast<SceneNode*> (sceneMgr->getRootSceneNode())->removeChild(node->getName());
}

//动画水圈
void animate(Real timeSinceLastFrame)
{
    int lastlvl = lvl ;
    tm += timeSinceLastFrame ;        //计时器增加
    lvl = (int) ( (Real)(tm)/CIRCLE_TIME * 16 );
    if (lvl<16 && lvl!=lastlvl) {       //如按波速递增进位
     setTextureLevel();         //更换贴图模板
    }
}
static void clearStaticBuffers()    //清除16个贴图模板
{
    posnormVertexBuffer = HardwareVertexBufferSharedPtr() ;
    indexBuffer = HardwareIndexBufferSharedPtr() ;
    for(int i=0;i<16;i++) {
     texcoordsVertexBuffers[i] = HardwareVertexBufferSharedPtr() ;
    }
    delete [] texcoordsVertexBuffers;
}
} ;


bool WaterCircle::first = true ;
HardwareVertexBufferSharedPtr WaterCircle::posnormVertexBuffer =
HardwareVertexBufferSharedPtr() ;
HardwareIndexBufferSharedPtr WaterCircle::indexBuffer =
HardwareIndexBufferSharedPtr() ;
HardwareVertexBufferSharedPtr* WaterCircle::texcoordsVertexBuffers = 0 ;

//经过上面漫长复杂的处理,圆环终于可以闪动了!不过,还要下面近100条语句来控制........

/* =========================================================================*/
/*                 WaterListener class                                            */
/* =========================================================================*/
// Event handler

 

转自:http://hi.baidu.com/ytxr/blog/item/538f042476338e30c89559b7.html

 

原创粉丝点击