转载:OGRE一起学(九)平面

第九章 平面

运行截图:

Image:Yanchen91.jpg

前几节悬空的模型没有为我们提供一个“踏实”的参照系,难以体现物体空间位置的变化,因为没有地面。所以在学习移动、缩放和旋转之前,我们先学习创造一个地面。

要在场景中创建并渲染一个平面,需要下面三个步骤: 1. 定义平面; 2. 从定义的平面创建平面模型; 3. 将平面模型绑定到场景节点。

  • 1. 定义平面 :
  Plane plane; // 定义平面
  plane.normal = Vector3::UNIT_Y; // 定义平面的法线方向(也就是平面正面的朝向)
  plane.d = 100; // 定义平面与世界原点的距离

平面 ( Plane ) 是 OGRE 唯一的一种内置简单几何体 (Primitive) 。当然,如果你高兴,你可以修改 OGRE 的内核代码,使它能够创建更多类型的简单几何体例如立方体 (Cube/Box) 、球体 (Sphere) 、柱体 (Cylinder) 、锥体 (Cone) 、 圆环体 (Torus) 、或者茶壶 (Teapot) ,很多商业引擎具有直接创建这些简单几何体的能力,但是 OGRE 目前只能创建简单平面。

OGRE:: Plane (平面) 对象的定义参看头文件 OgrePlane.h ,它有五个重载的构造函数,意味着我们可以使用五种不同的方法来创建一个平面:

  // 使用默认设置直接创建平面
  Plane::Plane ()
  {
  normal = Vector3::ZERO;
  d = 0.0;
  }
  // 使用现有平面的设置新建一个平面
  Plane::Plane (const Plane& rhs)
  {
  normal = rhs.normal;
  d = rhs.d;
  }
  // 由法线方向和平面到世界原点的距离创建一个平面
  Plane::Plane (const Vector3& rkNormal, Real fConstant)
  {
  normal = rkNormal;
  d = -fConstant;
  }
  // 由法线方向和平面上的一点创建一个平面
  Plane::Plane (const Vector3& rkNormal, const Vector3& rkPoint)
  {
  normal = rkNormal;
  d = -rkNormal.dotProduct(rkPoint);
  }
  // 三点确定一个平面
  Plane::Plane (const Vector3& rkPoint0, const Vector3& rkPoint1, const Vector3& rkPoint2)
  {
  redefine(rkPoint0, rkPoint1, rkPoint2);
  }

平面具有两种基本属性:

  Vector3 normal; // 法线方向
  Real d; // 与世界原点的距离
  • 2. 从定义的平面创建平面模型 :
  Mesh* pGround = MeshManager::getSingleton().createPlane(
  "GroundPlane", // 模型名称
  plane, // 平面定义
  2000, // X 方向宽度
  1000, // Z 方向宽度
  10, // X 方向分割
  5, // Z 方向分割
  true, // 是否创建法线
  2, // 纹理坐标数量
  16, // U 方向纹理铺嵌的行数
  8, // V 方向纹理铺嵌的行数
  Vector3::UNIT_Z // 正面朝向
  );

在第一步中,我们仅仅是定义了一个非常抽象的平面,这个抽象的平面只拥有法线方向和与世界原点的距离两个属性,在第二步,我们就要使用 createPlane 方法使这个平面具体化,赋予它名称、尺寸、分割、纹理坐标等具体属性,正式构建出一个平面模型 ( Mesh ) 。

MeshManager:: createPlane () (创建平面)方法在头文件 OgreMeshManager.h 中定义:

  Mesh * Ogre::MeshManager::createPlane (
  const String & name, // 平面模型的名称
  const Plane & plane, // 所使用的平面定义的名称
  Real width, // 平面宽度 (X 方向)
  Real height, // 平面高度 (Y 方向)
  int xsegments = 1, // X 方向分割数目
  int ysegments = 1, // Y 方向分割数目
  bool normals = true, // 是否创建垂直于平面的法线
  int numTexCoordSets = 1, // 纹理坐标集的数目(也就是多层纹理的层数)
  Real uTile = 1.0f, // U 方向纹理铺嵌行数
  Real vTile = 1.0f, // V 方向纹理铺嵌行数
  const Vector3 & upVector = Vector3::UNIT_Y, 
  // 上方向法线,指示平面的正面朝向
  HardwareBuffer::Usage vertexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
  // 顶点缓存用途
  HardwareBuffer::Usage indexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
  // 索引缓存用途
  bool vertexShadowBuffer = true, // 顶点阴影缓存
  bool indexShadowBuffer = true // 索引阴影缓存
  ) 

后面四个参数目前暂不深究,使用默认值。

  • 3. 将平面模型绑定到场景节点 :
  // 创建实体(地面)
  Entity* entGround = mSceneMgr->createEntity( "ground", "GroundPlane" );
  // 为地面设置材质
  entGround->setMaterialName( "Examples/Rockwall" );
  // 在场景根节点下创建一个子节点用于绑定这个地面实体
  SceneNode* groundNode = rootNode->createChildSceneNode();
  // 把地面实体绑定到这个子节点
  groundNode->attachObject( entGround );

Entity:: setMaterialName () (设置材质名称) 方法在头文件 OgreEntity.h 中定义,使用这个方法可以整体替换模型的本体材质,非常方便:

  void Ogre::Entity:: setMaterialName ( const String & name ) 

材质和模型、粒子一样,属于一种预制资源。打开 OGRE\Samples\Media\materials\scripts\ 目录,可以在下面看到一系列后缀是 *.material 的文件,这些都是材质的定义脚本。使用文本编辑器打开 Example.material ,在里面你可以查找到包含 Examples/Rockwall 字样的脚本段落,它在这个文件的最后:

  material Examples/Rockwall // material 材质名称
  {
  technique // 材质渲染技术块
  {
  pass // 材质渲染通道
  {
  texture_unit // 纹理单位
  {
  texture rockwall.tga // texture 纹理贴图名称
  }
  }
  }
  } 

其中的纹理贴图 rockwall.tga ,和其它所有的贴图文件一起,位于 OGRE\Samples\Media\textures\ 目录下,在这里我们不用指定贴图的路径, 凭借配置文件 resources.cfg , OGRE 可以自动找到这张贴图。

材质脚本的详细内容以后找时间再介绍。

最后,我用离线浏览工具下载了 OGRE 官网的手册 (Manual) ,里面有关于材质脚本的解说,比较详细,可以先看看。

posted @ 2009-06-08 13:19 回忆1919 阅读(...) 评论(...) 编辑 收藏