转载:OGRE一起学(九)平面
第九章 平面
运行截图:
前几节悬空的模型没有为我们提供一个“踏实”的参照系,难以体现物体空间位置的变化,因为没有地面。所以在学习移动、缩放和旋转之前,我们先学习创造一个地面。
要在场景中创建并渲染一个平面,需要下面三个步骤: 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) ,里面有关于材质脚本的解说,比较详细,可以先看看。