我要发帖 回复

管理员

735

主题

2万

积分

30

专家分

忠于职守杰出贡献鼓励

兴趣点(最多三项):

建模技术

私信
发表时间 : 2007-11-23 12:59:49 | 浏览 : 5239    评论 : 7
译者:竹林小舍




原文出处:http://www.nps.navy.mil/cs/sullivan/osgtutorials/osgGeometry.htm
摘要

本节涵盖了生成基本几何形状的一些方法。生成几何物体的方法有这么几种:在最底层对OpenGL基本几何进行松散的包装,中级是使用Open Scene Graph的基本形状,以及更高级一些的从文件读取。这篇教程涵盖的是最低层的。这种方法弹性最大但最费力。通常在Scene Graph级别,几何形状是从文件加载的。文件加载器完成了跟踪顶点的大部分工作。

背景

对一下几个类的简单解释:

Geode类:

geode
类继承自node类。在一个Scene Graph中,node(当然包含geode)可以作为叶子节点。Geode实例可以有多个相关的drawable。

Drawable类层次


基类drawable是一个有六个具体子类的抽象类。


geometry
类可以直接有vertex和vertex数据,或者任意个primitiveSet实例。


vertex
和vertex属性数据(颜色、法线、纹理坐标)存放在数组中。既然多个顶点可以共享相同的颜色、法线或纹理坐标,那么数组索引就可以用来将顶点数组映射到颜色、法线、或纹理坐标数组。

PrimitiveSet类:

这个类松散的包装了OpenGL的基本图形-POINTS,LINES,LINE_STRIP,LINE_LOOP,...,POLYGON.

代码

以下这节代码安装了一个viewer来观察我们创建的场景,一个‘group’实例作为scene graph的根节点,一个几何节点(geode)来收集drawable,和一个geometry实例来关联顶点和顶点数据。(这个例子中渲染的形状是一个四面体)


...


int main()


{


...


osgProducer::Viewer viewer;


osg::Group* root = new osg::Group();


osg::Geode* pyramidGeode = new osg::Geode();


osg::Geometry* pyramidGeometry = new osg::Geometry();


下一步,需要将锥体geometry和锥体geode关联起来,并将pyramid geode加到scene graph的根节点上。


pyramidGeode->addDrawable(pyramidGeometry);


root->addChild(pyramidGeode);



声明一个顶点数组。每个顶点由一个三元组表示——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.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。

// 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();


}




好运气!

掉了一段:下一步,将颜色数组和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);



[ 本帖最后由 obuil 于 2007-11-23 01:45 PM 编辑 ]

最近VR访客

子ぺ木 评论于2007-12-1 15:57:01
狂顶啊
linsua 评论于2008-1-5 21:26:10
原帖由 子ぺ木 于 2007-12-1 03:57 PM 发表
狂顶啊

灌水吗?
jungle_shaw 评论于2008-1-23 20:57:22

回复 #1 obuil 的帖子

谢谢!
seven0610 评论于2008-1-23 22:18:48
老大就是好人啊  

就是要看看这些底层的东西
yingzi_zxp 评论于2008-5-2 17:34:34
学习了
lzs4073 评论于2008-7-12 10:38:20
不错啊
Sailent 评论于2008-7-21 10:00:35
viewer.sync()和viewer.update();这两个函数哪来的啊?我编译的时候说sync()和update() “is not a member of 'osgViewer::Viewer'”。我用的是OSG2.4,应该不会是版本太低吧

手机版|VR开发网 统计 津ICP备18009691号
网安备12019202000257

GMT+8, 2021-4-21 01:02 PM

返回顶部