11.实现跟随节点的相机.doc

上传人:文库蛋蛋多 文档编号:3018110 上传时间:2023-03-08 格式:DOC 页数:45 大小:316KB
返回 下载 相关 举报
11.实现跟随节点的相机.doc_第1页
第1页 / 共45页
11.实现跟随节点的相机.doc_第2页
第2页 / 共45页
11.实现跟随节点的相机.doc_第3页
第3页 / 共45页
11.实现跟随节点的相机.doc_第4页
第4页 / 共45页
11.实现跟随节点的相机.doc_第5页
第5页 / 共45页
点击查看更多>>
资源描述

《11.实现跟随节点的相机.doc》由会员分享,可在线阅读,更多相关《11.实现跟随节点的相机.doc(45页珍藏版)》请在三一办公上搜索。

1、OSG开源教程整理:荣明、王伟北 京 2008年4月序第一次接触OSG是在2001年,当时开源社区刚刚兴起,还没有现在这么火。下载了OSG源码,但是在看了几个Demo之后,感觉没有什么特别之处。时隔七年之后,我再次将目光投向OSG,发现OSG确实有其独到之处,很多3D效果已经不弱于甚至超过商业软件,有感于开源力量的巨大。但是,与当前主流3D商业软件如Vega、VegaPrime、VTree、Performer等相比,开源软件的缺点也很明显,其中文档缺乏可谓其致命弱点之一。开发者只能从浩瀚的源码中,进行编程的学习,效率不高。OSG组织也意识到这一点,不断推出一些官方教程,网络上有很多OSG爱好者

2、发布的心得和教程。我收集、整理了许多学习资料,其中美国海军研究生院发布的OSG教程非常好,可作为OSG的官方教程的一个很好补充。它共有十一个专题,结合例子程序,一步步教你如何进行OSG的开发。我将其编辑成一个较为完善的教材,供大家学习。在教材整理过程中,王伟调试了源程序,对该书编辑和修订做了大量的工作;实验室的学生杨宇蒙、冯锐、章仕锋、李永川和李益强阅读了本书,并提出了宝贵的修改意见,在此一并表示感谢。希望这本小册子能对大家学习OSG编程起到一定的帮助作用。谢谢大家阅读本书! 荣 明二OO八年四月于崔春园Email:rong_ming(本书的资料全部来自互联网,仅供个人学习交流使用。感谢竹林小

3、舍、array翻译了Navy的教程。)目录1.使用Open Scene Graph几何11.1背景11.2代码12.使用StateSet产生有纹理的几何体42.1本章目标42.2背景42.3加载纹理,生成状态集合并将他们附加到节点上63.使用Shape,改变state83.1本章目标83.2使用Shape类83.3设置状态94.更多的StateSet104.1StateSet如何工作104.2例子及代码105.从文件中加载模型并放入到场景中125.1本章目标125.2加载几何模型并加入到场景中126.osg Text、HUD、RenderBins156.1本章目标156.2摘要156.3代码1

4、57.搜索并控制开关和DOF(自由度)节点(Finding and Manipulating a Switch and DOF Node)207.1搜索场景图形中的一个有名节点207.2按照“访问器”模式搜索有名节点228.使用更新回调来更改模型268.1本章目标268.2回调概览268.3创建一个更新回调269.处理键盘输入299.1本章目标299.2 GUI(图形用户接口)事件处理器:299.3简单的键盘接口类309.4使用键盘接口类329.5处理键盘输入实现更新回调329.5.1本节目标329.5.2问题的提出329.5.3解决方案3310.使用自定义矩阵来放置相机(Positionin

5、g a Camera with a User-Defined Matrix)3610.1本章目标3610.2设置矩阵的方向和位置3610.3声明一个用于设置相机的矩阵3710.4使用矩阵设置视口摄相机3811. 实现跟随节点的相机3811.1本章目标3811.2概述3911.3实现3911.4环绕(始终指向)场景中节点的相机4211.4.1本节目标4211.4.2实现431.使用Open Scene Graph几何本节涵盖了生成基本几何形状的一些方法。生成几何物体的方法有这么几种:在最底层对OpenGL基本几何进行松散的包装,中级是使用Open Scene Graph的基本形状,以及更高级一些

6、的从文件读取。这篇教程涵盖的是最低层的。这种方法弹性最大但最费力。通常在Scene Graph级别,几何形状是从文件加载的。文件加载器完成了跟踪顶点的大部分工作。1.1背景对一下几个类的简单解释:Geode类: geode类继承自node类。在一个Scene Graph中,node(当然包含geode)可以作为叶子节点。Geode实例可以有多个相关的drawable。Drawable类层次: 基类drawable是一个有六个具体子类的抽象类。 geometry类可以直接有vertex和vertex数据,或者任意个primitiveSet实例。 vertex和vertex属性数据(颜色、法线、纹

7、理坐标)存放在数组中。既然多个顶点可以共享相同的颜色、法线或纹理坐标,那么数组索引就可以用来将顶点数组映射到颜色、法线、或纹理坐标数组。PrimitiveSet类: 这个类松散的包装了OpenGL的基本图形POINTS,LINES,LINE_STRIP,LINE_LOOP,.,POLYGON. 1.2代码以下这节代码安装了一个viewer来观察我们创建的场景,一个group实例作为scene graph的根节点,一个几何节点(geode)来收集drawable,和一个geometry实例来关联顶点和顶点数据。(这个例子中渲染的形状是一个四面体).int main() .osgProducer:

8、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);声明一个顶点数组。每个顶点由一个三元组表示

9、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 pyram

10、idVertices-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-setVertex

11、Array( pyramidVertices );下一步,产生一个基本集合并将其加入到pyramid geometry中。使用pyramid的前四个点通过DrawElementsUint类的实例来定义基座。这个类也继承自STL的vector,所以push_back方法会顺序添加元素。为了保证合适的背面剔除,顶点的顺序应当是逆时针方向的。构造器的参数是基本的枚举类型(和opengl的基本枚举类型一致),和起始的顶点数组索引。osg:DrawElementsUInt* pyramidBase = new osg:DrawElementsUInt(osg:PrimitiveSet:QUADS, 0)

12、; 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);

13、 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); pyramidGe

14、ometry-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:DrawElementsUI

15、nt* 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(

16、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声明的这个变量可以将顶点数组元素和颜色数组元素匹配起来。这个容器的元素数应当和顶点数一致。这个容器

17、是顶点数组和颜色数组的连接。这个索引数组中的条目就对应着顶点数组中的元素。他们的值就是颜色数组中的索引。顶点数组元素与normal和纹理坐标数组的匹配也是遵循这种模式。 注意,这种情况下,我们将5个顶点指定4种颜色。顶点数组的0和4元素都被指定为颜色数组的0元素。osg:TemplateIndexArray *colorIndexArray; colorIndexArray = new osg:TemplateIndexArray; colorIndexArray-push_back(0); / vertex 0 assigned color array element 0 colorInde

18、xArray-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关联起来

19、,将上面产生的颜色索引指定给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.

20、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 addChi

21、ld 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 s

22、cene osg:Vec3 pyramidTwoPosition(15,0,0); pyramidTwoXForm-setPosition( pyramidTwoPosition );既然我们生成了一个geometry节点并将它加到了场景中,我们就可以重用这个geometry。例如,如果我们想让另一个pyramid在第一个的右侧15个单位处,我们就可以在我们的scene graph中将这个geode加到transform节点的子节点上。 最后一步,建立并进入一个仿真循环。viewer.setUpViewer(osgProducer:Viewer:STANDARD_SETTINGS); view

23、er.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* cre

24、atePyramid() 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 pyramidVerti

25、ces-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 / g

26、eode 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_ba

27、ck(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; color

28、s-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 *colorIndexAr

29、ray; colorIndexArray = new osg:TemplateIndexArray; 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); / v

30、ertex 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

31、texture coordinates is 1:1, / we dont 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 h

32、ave 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.0

33、f); / 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附加到场景中的一个

34、节点上。前面开始的代码和上一节教程中的一样,初始化一个viewer并建立有一个pyramid的场景。int main() osgProducer:Viewer viewer; / Declare a group to act as root node of a scene: osg:Group* root = new osg:Group(); osg:Geode* pyramidGeode = createPyramid(); root-addChild(pyramidGeode);现在,准备加纹理。这里我们会声明一个纹理实例并将它的数据不一致性设为DYNAMIC。(如果不把纹理声明为dyna

35、mic,osg的一些优化程序会删除它。)这个texture类包装了OpenGL纹理模式(wrap,filter,等等)和一个osg:Image。下面的代码说明了如何从文件里读取osg:Image实例并把这个图像和纹理关联起来。osg:Texture2D* KLN89FaceTexture = new osg:Texture2D; / protect from being optimized away as static state: KLN89FaceTexture-setDataVariance(osg:Object:DYNAMIC); / load an image by reading

36、a file: osg:Image* klnFace = osgDB:readImageFile(KLN89FaceB.tga); if (!klnFace) std:cout couldnt find texture, quiting. setImage(klnFace);纹理可以和渲染StateSet关联起来。下一步就产生一个StateSet,关联并启动我们的纹理,并将这个StateSet附加到我们的geometry上。/ Create a new StateSet with default settings: osg:StateSet* stateOne = new osg:StateS

37、et(); / Assign texture unit 0 of our new StateSet to the texture / we just created and enable the texture. stateOne-setTextureAttributeAndModes(0,KLN89FaceTexture,osg:StateAttribute:ON); / Associate this state set with the Geode that contains / the pyramid: pyramidGeode-setStateSet(stateOne);最后一步是仿真

38、循环:/The final step is to set up and enter a simulation loop. viewer.setUpViewer(osgProducer:Viewer:STANDARD_SETTINGS); viewer.setSceneData( root ); viewer.realize(); while( !viewer.done() ) viewer.sync(); viewer.update(); viewer.frame(); return 0; 3.使用Shape,改变state3.1本章目标用osg:Shape实例构建场景。使用osg:State

39、Set控制shape的渲染。3.2使用Shape类Shape类是所有形状类别的基类。Shape既可用于剪裁和碰撞检测也可用于定义程序性地产生几何体的那些基本形状。下面的类继承自Shape类: TriangleMesh Sphere InfinitePlane HeightField Cylinder Cone CompositeShape Box 为了使这些形状可以被渲染,我们需要把他们和Drawable类的实例关联起来。ShapeDrawable类提供了这样的功能。这个类继承自Drawable并允许我们把Shape实例附加到可以被渲染的东西上。既然ShapeDrawable类继承自Drawa

40、ble,ShapDrawable实例就可以被加到Geode类实例上。下面的步骤演示了将一个单位立方体加到空场景中时是如何做到这些的。/ Declare a group to act as root node of a scene: osg:Group* root = new osg:Group(); / Declare a box class (derived from shape class) instance / This constructor takes an osg:Vec3 to define the center / and a float to define the heigh

41、t, width and depth. / (an overloaded constructor allows you to specify unique / height, width and height values.) osg:Box* unitCube = new osg:Box( osg:Vec3(0,0,0), 1.0f); / Declare an instance of the shape drawable class and initialize / it with the unitCube shape we created above. / This class is d

42、erived from drawable so instances of this / class can be added to Geode instances. osg:ShapeDrawable* unitCubeDrawable = new osg:ShapeDrawable(unitCube); / Declare a instance of the geode class: osg:Geode* basicShapesGeode = new osg:Geode(); / Add the unit cube drawable to the geode: basicShapesGeod

43、e-addDrawable(unitCubeDrawable); / Add the goede to the scene: root-addChild(basicShapesGeode); 产生一个球体和上面的代码基本相似。没有太多的注释的代码看起来是这个样子:/ Create a sphere centered at the origin, unit radius: osg:Sphere* unitSphere = new osg:Sphere( osg:Vec3(0,0,0), 1.0); osg:ShapeDrawable* unitSphereDrawable=new osg:Sha

44、peDrawable(unitSphere); 现在,我们可以使用transform节点将这个球体加到场景中,以便让它离开原点。unitSphereDrawable不能直接添加到场景中(因为它不是继承自node类),所以我们需要一个新的geode以便添加它。osg:PositionAttitudeTransform* sphereXForm = new osg:PositionAttitudeTransform(); sphereXForm-setPosition(osg:Vec3(2.5,0,0); osg:Geode* unitSphereGeode = new osg:Geode();

45、root-addChild(sphereXForm); sphereXForm-addChild(unitSphereGeode); unitSphereGeode-addDrawable(unitSphereDrawable);3.3设置状态前面的教程讲解了如何生成纹理,将其指定为从文件加载的图像,生成一个带纹理的StateSet。下面的代码建立了两个状态集合一个是BLEND纹理模式,另一个是DECAL纹理模式。BLEND模式:/ Declare a state set for BLEND texture mode osg:StateSet* blendStateSet = new osg:StateSet(); / Declare a TexEnv instance, set the mode to BLEND osg:TexEnv* blendTexEnv = new osg:TexEnv; blendTexEnv-setMode(osg:TexEnv:BLEND); / Turn the attribute of texture 0 - the texture we loaded above - ON blendStateSet-se

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教育教学 > 成人教育


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号