声明一个顶点数组。每个顶点由一个三元组表示一一vc3类的实例。这些三元组用 osg:Vec3 Array类的实例存贮。既然osg:Vec3 Array继承自STL的vector类,那么我们就可以使 用push_back方法来添加数组成员。push back将元素加到向量的尾端,因此第一个元素的索引是 0,第二个是1,依此类推。 使用‘z’轴向上的右手坐标系系统,下面的0..4数组元素代表着产生一个简单锥体所需的5 个点。 osg:Vec3Array*pyramidVertices new osg:Vec3Array; pyramidVertices->push_back(osg:Vec3(0,0,0));//front left pyramidVertices->push_back(osg:Vec3(10,0,0));//front right pyramidVertices->push_back(osg:Vec3(10,10,0));//back right pyramidVertices->push_back(osg:Vec3(0,10,0));//back left pyramidVertices->push_back(osg:Vec3(5,5,10));//peak 将这个顶点集合和与我们加到场景中的geode相关的geometry关联起来。 pyramidGeometry->setVertexArray(pyramidVertices ) 下一步,产生一个基本集合并将其加入到pyramid geometry中。使用pyramid的前四个点通过 DrawElementsUint类的实例来定义基座。这个类也继承自STL的vector,所以push_back方法会 顺序添加元素。为了保证合适的背面剔除,顶点的顺序应当是逆时针方向的。构造器的参数是基本 的枚举类型(和opengl的基本枚举类型一致),和起始的顶点数组索引。 osg:DrawElementsUInt*pyramidBase new osg:DrawElementsUInt (osg:PrimitiveSet:QUADS,0); pyramidBase->push back(3); pyramidBase->push_back(2); pyramidBase->push_back(1); pyramidBase->push_back(0); pyramidGeometry->addPrimitiveSet(pyramidBase); 对每个面重复相同的动作。顶点仍要按逆时针方向指定。 osg:DrawElementsUInt*pyramidFaceOne new osg:DrawElementsUInt (osg:PrimitiveSet:TRIANGLES,0); pyramidFaceOne->push_back(0); pyramidFaceOne->push_back(1); pyramidFaceOne->push_back(4): pyramidGeometry->addPrimitiveSet(pyramidFaceOne); osg:DrawElementsUInt*pyramidFaceTwo new osg:DrawElementsUInt (osg:PrimitiveSet:TRIANGLES,0); pyramidFaceTwo->push_back(1); pyramidFaceTwo->push_back(2); pyramidFaceTwo->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceTwo); osg:DrawElementsUInt*pyramidFaceThree new osg:DrawElementsUInt (osg:PrimitiveSet:TRIANGLES,0); pyramidFaceThree->push_back(2); pyramidFaceThree->push_back(3);
2 声 明 一 个 顶 点 数 组 。 每 个 顶 点 由 一 个 三 元 组 表 示 ——vec3 类 的 实 例 。 这 些 三 元 组 用 osg::Vec3Array 类的实例存贮。既然 osg::Vec3Array 继承自 STL 的 vector 类,那么我们就可以使 用 push_back 方法来添加数组成员。push_back 将元素加到向量的尾端,因此第一个元素的索引是 0,第二个是 1,依此类推。 使用‘z’轴向上的右手坐标系系统,下面的 0...4 数组元素代表着产生一个简单锥体所需的 5 个点。 osg::Vec3Array* pyramidVertices = new osg::Vec3Array; pyramidVertices->push_back( osg::Vec3( 0, 0, 0) ); // front left pyramidVertices->push_back( osg::Vec3(10, 0, 0) ); // front right pyramidVertices->push_back( osg::Vec3(10,10, 0) ); // back right pyramidVertices->push_back( osg::Vec3( 0,10, 0) ); // back left pyramidVertices->push_back( osg::Vec3( 5, 5,10) ); // peak 将这个顶点集合和与我们加到场景中的 geode 相关的 geometry 关联起来。 pyramidGeometry->setVertexArray( pyramidVertices ); 下一步,产生一个基本集合并将其加入到 pyramid geometry 中。使用 pyramid 的前四个点通过 DrawElementsUint 类的实例来定义基座。这个类也继承自 STL 的 vector,所以 push_back 方法会 顺序添加元素。为了保证合适的背面剔除,顶点的顺序应当是逆时针方向的。构造器的参数是基本 的枚举类型(和 opengl 的基本枚举类型一致),和起始的顶点数组索引。 osg::DrawElementsUInt* pyramidBase = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); pyramidBase->push_back(3); pyramidBase->push_back(2); pyramidBase->push_back(1); pyramidBase->push_back(0); pyramidGeometry->addPrimitiveSet(pyramidBase); 对每个面重复相同的动作。顶点仍要按逆时针方向指定。 osg::DrawElementsUInt* pyramidFaceOne = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); pyramidFaceOne->push_back(0); pyramidFaceOne->push_back(1); pyramidFaceOne->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceOne); osg::DrawElementsUInt* pyramidFaceTwo = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); pyramidFaceTwo->push_back(1); pyramidFaceTwo->push_back(2); pyramidFaceTwo->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceTwo); osg::DrawElementsUInt* pyramidFaceThree = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); pyramidFaceThree->push_back(2); pyramidFaceThree->push_back(3);
pyramidFaceThree->push back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceThree); osg:DrawElementsUInt*pyramidFaceFour new osg:DrawElementsUInt(osg:PrimitiveSet:TRIANGLES,0); pyramidFaceFour->push_back(3); pyramidFaceFour->push_back(0); pyramidFaceFour->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceFour) 声明并加载一个vec4为元素的数组来存储颜色。 osg:Vec4Array*colors new osg:Vec4Array; colors->push_back(osg:Vec4(1.Of,0.Of,0.Of,1.0f));//index 0 red colors->push_back(osg:Vec4(0.Of,1.0f,0.Of,1.0f))://index 1 green colors->push_back(osg:Vec4(0.Of,0.Of,1.Of,1.0f));//index 2 blue colors->push_back(osg:Vec4(1.0f,1.0f,1.0f,1.0f));//index 3 white 声明的这个变量可以将顶点数组元素和颜色数组元素匹配起来。这个容器的元素数应当和顶点数 致。这个容器是顶点数组和颜色数组的连接。这个索引数组中的条目就对应着顶点数组中的元素。 他们的值就是颜色数组中的索引。顶点数组元素与normal和纹理坐标数组的匹配也是遵循这种模 式。 注意,这种情况下,我们将5个顶点指定4种颜色。顶点数组的0和4元素都被指定为颜色数组 的0元素。 osg:TemplateIndexArray <unsigned int,osg:Array:UIntArrayType,4,4>*colorIndexArray; colorIndexArray new osg:TemplateIndexArray<unsigned int,osg:Array:UIntArrayType,4,4>; colorIndexArray->push_back(0);//vertex 0 assigned color array element 0 colorIndexArray->push_back(1);//vertex 1 assigned color array element 1 colorIndexArray->push_back(2);//vertex 2 assigned color array element 2 colorIndexArray->push_back(3);//vertex 3 assigned color array element 3 colorIndexArray->push_back(0);//vertex 4 assigned color array element 0 下一步,将颜色数组和geometry关联起来,将上面产生的颜色索引指定给geometry,设定绑定 模式为PER_VERTEX。 pyramidGeometry->setColorArray(colors); pyramidGeometry->setColorIndices(colorIndexArray); pyramidGeometry->setColorBinding(osg:Geometry:BIND_PER_VERTEX); osg:Vec2Array*texcoords new osg:Vec2Array(5); (*texcoords)[0].set(0.00f,0.Of); (*texcoords)[1].set(0.25f,0.Of); (*texcoords)[2].set(0.50f,0.0f); (*texcoords)[3].set(0.75f,0.0f); (*texcoords)[4].set (0.50f,1.Of); pyramidGeometry->setTexCoordArray(0,texcoords); 注:一下部分可能错误
3 pyramidFaceThree->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceThree); osg::DrawElementsUInt* pyramidFaceFour = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); pyramidFaceFour->push_back(3); pyramidFaceFour->push_back(0); pyramidFaceFour->push_back(4); pyramidGeometry->addPrimitiveSet(pyramidFaceFour) 声明并加载一个 vec4 为元素的数组来存储颜色。 osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) ); //index 0 red colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) ); //index 1 green colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); //index 2 blue colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 3 white 声明的这个变量可以将顶点数组元素和颜色数组元素匹配起来。这个容器的元素数应当和顶点数 一致。这个容器是顶点数组和颜色数组的连接。这个索引数组中的条目就对应着顶点数组中的元素。 他们的值就是颜色数组中的索引。顶点数组元素与 normal 和纹理坐标数组的匹配也是遵循这种模 式。 注意,这种情况下,我们将 5 个顶点指定 4 种颜色。顶点数组的 0 和 4 元素都被指定为颜色数组 的 0 元素。 osg::TemplateIndexArray <unsigned int, osg::Array::UIntArrayType,4,4> *colorIndexArray; colorIndexArray = new osg::TemplateIndexArray<unsigned int, osg::Array::UIntArrayType,4,4>; colorIndexArray->push_back(0); // vertex 0 assigned color array element 0 colorIndexArray->push_back(1); // vertex 1 assigned color array element 1 colorIndexArray->push_back(2); // vertex 2 assigned color array element 2 colorIndexArray->push_back(3); // vertex 3 assigned color array element 3 colorIndexArray->push_back(0); // vertex 4 assigned color array element 0 下一步,将颜色数组和 geometry 关联起来,将上面产生的颜色索引指定给 geometry,设定绑定 模式为_PER_VERTEX。 pyramidGeometry->setColorArray(colors); pyramidGeometry->setColorIndices(colorIndexArray); pyramidGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); osg::Vec2Array* texcoords = new osg::Vec2Array(5); (*texcoords)[0].set(0.00f,0.0f); (*texcoords)[1].set(0.25f,0.0f); (*texcoords)[2].set(0.50f,0.0f); (*texcoords)[3].set(0.75f,0.0f); (*texcoords)[4].set(0.50f,1.0f); pyramidGeometry->setTexCoordArray(0,texcoords); 注:一下部分可能错误
/Declare and initialize a transform node. osg:PositionAttitudeTransform*pyramidTwoXForm new osg:PositionAttitudeTransform(); /Use the 'addChild'method of the osg:Group class to /add the transform as a child of the root node and the /pyramid node as a child of the transform. root->addChild(pyramidTwoXForm): pyramidTwoXForm->addChild(pyramidGeode); /Declare and initialize a Vec3 instance to change the /position of the tank model in the scene osg:Vec3 pyramidTwoPosition(15,0,0); pyramidTwoXForm->setPosition(pyramidTwoPosition ) 既然我们生成了一个geometry节点并将它加到了场景中,我们就可以重用这个geometry。.例如, 如果我们想让另一个pyramid在第一个的右侧l5个单位处,我们就可以在我们的scene graph中 将这个geode加到transform节点的子节点上。 最后一步,建立并进入一个仿真循环。 viewer.setUpViewer(osgProducer:Viewer:STANDARD_SETTINGS); viewer.setSceneData(root ) viewer.realize(); while(!viewer.done()) { viewer.sync(); viewer.update(); viewer.frame(); 2.使用StateSet产生有纹理的几何体 2.1本章目标 为教程1中介绍的由OpenGL基本绘制单位定义的几何体添加纹理。 2.2背景 前一节教程介绍了包含由OpenGL基本单位产生的基本形状的视景。本节讲解如何为这些形状 添加纹理。为了使代码更方便使用,我们将pyramid的代码放到一个函数中,产生geode并返回它 的指针。下面的代码来自教程1。 osg:Geode*createPyramid()
4 // Declare and initialize a transform node. osg::PositionAttitudeTransform* pyramidTwoXForm = new osg::PositionAttitudeTransform(); // Use the 'addChild' method of the osg::Group class to // add the transform as a child of the root node and the // pyramid node as a child of the transform. root->addChild(pyramidTwoXForm); pyramidTwoXForm->addChild(pyramidGeode); // Declare and initialize a Vec3 instance to change the // position of the tank model in the scene osg::Vec3 pyramidTwoPosition(15,0,0); pyramidTwoXForm->setPosition( pyramidTwoPosition ); 既然我们生成了一个 geometry 节点并将它加到了场景中,我们就可以重用这个 geometry。例如, 如果我们想让另一个 pyramid 在第一个的右侧 15 个单位处,我们就可以在我们的 scene graph 中 将这个 geode 加到 transform 节点的子节点上。 最后一步,建立并进入一个仿真循环。 viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); viewer.setSceneData( root ); viewer.realize(); while( !viewer.done() ) { viewer.sync(); viewer.update(); viewer.frame(); } 2.使用 StateSet 产生有纹理的几何体 2.1 本章目标 为教程 1 中介绍的由 OpenGL 基本绘制单位定义的几何体添加纹理。 2.2 背景 前一节教程介绍了包含由 OpenGL 基本单位产生的基本形状的视景。本节讲解如何为这些形状 添加纹理。为了使代码更方便使用,我们将 pyramid 的代码放到一个函数中,产生 geode 并返回它 的指针。下面的代码来自教程 1。 osg::Geode* createPyramid() {
osg:Geode*pyramidGeode new osg:Geode(); osg:Geometry*pyramidGeometry new osg:Geometry(); pyramidGeode->addDrawable(pyramidGeometry); //Specify the vertices: osg:Vec3Array*pyramidVertices new osg:Vec3Array: pyramidVertices->push_back(osg:Vec3(0,0,0));//front left pyramidVertices->push_back(osg:Vec3(2,0,0))://front right pyramidVertices->push_back(osg:Vec3(2,2,0));//back right pyramidVertices->push_back(osg:Vec3(0,2,0))://back left pyramidVertices->push_back(osg:Vec3(1,1,2))://peak /Associate this set of vertices with the geometry associated with the /geode we added to the scene. pyramidGeometry->setVertexArray(pyramidVertices ) /Create a QUAD primitive for the base by specifying the /vertices from our vertex list that make up this QUAD: osg:DrawElementsUInt*pyramidBase new osg:DrawElementsUInt (osg:PrimitiveSet:QUADS,0); pyramidBase->push_back(3); pyramidBase->push_back(2); pyramidBase->push_back(1); pyramidBase->push_back(0); //Add this primitive to the geometry: pyramidGeometry->addPrimitiveSet(pyramidBase); /code to create other faces goes here! //(removed to save space,see tutorial two) osg:Vec4Array*colors new osg:Vec4Array; colors->push_back(osg:Vec4(1.0f,0.Of,0.0f,1.0f));//index 0 red colors->push_back(osg:Vec4(0.Of,1.0f,0.Of,1.0f));//index 1 green colors->push_back (osg:Vec4(0.0f,0.Of,1.0f,1.0f));//index 2 blue colors->push_back(osg:Vec4(1.Of,1.0f,1.Of,1.0f));//index 3 white osg:TemplatelndexArray <unsigned int,osg:Array:UIntArrayType,4,4>*colorIndexArray; colorIndexArray new osg:TemplateIndexArray<unsigned int,osg:Array:UIntArrayType,4,4>; colorIndexArray->push_back(0);//vertex 0 assigned color array element 0
5 osg::Geode* pyramidGeode = new osg::Geode(); osg::Geometry* pyramidGeometry = new osg::Geometry(); pyramidGeode->addDrawable(pyramidGeometry); // Specify the vertices: osg::Vec3Array* pyramidVertices = new osg::Vec3Array; pyramidVertices->push_back( osg::Vec3(0, 0, 0) ); // front left pyramidVertices->push_back( osg::Vec3(2, 0, 0) ); // front right pyramidVertices->push_back( osg::Vec3(2, 2, 0) ); // back right pyramidVertices->push_back( osg::Vec3( 0,2, 0) ); // back left pyramidVertices->push_back( osg::Vec3( 1, 1,2) ); // peak // Associate this set of vertices with the geometry associated with the // geode we added to the scene. pyramidGeometry->setVertexArray( pyramidVertices ); // Create a QUAD primitive for the base by specifying the // vertices from our vertex list that make up this QUAD: osg::DrawElementsUInt* pyramidBase = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); pyramidBase->push_back(3); pyramidBase->push_back(2); pyramidBase->push_back(1); pyramidBase->push_back(0); //Add this primitive to the geometry: pyramidGeometry->addPrimitiveSet(pyramidBase); // code to create other faces goes here! // (removed to save space, see tutorial two) osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) ); //index 0 red colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) ); //index 1 green colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); //index 2 blue colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 3 white osg::TemplateIndexArray <unsigned int, osg::Array::UIntArrayType,4,4> *colorIndexArray; colorIndexArray = new osg::TemplateIndexArray<unsigned int, osg::Array::UIntArrayType,4,4>; colorIndexArray->push_back(0); // vertex 0 assigned color array element 0
colorIndexArray->push_back(1);//vertex 1 assigned color array element 1 colorIndexArray->push_back(2)://vertex 2 assigned color array element 2 colorIndexArray->push_back(3);//vertex 3 assigned color array element 3 colorIndexArray->push back(0);/vertex 4 assigned color array element 0 pyramidGeometry->setColorArray(colors): pyramidGeometry->setColorIndices(colorIndexArray); pyramidGeometry->setColorBinding(osg:Geometry:BIND_PER_VERTEX); /Since the mapping from vertices to texture coordinates is 1:1, /we don't need to use an index array to map vertices to texture /coordinates.We can do it directly with the 'setTexCoordArray' /method of the Geometry class. /This method takes a variable that is an array of two dimensional /vectors (osg:Vec2).This variable needs to have the same /number of elements as our Geometry has vertices.Each array element /defines the texture coordinate for the cooresponding vertex in the /vertex array. osg:Vec2Array*texcoords new osg:Vec2Array (5); (*texcoords)[0].set(0.00f,0.0f);/tex coord for vertex 0 (*texcoords)[1].set(0.25f,0.0f);//tex coord for vertex I (*texcoords))[2].set(0.50f,0.0f):/"” (*texcoords)[3].set(0.75f,0.Of);//"" (*texcoords)[4].set(0.50f,1.0f);//"" pyramidGeometry->setTexCoordArray(0,texcoords); return pyramidGeode; 2.3加载纹理,生成状态集合并将他们附加到节点上 渲染基本单位的方法是使用StateSet.。这节代码演示了怎样从文件中加载纹理,产生此纹理起 作用的一个StateSet,.并将这个StateSet附加到场景中的一个节点上。前面开始的代码和上一节 教程中的一样,初始化一个viewer并建立有一个pyramid的场景。 int main() { osgProducer:Viewer viewer; /Declare a group to act as root node of a scene: osg:Group*root new osg:Group(); 6
6 colorIndexArray->push_back(1); // vertex 1 assigned color array element 1 colorIndexArray->push_back(2); // vertex 2 assigned color array element 2 colorIndexArray->push_back(3); // vertex 3 assigned color array element 3 colorIndexArray->push_back(0); // vertex 4 assigned color array element 0 pyramidGeometry->setColorArray(colors); pyramidGeometry->setColorIndices(colorIndexArray); pyramidGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); // Since the mapping from vertices to texture coordinates is 1:1, // we don't need to use an index array to map vertices to texture // coordinates. We can do it directly with the 'setTexCoordArray' // method of the Geometry class. // This method takes a variable that is an array of two dimensional // vectors (osg::Vec2). This variable needs to have the same // number of elements as our Geometry has vertices. Each array element // defines the texture coordinate for the cooresponding vertex in the // vertex array. osg::Vec2Array* texcoords = new osg::Vec2Array(5); (*texcoords)[0].set(0.00f,0.0f); // tex coord for vertex 0 (*texcoords)[1].set(0.25f,0.0f); // tex coord for vertex 1 (*texcoords)[2].set(0.50f,0.0f); // "" (*texcoords)[3].set(0.75f,0.0f); // "" (*texcoords)[4].set(0.50f,1.0f); // "" pyramidGeometry->setTexCoordArray(0,texcoords); return pyramidGeode; } 2.3 加载纹理,生成状态集合并将他们附加到节点上 渲染基本单位的方法是使用 StateSet。这节代码演示了怎样从文件中加载纹理,产生此纹理起 作用的一个 StateSet,并将这个 StateSet 附加到场景中的一个节点上。前面开始的代码和上一节 教程中的一样,初始化一个 viewer 并建立有一个 pyramid 的场景。 int main() { osgProducer::Viewer viewer; // Declare a group to act as root node of a scene: osg::Group* root = new osg::Group();