【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 6178|回复: 3

[OGRE引擎] Ogre草地演示(Demo_Grass)(注释)[转]

[复制链接]
发表于 2009-8-6 09:32:29 | 显示全部楼层 |阅读模式
这是从前学习Ogre时随手写下的注释,原来贴在燕尘的主页上,不幸主页被黑,好多篇都丢了。连我的发文资格也没了。
在硬盘上偶然找到一篇,贴在这里。

//这是Ogre(RC1版本)中的一个很漂亮的演示:
//幽蓝的天空下,广阔的草地随风起舞;Ogre鬼头深藏草丛中,仿佛远古的遗迹;天空飞舞着闪动的彩灯,仿佛外太空使者来访......
//呵呵,好美,但我不能贴出图来,因为燕版主还没给我这个权利。
//只好自己编译了去看了.......假如你的电脑是块很老很老的显示卡,恐怕也看不见草的摇摆了。
//这个Demo场景不算复杂,只有几百个mesh,用老技术完全可以很容易实现。采用新技术可算是杀鸡用宰牛刀了。
//该程序的主要原理是,使用三个方片,贴alpha草叶图,三个方片按竖中轴各60度交叉,形成一个草墩。
//场景中放置26X26个草墩,形成草地。草墩顶点坐标左右前后轻微移动........
//通过这个Demo,可初步了解一下新技术的采用方法,包括:
//1.静态几何体(StaticGeometry)的使用:
//这是Ogre1.0RC新出现的内容,将不需要移动的多个Mesh按区域集合,渲染时按批渲染。据Ogre称:这样比逐个渲染提高效率。
//Ogre为此做了一个庞大的管理器。这未免有点太夸张了——Ogre的很多地方都很夸张。
//2.CG程序的使用
//cg是目前的新潮。Ogre为我们提供了一个采用cg的简便的平台,可以跳过cg编译等一大堆东西,直接切入主题。
//本程序的cg不复杂,通过这个程序,我们将知道如何定义顶点脚本,怎么在顶点脚本嵌入cg程序,主程序如何把参数传给cg程序,如何写一个初步的cg脚本。
//(材料及cg脚本的注释在程序后面)
//3.控制器(Controller)的使用,如何自动驱动灯光的闪动。这可能是老内容了
//注意,本程序包括在Ogre 1.0RC中,Demo_Grass,老的(0.152版)没有。
//以下是注释,非关键的地方就懒得注了。
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see
http://www.ogre3d.org/
Copyright (c) 2000-2005 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.
-----------------------------------------------------------------------------
*/
/**
    \file
        Grass.cpp
    \brief
        Specialisation of OGRE's framework application to show the
        use of the StaticGeometry class to create 'baked' instances of
  many meshes, to create effects like grass efficiently.
**/
//老的头文件
#include "ExampleApplication.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
//定义键盘控制函数,按B键可以看到静态几何体的区域划分的边框
#define KEY_PRESSED(_key,_timeDelay, _macro) \
{ \
    if (mInputDevice->isKeyDown(_key) && timeDelay
//参数定义
#define GRASS_HEIGHT 300      //草墩高300
#define GRASS_WIDTH 250       //草墩宽250
#define GRASS_MESH_NAME "grassblades"   //草片mesh名
#define GRASS_MATERIAL "Examples/GrassBlades" //草片材料名定义
#define OFFSET_PARAM 999      //偏移参数
Light* mLight;
SceneNode* mLightNode = 0;
AnimationState* mAnimState = 0;
ColourValue mMinLightColour(0.5, 0.1, 0.0);
ColourValue mMaxLightColour(1.0, 0.6, 0.0);
Real mMinFlareSize = 40;      //闪光使用一个带光环的贴图,可以按此原理做简单的光晕了。
Real mMaxFlareSize = 80;
StaticGeometry* mStaticGeom;
/** This class 'wibbles' the light and billboard */
//灯光闪动控制对象
class LightWibbler : public ControllerValue
{
protected:
Light* mLight;
Billboard* mBillboard;
ColourValue mColourRange;
ColourValue mHalfColour;
Real mMinSize;
Real mSizeRange;
Real intensity;
public:
//建立灯光对象,入口参数包括灯,转片,颜色范围,大小范围
LightWibbler(Light* light, Billboard* billboard, const ColourValue& minColour,
  const ColourValue& maxColour, Real minSize, Real maxSize)
{
  mLight = light;
  mBillboard = billboard;
  mColourRange.r = (maxColour.r - minColour.r) * 0.5;
  mColourRange.g = (maxColour.g - minColour.g) * 0.5;
  mColourRange.b = (maxColour.b - minColour.b) * 0.5;
  mHalfColour = minColour + mColourRange;   //保存亮度的中间值为参考
  mMinSize = minSize;
  mSizeRange = maxSize - minSize;
}
//取灯光强度值函数,由控制器调用
virtual Real  getValue (void) const
{
  return intensity;
}
//灯光强度值设置函数,由控制器调用
virtual void  setValue (Real value)
{
  intensity = value;
  ColourValue newColour;
  // Attenuate the brightness of the light
  //在原始的的亮度中间值,增加或减少
  newColour.r = mHalfColour.r + (mColourRange.r * intensity);
  newColour.g = mHalfColour.g + (mColourRange.g * intensity);
  newColour.b = mHalfColour.b + (mColourRange.b * intensity);
  mLight->setDiffuseColour(newColour);
  mBillboard->setColour(newColour);
  //转片与亮度一起放大缩小
  // set billboard size
  Real newSize = mMinSize + (intensity * mSizeRange);
  mBillboard->setDimensions(newSize, newSize);
}
};
//听筒处理
class GrassListener : public ExampleFrameListener
{
protected:
SceneManager* mSceneManager;
bool mShowBBs;
public:
//构造函数
GrassListener(RenderWindow* win, Camera* cam, SceneManager* sceneManager)
  : ExampleFrameListener(win, cam),
  mSceneManager(sceneManager), mShowBBs(false)
{
}
    //草波处理函数
void waveGrass(Real timeElapsed)
{
  //根据当前时间,确定变化参数 offset
  //坐标:简单理解为x左右方向,z前后方向,y上下方向。
  static Real xinc = Math:I * 0.4;
  static Real zinc = Math:I * 0.55;
  static Real xpos = Math::RangeRandom(-Math:I, Math:I);  //x随机位置(-3.14到3.14间)
  static Real zpos = Math::RangeRandom(-Math:I, Math:I);  //z随机位置(-3.14到3.14间)
  xpos += xinc * timeElapsed;  //x加时间因数*PI*0.4   
  zpos += zinc * timeElapsed;  //z加时间因数*PI*0.55 ,前后幅度比左右略大
  // Update vertex program parameters by binding a value to each renderable
  static Vector4 offset(0,0,0,0);  //定义offset,这是要传给顶点程序的
  StaticGeometry::RegionIterator rit =  mStaticGeom->getRegionIterator(); //取得静态几何体的区域接口
  //主循环遍历所有几何体区域, 刷新其各个组件的材料的参数
  while (rit.hasMoreElements())
  {
   //取得静态几何体的一个区域
   StaticGeometry::Region* reg = rit.getNext();  //区域
   //按区域摇摆,确定摇摆参数
   //这样,一个区域都一样地摆动,有点机械
   // a little randomness
   xpos += reg->getCentre().x * 0.001; //x根据中心位置作少许偏移
   zpos += reg->getCentre().z * 0.001; //z....
   offset.x = Math::Sin(xpos) * 0.05;  //草的摇摆幅度x
   offset.z = Math::Sin(zpos) * 0.05;  //草的摇摆幅度z
   StaticGeometry::Region:ODIterator lodit = reg->getLODIterator();  //LOD
   //这个循环列举每个区域的所有Mesh元素
   while (lodit.hasMoreElements())
   {
    StaticGeometry:ODBucket* lod = lodit.getNext();
    StaticGeometry:ODBucket::MaterialIterator matit =  
     lod->getMaterialIterator();  //取得材料接口
    //一个元素可能采用不止一种材料,故命名为材料桶,列举所有材料元素
    while (matit.hasMoreElements())
    {
     StaticGeometry::MaterialBucket* mat = matit.getNext();
     StaticGeometry::MaterialBucket::GeometryIterator geomit =
      mat->getGeometryIterator();
     //geomit
     //循环列举材料筒所有材料
     while (geomit.hasMoreElements())
     {
      StaticGeometry::GeometryBucket* geom = geomit.getNext();
      //将新的偏移参数(offset)传送到geomit
      geom->setCustomParameter(OFFSET_PARAM, offset);
      
      //OFFSET_PARAM为索引指针,在本程序开始定义为999,
      //与材料里面顶点程序的定义匹配:材料里定义为param_named_auto offset custom 999
      //这样,就将offset传送到材料的offset参数
      //本材料使用的cg程序,将按此设定作顶点处理
     }
    }
   }
  }
}
//每帧前处理
bool frameStarted(const FrameEvent& evt)
{
  bool ok = ExampleFrameListener::frameStarted(evt);   //父功能调用     
  static Real timeDelay = 0;
  timeDelay -= evt.timeSinceLastFrame;    //更新时间参数
  if (mAnimState)
   mAnimState->addTime(evt.timeSinceLastFrame); //动画器处理,驱动灯光位置变化
  KEY_PRESSED(KC_B, 1,
   mShowBBs = !mShowBBs;
   mSceneManager->showBoundingBoxes(mShowBBs);  //按B键,打开包围盒显示。(或者关上)
   )
  waveGrass(evt.timeSinceLastFrame);     //调草波处理函数
  return ok;
}
};
//主过程
class Grass_Application : public ExampleApplication
{
public:
    Grass_Application() {}

protected:
SceneNode *mpObjsNode; // the node wich will hold our entities
//建立一个草墩的Mesh体,
void createGrassMesh()
{
  //使用硬件缓存建立
  // Each grass section is 3 planes at 60 degrees to each other
  // Normals point straight up to simulate correct lighting
  //每墩草使用3个平面组成,三个以y轴中心交叉的方片,片间角度为60度。
  //其贴图采用带alpha通道的png格式——这是游戏里通常做树木的手法
  //2006.1.22:这涉及到透明物体的排序,Ogre如何实现许多的面排序的?
  //分组的目的是否是利于先组内排序,再组间排序以减少运算量?
  MeshPtr msh = MeshManager::getSingleton().createManual(GRASS_MESH_NAME,
   ResourceGroupManager:EFAULT_RESOURCE_GROUP_NAME);
  SubMesh* sm = msh->createSubMesh();
  sm->useSharedVertices = false;
  sm->vertexData = new VertexData();  //建立新的顶点数据
  sm->vertexData->vertexStart = 0;
  sm->vertexData->vertexCount = 12;  //12个顶点
  //加入顶点附加参数描述,即包括位置,法线,贴图坐标
  VertexDeclaration* dcl = sm->vertexData->vertexDeclaration;
  size_t offset = 0;
  dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);  //顶点位置
  offset += VertexElement::getTypeSize(VET_FLOAT3);
  dcl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);   //法线
  offset += VertexElement::getTypeSize(VET_FLOAT3);
  dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); //贴图坐标
  offset += VertexElement::getTypeSize(VET_FLOAT2);
  //建立顶点硬件缓存
  HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
   .createVertexBuffer(
    offset, 12, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  //锁定,设置单个草墩顶点
  float* pReal = static_cast(vbuf->lock(HardwareBuffer::HBL_DISCARD));
  Vector3 baseVec(GRASS_WIDTH/2, 0, 0);
  Vector3 vec = baseVec;
  Quaternion rot;
  rot.FromAngleAxis(Degree(60), Vector3::UNIT_Y);
  int i;
  for (i = 0; i
   //点2
   // position
   *pReal++ = vec.x;
   *pReal++ = GRASS_HEIGHT;
   *pReal++ = vec.z;
   // normal
   *pReal++ = 0;
   *pReal++ = 1;
   *pReal++ = 0;
   // uv
   *pReal++ = 1;
   *pReal++ = 0;
   //点3
   // position
   *pReal++ = -vec.x;
   *pReal++ = 0;
   *pReal++ = -vec.z;
   // normal
   *pReal++ = 0;
   *pReal++ = 1;
   *pReal++ = 0;
   // uv
   *pReal++ = 0;
   *pReal++ = 1;
   //点4
   // position
   *pReal++ = vec.x;
   *pReal++ = 0;
   *pReal++ = vec.z;
   // normal
   *pReal++ = 0;
   *pReal++ = 1;
   *pReal++ = 0;
   // uv
   *pReal++ = 1;
   *pReal++ = 1;
   vec = rot * vec;
  }
  vbuf->unlock();  
  sm->vertexData->vertexBufferBinding->setBinding(0, vbuf); //顶点设置完毕,绑定到硬件缓存0
  //下面设置面片,索引到上面的顶点
  sm->indexData->indexCount = 6*3;  //3个平面,每面2个三角形,
  sm->indexData->indexBuffer = HardwareBufferManager::getSingleton()
   .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 6*3,
    HardwareBuffer::HBU_STATIC_WRITE_ONLY);
  uint16* pI = static_cast(
   sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
  for (i = 0; i
   *pI++ = 0 + off;  //第2个三角形
   *pI++ = 2 + off;
   *pI++ = 3 + off;
  }
  sm->indexData->indexBuffer->unlock();  //数据设定完毕
  sm->setMaterialName(GRASS_MATERIAL);  //指定为GRASS_MATERIAL材料
}
 
发表于 2013-6-6 01:36:44 | 显示全部楼层
顶!!!!!!!!!!

qq皮肤透明素材 qq搞笑个性签名 qq非主流男生网名 非主流高清女生头像 女生唯美图片 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-5-14 05:48

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表