1、新版第四章场景的节点与数据结构课件doc第四章 场景的节点与数据结构 如果将场景比作房间,那么场景的节点就是房间里的床、桌、灯、柜等设施。著名的3D软件开发工具Open Inventor将应用程序抽象成“a scene graph plus a set of actions”,所有的图形对象、属性、事件响应全由场景的节点来处理,十分适合于图形的交互式绘制。Intra3D 2.0借鉴了Open Inventor的节点设计。本章讲述Intra3D 2.0的节点基类、形体节点、相机节点、光源节点和组节点的设计与实现。4.1 场景图与节点的概念从数据结构角度讲,场景是一个有向无环图,称为Scene G
2、raph。场景的交互式绘制就是对Scene Graph各个节点的遍历绘制。节点可分为组节点与叶子节点两大类,Scene Graph的根节点总是组节点。以下“伪代码”用于创建图4.1所示的Scene Graph :图4.1 Scene Graph 的组节点与叶子节点 GroupNode *node1 = new GroupNode ; GroupNode *node2 = new GroupNode ; GroupNode *node4 = new GroupNode ; GroupNode *node7 = new GroupNode ; LeafNode *node3 = new LeafN
3、ode ; LeafNode *node5 = new LeafNode ; LeafNode *node6 = new LeafNode ; LeafNode *node8 = new LeafNode ; LeafNode *node9 = new LeafNode ; LeafNode *node10 = new LeafNode ; node1-AddChild(node2); node1-AddChild(node6); node1-AddChild(node7); node1-AddChild(node9); node1-AddChild(node10); node2-AddChi
4、ld(node3); node2-AddChild(node4); node4-AddChild(node5); node7-AddChild(node8); 如果用深度优先的方法遍历图4.1的Scene Graph,则节点的遍历顺序是1、2、3、4、5、6、7、8、9与10。 Scene Grpah 中的叶子节点可以被多个组节点引用,如图4.2所示。当Scene Grpah比较复杂时,节点之间的引用关系也变得复杂,因此Scene Grpah需要用“对象引用计数”方法来管理节点的内存(见2.5节)。节点可以显式使用new来创建,但不可显式使用delete删除节点,应该用节点的Release函数
5、。图4.2 叶子节点可以被多个组节点引用 Intra3D 将Scene Graph节点分为组节点(GroupNode),形体节点(ShapeNode),光源节点(DirLightNode、PointLightNode、SpotLightNode)和相机节点(CameraNode)。所有上述节点均从基类节点SceneNode派生。SceneNode节点中定义了坐标系与丰富的3D交互功能。由于C+类支持数据(Data)和代码(Implementation)的继承,SceneNode节点功能可以被派生类节点继承。但是COM对象仅支持接口继承(本质上是继承虚函数的声明),不支持数据和代码的继承。只能在
6、派生节点中包容ISceneNode并将ISceneNode的函数重新封装为当前节点的函数。COM库中的节点程序要比C+类库的复杂,4.3节将以ShapeNode为例分别论述类与COM对象的程序设计。 相机是否该成为一种节点是值得商讨的话题。直观地讲,相机等同于观察者的眼睛,的确不是场景的组成部分。如果应用程序不涉及相机的交互,那么只需调用OpenGL的几个投影函数就可以实现图形学概念中的相机变换(请参考 Intra3D 的Window3D程序)。如果应用程序涉及复杂的相机交互,例如多个相机的切换,场景的漫游;此时将相机作为节点插入Scene Graph中,可以享用到在SceneNode定义的交
7、互功能(请参考 Intra3D 的SceneView程序)。使用了相机节点的SceneView程序要比不使用相机节点的 Window3D程序复杂。4.2 场 景 节 点 的 基 类C+类库中的SceneNode程序见Intra3D-DLLIncludeLayer3SceneNode.h和Intra3D-DLLLayer3SceneNode.cpp。COM库的程序见Intra3D-COMLayer3SceneNode.h和SceneNode.cpp。本节主要论述类SceneNode的设计。SceneNode为场景的交互式绘制提供了两大功能:一是坐标系统的定义与图形变换;二是节点的拾取与绘制。类S
8、ceneNode是Container的公有派生类,其数据结构并不复杂,但运算函数较多。其主要数据成员如下:protected: SceneNode *m_pParent ; char m_strNodeName32 ; VECTOR m_position, m_oldPosition ; ROTATION m_rotation, m_oldRotation ; VECTOR m_scale, m_oldScale ; Trackball m_trackball ; / 跟踪球 BOOL m_bSelected ; / 当前节点被拾取的标志4.2.1 坐标系统的定义与图形变换每个节点都有标定自己
9、的坐标系,称为对象坐标系(Object Coordinate System)。在2.1节已经论述了可用旋转结构(ROTATION)、平移矢量、比例矢量来确定图形变换的状态与过程。m_position、m_rotation与m_scale三个量分别表示该节点在父节点坐标系中的位置量、旋转量与比例量,执行节点的图形变换函数将改变上述量。m_oldPosition、 m_odlRotation与m_oldScale用于记录原始状态,便于恢复。节点的相互连接构成了Scene Graph,为了有统一的参照系,把Scene Graph的根节点的坐标系称为世界坐标系(World Coordinate Sys
10、tem)。场景最后投影到窗口中,即执行了相机变换。观察者用鼠标对场景节点直接拖动、旋转等操作,实质是执行了相机坐标系(Camera Coordinate System)的图形变换。因此场景的3D交互包含了节点在对象坐标系与相机坐标系的图形变换。用于定义坐标系统与图形变换的主要函数有: public: / 定义坐标系统的函数 void SetPosition(float x, float y, float z); void SetRotation(float angle, float nx, float ny, float nz); void SetScale(float sx, float s
11、y, float sz); / 对象坐标系的图形变换函数 void Translate(VECTOR trans);void Rotate(float angle, VECTOR axis); void Scale(float sx, float sy, float sz); virtual void ResetTransform(void); / 相机坐标系的图形变换函数 void TranslateInCamera(VECTOR trans); void RotateInCamera(float angle, VECTOR axis); void MouseTrackStart(int i
12、ViewportWidth, int iViewportHeight, int mx, int my); void MouseTracking(int dx, int dy); protected: / FWTO : From World Coordinate To Object Coordinate / FOTW : From Object Coordinate To World Coordinate / FCTO : From Camera To Coordinate Object Coordinate / FOTC : From Object Coordinate To Camera C
13、oordinate / 对象坐标系、世界坐标系、相机坐标系之间的顶点换算 void VertexTransform_FWTO(float *x, float *y, float *z); void VertexTransform_FOTW(float *x, float *y, float *z); void VertexTransform_FCTO(float *x, float *y, float *z); void VertexTransform_FOTC(float *x, float *y, float *z); / 对象坐标系、世界坐标系、相机坐标系之间的矢量换算 void Vec
14、torTransform_FWTO(VECTOR *V); void VectorTransform_FOTW(VECTOR *V); void VectorTransform_FCTO(VECTOR *V); void VectorTransform_FOTC(VECTOR *V); 函数SetPosition、SetRotation与SetScale用于设置该节点在父节点坐标系中的位置量、旋转量与比例量。void SceneNode:SetPosition(float x, float y, float z) m_position.x=x; m_position.y=y; m_positi
15、on.z=z; m_oldPosition=m_position; / 记录原始状态void SceneNode:SetRotation(float angle, float nx, float ny, float nz) m_rotation.angle=angle; m_rotation.axis.x=nx; m_rotation.axis.y=ny; m_rotation.axis.z=nz; VectorNormalize(&m_rotation.axis); m_oldRotation=m_rotation; / 记录原始状态void SceneNode:SetScale(float
16、 sx, float sy, float sz) m_scale.x=sx; m_scale.y=sy; m_scale.z=sz; m_oldScale=m_scale; / 记录原始状态函数Translate、Rotate与Scale用于实现对象坐标系中的平移变换、旋转变换与比例变换。ResetTransform函数用于恢复原始状态。void SceneNode:Translate(VECTOR trans) / 注意理解为什么要用 VectorTransform trans=VectorTransform(trans, m_rotation); / 见Rotation.h m_posit
17、ion.x += trans.x; m_position.y += trans.y; m_position.z += trans.z;void SceneNode:Rotate(float angle, VECTOR axis) ROTATION R(axis, angle); VectorNormalize(&R.axis); / 注意理解为什么要用 VectorTransform R.axis=VectorTransform(R.axis, m_rotation); m_rotation=m_rotation*R; / 见Rotation.hvoid SceneNode:Scale(flo
18、at sx, float sy, float sz) m_scale.x *= sx; m_scale.y *= sy; m_scale.z *= sz;void SceneNode:ResetTransform(void) / 恢复初始状态 m_position= m_oldPosition; m_rotation = m_oldRotation; m_scale = m_oldScale; TranslateInCamera与RotateInCamera是相机坐标系的平移变换与旋转变换函数。MouseTrackStart 与MouseTracking用于鼠标跟踪球交互。void Scene
19、Node:TranslateInCamera(VECTOR trans) if(GetType() != CAMERA_NODE) VectorTransform_FCTO(&trans); Translate(trans);void SceneNode:RotateInCamera(float angle, VECTOR axis) if(GetType() != CAMERA_NODE) VectorTransform_FCTO(&axis); Rotate(angle, axis);void SceneNode:MouseTrackStart(int width, int height,
20、 int mx, int my) / 计算旋转中心在窗口中的坐标 float cx=0, cy=0, cz=0; if(GetType() = CAMERA_NODE) cx=width/2.0; cy=height/2.0; else VertexTransform_ObjectToWindow(&cx, &cy, &cz); cy=height-cy; / OpenGL Window 与 MFC Window 在Y方向反向 m_trackball.SetTrackWindow(width, height, int(cx), int(cy); m_trackball.Start(mx, my
21、);void SceneNode:MouseTracking(int dx, int dy) VECTOR axis; float angle; m_trackball.Tracking(dx, dy, &axis, &angle); RotateInCamera(angle, axis);4.2.2 节点的拾取与绘制用于拾取与绘制节点的主要函数有: public: virtual SceneNode *Search(char *name)return NULL; virtual void Selected(void)m_bSelected=TRUE; virtual void Unselec
22、ted(void)m_bSelected=FALSE; virtual void Draw(void); virtual void DrawForMouseSelect(void); void LoadMatrix(void); / 在Draw, DrawForMouseSelect 之前调用 一般情况下,节点用Draw函数绘制。当场景的节点处于拾取状态时,OpenGL的绘制模式为GL_SELECT,此时要用DrawForMouseSelect函数绘制节点。在执行Draw或DrawForMouseSelect函数前,应调用LoadMatrix函数。Search、Selected、Unselec
23、ted、Draw与DrawForMouseSelect均为虚函数,具体行为由派生类定义。void SceneNode:LoadMatrix(void) glTranslatef(m_position.x, m_position.y, m_position.z); glRotatef(m_rotation.angle,m_rotation.axis.x, m_rotation.axis.y, m_rotation.axis.z); glScalef(m_scale.x, m_scale.y, m_scale.z); COM接口ISceneNode定义如下: interface ISceneNod
24、e : IDispatch HRESULT SetName(BSTR strName);HRESULT GetName(BSTR *strName);HRESULT SetPosition(float x, float y, float z);HRESULT GetPosition(out float *x, out float *y, out float *z);HRESULT SetRotation(float angle, float nx, float ny, float nz);HRESULT GetRotation(out float *angle, out float *nx,
25、out float *ny, out float *nz);HRESULT SetScale(float sx, float sy, float sz);HRESULT GetScale(out float *sx, out float *sy, out float *sz);HRESULT SetRotateStep(float fRotateStep);HRESULT GetRotateStep(out,retval float *step);HRESULT GetTranslateStep(out,retval float *step);HRESULT SetTranslateStep(
26、float fTransStep);HRESULT SetScaleStep(float fScaleStep);HRESULT GetScaleStep(out,retval float *step);HRESULT ResetTransform();HRESULT Scale(float sx, float sy, float sz);HRESULT Translate(float dx, float dy, float dz);HRESULT Rotate(float angle, float nx, float ny, float nz);HRESULT TranslateInCame
27、ra(float dx, float dy, float dz);HRESULT RotateInCamera(float angle, float nx, float ny, float nz);HRESULT MouseTrackStart(int iViewportWidth, int iViewportHeight, int mx, int my);HRESULT MouseTracking(int dx, int dy);HRESULT LoadMatrix();HRESULT LoadInverseMatrix();HRESULT LoadMatrix_FWTO();HRESULT
28、 LoadMatrix_FOTW();HRESULT VertexTransform_FWTO(in,out float *x, in,out float *y, in,out float *z);HRESULT VertexTransform_FOTW(in,out float *x, in,out float *y, in,out float *z);HRESULT VertexTransform_FCTO(in,out float *x, in,out float *y, in,out float *z);HRESULT VertexTransform_FOTC(in,out float
29、 *x, in,out float *y, in,out float *z);HRESULT SetParent(ISceneNode *node);HRESULT GetParent(out,retval ISceneNode *node);HRESULT GetType(out,retval EnumNodeType *type);HRESULT Search(BSTR name, out, retval ISceneNode *node);HRESULT Draw();HRESULT DrawForMouseSelect();HRESULT Selected();HRESULT Unse
30、lected();HRESULT IsSelected(out,retval BOOL *bFlag); ;4.3 形 体 节 点形体节点可以引用图形对象,3D交互由节点提供,绘制则由所引用的图形对象实现。这样设计可使形体节点既简单又通用。C+类库中的ShapeNode程序见Intra3D-DLL IncludeLayer3ShapeNode.h和Intra3D-DLLLayer3ShapeNode.cpp。COM库中的程序见Intra3D-COMLayer3ShapeNode.h和ShapeNode.cpp。 类ShapeNode的声明如下:class ShapeNode : public
31、SceneNodepublic: void SetBoundColor(float red, float green, float blue); void ShowBoundBox(void); void HideBoundBox(void); void SetGraphicalObject(GraphicalObject *object); virtual void Draw(void); virtual void DrawForMouseSelect(void); .protected: virtual void FinalRelease(void); / Container.hprotec
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1