您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > 第四章场景的节点与数据结构
65第四章场景的节点与数据结构如果将场景比作房间,那么场景的节点就是房间里的床、桌、灯、柜等设施。著名的3D软件开发工具OpenInventor将应用程序抽象成“ascenegraphplusasetofactions”,所有的图形对象、属性、事件响应全由场景的节点来处理,十分适合于图形的交互式绘制。Intra3D2.0借鉴了OpenInventor的节点设计。本章讲述Intra3D2.0的节点基类、形体节点、相机节点、光源节点和组节点的设计与实现。4.1场景图与节点的概念从数据结构角度讲,场景是一个有向无环图,称为SceneGraph。场景的交互式绘制就是对SceneGraph各个节点的遍历绘制。节点可分为组节点与叶子节点两大类,SceneGraph的根节点总是组节点。以下“伪代码”用于创建图4.1所示的SceneGraph:图4.1SceneGraph的组节点与叶子节点GroupNode*node1=newGroupNode;GroupNode*node2=newGroupNode;GroupNode*node4=newGroupNode;GroupNode*node7=newGroupNode;LeafNode*node3=newLeafNode;LeafNode*node5=newLeafNode;LeafNode*node6=newLeafNode;LeafNode*node8=newLeafNode;LeafNode*node9=newLeafNode;LeafNode*node10=newLeafNode;node1-AddChild(node2);66node1-AddChild(node6);node1-AddChild(node7);node1-AddChild(node9);node1-AddChild(node10);node2-AddChild(node3);node2-AddChild(node4);node4-AddChild(node5);node7-AddChild(node8);如果用深度优先的方法遍历图4.1的SceneGraph,则节点的遍历顺序是1、2、3、4、5、6、7、8、9与10。SceneGrpah中的叶子节点可以被多个组节点引用,如图4.2所示。当SceneGrpah比较复杂时,节点之间的引用关系也变得复杂,因此SceneGrpah需要用“对象引用计数”方法来管理节点的内存(见2.5节)。节点可以显式使用new来创建,但不可显式使用delete删除节点,应该用节点的Release函数。图4.2叶子节点可以被多个组节点引用Intra3D将SceneGraph节点分为组节点(GroupNode),形体节点(ShapeNode),光源节点(DirLightNode、PointLightNode、SpotLightNode)和相机节点(CameraNode)。所有上述节点均从基类节点SceneNode派生。SceneNode节点中定义了坐标系与丰富的3D交互功能。由于C++类支持数据(Data)和代码(Implementation)的继承,SceneNode节点功能可以被派生类节点继承。但是COM对象仅支持接口继承(本质上是继承虚函数的声明),不支持数据和代码的继承。只能在派生节点中包容ISceneNode并将ISceneNode的函数重新封装为当前节点的函数。COM库中的节点程序要比C++类库的复杂,4.3节将以ShapeNode为例分别论述类与COM对象的程序设计。相机是否该成为一种节点是值得商讨的话题。直观地讲,相机等同于观察者的眼睛,的确不是场景的组成部分。如果应用程序不涉及相机的交互,那么只需调用OpenGL的几个投影函数就可以实现图形学概念中的相机变换(请参考Intra3D的Window3D程序)。如果应用程序涉及复杂的相机交互,例如多个相机的切换,场景的漫游;此时将相67机作为节点插入SceneGraph中,可以享用到在SceneNode定义的交互功能(请参考Intra3D的SceneView程序)。使用了相机节点的SceneView程序要比不使用相机节点的Window3D程序复杂。4.2场景节点的基类C++类库中的SceneNode程序见Intra3D-DLL\Include\Layer3\SceneNode.h和Intra3D-DLL\Layer3\SceneNode.cpp。COM库的程序见Intra3D-COM\Layer3\SceneNode.h和SceneNode.cpp。本节主要论述类SceneNode的设计。SceneNode为场景的交互式绘制提供了两大功能:一是坐标系统的定义与图形变换;二是节点的拾取与绘制。类SceneNode是Container的公有派生类,其数据结构并不复杂,但运算函数较多。其主要数据成员如下:protected:SceneNode*m_pParent;charm_strNodeName[32];VECTORm_position,m_oldPosition;ROTATIONm_rotation,m_oldRotation;VECTORm_scale,m_oldScale;Trackballm_trackball;//跟踪球BOOLm_bSelected;//当前节点被拾取的标志4.2.1坐标系统的定义与图形变换每个节点都有标定自己的坐标系,称为对象坐标系(ObjectCoordinateSystem)。在2.1节已经论述了可用旋转结构(ROTATION)、平移矢量、比例矢量来确定图形变换的状态与过程。m_position、m_rotation与m_scale三个量分别表示该节点在父节点坐标系中的位置量、旋转量与比例量,执行节点的图形变换函数将改变上述量。m_oldPosition、m_odlRotation与m_oldScale用于记录原始状态,便于恢复。节点的相互连接构成了SceneGraph,为了有统一的参照系,把SceneGraph的根节点的坐标系称为世界坐标系(WorldCoordinateSystem)。场景最后投影到窗口中,即执行了相机变换。观察者用鼠标对场景节点直接拖动、旋转等操作,实质是执行了相机坐标系(CameraCoordinateSystem)的图形变换。因此场景的3D交互包含了节点在对象坐标系与相机坐标系的图形变换。用于定义坐标系统与图形变换的主要函数有:public://定义坐标系统的函数voidSetPosition(floatx,floaty,floatz);voidSetRotation(floatangle,floatnx,floatny,floatnz);voidSetScale(floatsx,floatsy,floatsz);//对象坐标系的图形变换函数68voidTranslate(VECTORtrans);voidRotate(floatangle,VECTORaxis);voidScale(floatsx,floatsy,floatsz);virtualvoidResetTransform(void);//相机坐标系的图形变换函数voidTranslateInCamera(VECTORtrans);voidRotateInCamera(floatangle,VECTORaxis);voidMouseTrackStart(intiViewportWidth,intiViewportHeight,intmx,intmy);voidMouseTracking(intdx,intdy);protected://FWTO:FromWorldCoordinateToObjectCoordinate//FOTW:FromObjectCoordinateToWorldCoordinate//FCTO:FromCameraToCoordinateObjectCoordinate//FOTC:FromObjectCoordinateToCameraCoordinate//对象坐标系、世界坐标系、相机坐标系之间的顶点换算voidVertexTransform_FWTO(float*x,float*y,float*z);voidVertexTransform_FOTW(float*x,float*y,float*z);voidVertexTransform_FCTO(float*x,float*y,float*z);voidVertexTransform_FOTC(float*x,float*y,float*z);//对象坐标系、世界坐标系、相机坐标系之间的矢量换算voidVectorTransform_FWTO(VECTOR*V);voidVectorTransform_FOTW(VECTOR*V);voidVectorTransform_FCTO(VECTOR*V);voidVectorTransform_FOTC(VECTOR*V);函数SetPosition、SetRotation与SetScale用于设置该节点在父节点坐标系中的位置量、旋转量与比例量。voidSceneNode::SetPosition(floatx,floaty,floatz){m_position.x=x;m_position.y=y;m_position.z=z;m_oldPosition=m_position;//记录原始状态}voidSceneNode::SetRotation(floatangle,floatnx,floatny,floatnz){m_rotation.angle=angle;m_rotation.axis.x=nx;m_rotation.axis.y=ny;m_rotation.axis.z=nz;69VectorNormalize(&m_rotation.axis);m_oldRotation=m_rotation;//记录原始状态}voidSceneNode::SetScale(floatsx,floatsy,floatsz){m_scale.x=sx;m_scale.y=sy;m_scale.z=sz;m_oldScale=m_scale;//记录原始状态}函数Translate、Rotate与Scale用于实现对象坐标系中的平移变换、旋转变换与比例变换。ResetTransform函数用于恢复原始状态。voidSceneNode::Translate(VECTORtrans){//注意理解为什么要用VectorTransformtrans=VectorTransform(trans,m_rotation);//见Rotation.hm_position.x+=trans.x;m_position.y+=trans.y;m_position.z+=trans.z;}voidSceneNode::Rotate(floatangle,VECTORaxis){ROTATIONR(axis,angle);VectorNormalize(&R.axis);//注意理解为什么要用VectorTransformR.axis=VectorTransform(R.axis,m_rotation);m_rotation=m_rotation*R;//见Rotation.h}voidSceneNode::Scale(floatsx,floatsy,floatsz){m_scale.x*=sx;m_scale.y*=sy;m_scale.z*=sz;}voidSceneNode::ResetTransform(void){//恢复初始状态m_position=m_oldPosition;m_rotation=m_oldRotation;m_scale=m_oldScale;70}TranslateInCamera与RotateInCamera是相机坐标系的平移变换与旋转变换函数。Mou
本文标题:第四章场景的节点与数据结构
链接地址:https://www.777doc.com/doc-2168762 .html