OGRE中级教程五 Static Geometry

英语水平有限,欢迎大家批评指正微笑

本文并没有将原文全部翻译,只是将其中的一些知识点翻译总结了一下,想要查看详细讲解的话,可以到原文处看一下,附上英文原文地址:http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Intermediate+Tutorial+5&structure=Tutorials

Introduction

   有很多这样的情况,你向场景中添加对象,当你根本不需要移动他们,如岩石或树。对于这些情况,OGRE提供了StaticGeometry类,它允许你创建一批对象并成群(in a big bunch)渲染他们。这比手动添加场景节点要快的多。本教程中我们将学校StaticGeometry在程序中的基本应用,我们还会学一些关于ManualObject的东西。本教程中我们将手动创建一个草地(grass)的网格,然后添加很多这些网格到场景中的StaticGeometry对象中。

Creating the Scene

Creating the Mesh

   首先场景草坪网格。大体的想法就是创建三个互相重叠的四方形(quad)。每个四方形有一个草坪纹理,所以除了从上往下,当你从任意方向观察时,他就像3D草坪一样。重叠这些四方形的最简单的方法就是创建一个四方形,然后旋转60度角再创建另一个,然后再旋转60度角创建另一个。

   我们要使用ManualObject来生成我们的对象,但不想之前的教程使用线条列表(它要求我们创建一个索引缓存,指定我们创建的三角形),而是实际创建一个网格。

   首先定义一些基本的变量,由于我们要旋转我们定义的四方形,如果我们用OGRE构造Vector3和四元数来为我们做计算而不是手动,那么事情就会很简单。我们计划创建一个有XZ坐标的Vector3,用它创建一个四方形,然后用一个四元数旋转它,然后重复这些操作。添加如下代码到createGrassMesh成员函数中:

    const float width = 25;

const float height = 30;

Ogre::ManualObject mo("GrassObject");

Ogre::Vector3 vec(width/2, 0, 0);

Ogre::Quaternion rot;

rot.FromAngleAxis(Ogre::Degree(60), Ogre::Vector3::UNIT_Y);

   现在我们已经设置了变量,然后要定义ManualObject。不像之前的教程,我们将实际指定一个材质给该对象使用。RenderOperation也会被设为一个三角形列表,即定义好顶点后我们必须定义一个创建四方形各个面的三角形的列表:

  mo.begin("Examples/GrassBlades", Ogre::RenderOperation::OT_TRIANGLE_LIST);

for (int i = 0; i < 3; ++i)

{

   每个四方形都定义四个顶点,一个对应一个角。为每个顶点指定一个纹理坐标,纹理坐标告诉OGRE如何取样(sample)我们在Examples/GrassBlades材质里面指定的纹理。我们将使左上角为纹理的(0,0)点,右下角为纹理的(1,1)点:

   mo.position(-vec.x, height, -vec.z);

        mo.textureCoord(0, 0);

        mo.position(vec.x, height, vec.z);

        mo.textureCoord(1, 0);

        mo.position(-vec.x, 0, -vec.z);

        mo.textureCoord(0, 1);

        mo.position(vec.x, 0, vec.z);

        mo.textureCoord(1, 1);

   现在我们定义了四方形的四个角,下面要创建面(face)了。你必须通过创建三角形来指定面(face),还要确保逆时针(counter clockwise)扭转(wind)面(face)朝向你。对每个四方形,我们都创建两个三角形。第一个有第031顶点定义,第二个有0,2,3顶点定义。还要记住我们在循环,每次都创建4个顶点,因此我们必须用一个offset变量来旋转合适的顶点:

   int offset = i * 4;

        mo.triangle(offset, offset+3, offset+1);

        mo.triangle(offset, offset+2, offset+3);

   下面旋转我们使用的向量来创建当前的四方形并继续循环,循环结束后我们必须调用 ManualObject::end来完成对象:

    vec = rot * vec;

}

mo.end();

   现在,我们已经定义了手动对象(manual object),可以开始创建我们的StaticGeometry了。最后要做的一件事就是不用ManualObject而创建一个网格,直接渲染网格比使用ManualObject要更好。为此,我们只需要调用ManualObject::convertToMesh用一个名字来保存网格:

   ManualObject::convertToMesh

   我们现在已经完成了场景草坪网格,注意如果你用这个方法创建了一个很复杂的网格,你最好把它保存成文件,然后加载文件而不是每次使用程序时都要重新创建ManualObject。为此我们将获取convertToMesh的返回值并传给它返回给MeshSerializer::exportMesh函数的网格。例如:

   // Do not add to the code!

        Ogre::MeshPtr        ptr = mo.convertToMesh("GrassBladesMesh");

        Ogre::MeshSerializer ser;

        ser.exportMesh(ptr.getPointer(), "grass.mesh");

     我们现在准备要创建StaticGeometry

Adding Static Geometry

   createScene方法已经完成了几件事情,已经添加了创建一个地面(floor plane)、添加一个机器人、设置摄像机位置等功能的代码。现在我们要创建一个基于之前我们创建的草坪网格的实体,和一个StaticGeometry对象。注意我们只创建一个实体来使用我们的StaticGeometry。添加如下代码到createScene方法的末尾:

   Ogre::Entity *grass = mSceneMgr->createEntity("grass", "GrassBladesMesh");

        Ogre::StaticGeometry *sg = mSceneMgr->createStaticGeometry("GrassArea");

        const int size = 375;

        const int amount = 20;

   Size变量定义我们覆盖上草坪的区域的大小,amount变量定义每个StaticGeometry中放多少对象。

   下面定义StaticGeometry的大小和原点,一旦我们创建了对象(调用StaticGeometry::build),就不能再改变StaticGeometry定义的原点或区域了。

   原点就是StaticGeometry定义的区域的左上角,如果你想把StaticGeometry绕一个点放置,你需要设原点的xy坐标为区域的XY大小的一半:

   sg->setRegionDimensions(Ogre::Vector3(size, size, size));

   sg->setOrigin(Ogre::Vector3(-size/2, 0, -size/2));

   这将使该对象以点(0,0,0)为中心,在3D空间中以某一点为中心,你需要这样做:

   // Do not add to the project!

   sg->setOrigin(Vector3(-size/2, -size/2, -size/2) + Vector3(x, y, z));

   还要注意设置区域时,我们定义了对象的垂直高度。确保setRegionDimensionsy轴长度至少和StaticGeometry中最高的对象一样大。

   下面我们要添加对象到StaticGeometry中。下面的代码有点复杂,因为我们要添加一整块草坪到几何体中,并使xz轴的位置随机变化,添加一个随机旋转,添加一个随机垂直缩放。事实上,需要理解的最重要的是StaticGeometry::addEntity:

for (int x = -size/2; x < size/2; x += (size/amount))

{

        for (int z = -size/2; z < size/2; z += (size/amount))

        {

                Ogre::Real r = size / (float)amount / 2;

                Ogre::Vector3 pos(x + Ogre::Math::RangeRandom(-r, r), 0, z + Ogre::Math::RangeRandom(-r, r));

                Ogre::Vector3 scale(1, Ogre::Math::RangeRandom(0.9, 1.1), 1);

                Ogre::Quaternion orientation;

                orientation.FromAngleAxis(Ogre::Degree(Ogre::Math::RangeRandom(0, 359)), Ogre::Vector3::UNIT_Y);

                sg->addEntity(grass, pos, orientation, scale);

        }

}

   addEntity函数接收实体来使用对象的位置、对象的方向、对象的规模(scale)。当你定义StaticGeometry时,不要使用addEntityaddSceneNode函数。The addSceneNode function walks the -SceneNode adding all Entities to the static geometry, using the position, orientation, and scale of the children SceneNodes instead of specifying them manually. 注意使用addSceneNode函数时,确保把该节点从他的父场景节点移除掉,因为addSceneNode 函数不为你做这些。否则OGRE将把StaticGeometry和原来的场景节点都渲染出来,显然这并不是你想要的。

   最后我们需要在StaticGeometry显示之前建立他(build):

   sg->build();

   编译运行程序,你现在可以看到一个机器人站在一块草地上!

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值