新版第四章场景的节点与数据结构课件doc.docx

上传人:b****5 文档编号:3434309 上传时间:2022-11-23 格式:DOCX 页数:29 大小:87.50KB
下载 相关 举报
新版第四章场景的节点与数据结构课件doc.docx_第1页
第1页 / 共29页
新版第四章场景的节点与数据结构课件doc.docx_第2页
第2页 / 共29页
新版第四章场景的节点与数据结构课件doc.docx_第3页
第3页 / 共29页
新版第四章场景的节点与数据结构课件doc.docx_第4页
第4页 / 共29页
新版第四章场景的节点与数据结构课件doc.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

新版第四章场景的节点与数据结构课件doc.docx

《新版第四章场景的节点与数据结构课件doc.docx》由会员分享,可在线阅读,更多相关《新版第四章场景的节点与数据结构课件doc.docx(29页珍藏版)》请在冰豆网上搜索。

新版第四章场景的节点与数据结构课件doc.docx

新版第四章场景的节点与数据结构课件doc

第四章场景的节点与数据结构

如果将场景比作房间,那么场景的节点就是房间里的床、桌、灯、柜等设施。

著名的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);

node1->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程序)。

如果应用程序涉及复杂的相机交互,例如多个相机的切换,场景的漫游;此时将相机作为节点插入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);

//对象坐标系的图形变换函数

voidTranslate(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;

VectorNormalize(&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)

{

//注意理解为什么要用VectorTransform

trans=VectorTransform(trans,m_rotation);//见Rotation.h

m_position.x+=trans.x;

m_position.y+=trans.y;

m_position.z+=trans.z;

}

voidSceneNode:

:

Rotate(floatangle,VECTORaxis)

{

ROTATIONR(axis,angle);

VectorNormalize(&R.axis);

//注意理解为什么要用VectorTransform

R.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;

}

TranslateInCamera与RotateInCamera是相机坐标系的平移变换与旋转变换函数。

MouseTrackStart与MouseTracking用于鼠标跟踪球交互。

voidSceneNode:

:

TranslateInCamera(VECTORtrans)

{

if(GetType()!

=CAMERA_NODE)

VectorTransform_FCTO(&trans);

Translate(trans);

}

voidSceneNode:

:

RotateInCamera(floatangle,VECTORaxis)

{

if(GetType()!

=CAMERA_NODE)

VectorTransform_FCTO(&axis);

Rotate(angle,axis);

}

voidSceneNode:

:

MouseTrackStart(intwidth,intheight,intmx,intmy)

{

//计算旋转中心在窗口中的坐标

floatcx=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;//OpenGLWindow与MFCWindow在Y方向反向

}

m_trackball.SetTrackWindow(width,height,int(cx),int(cy));

m_trackball.Start(mx,my);

}

voidSceneNode:

:

MouseTracking(intdx,intdy)

{

VECTORaxis;

floatangle;

m_trackball.Tracking(dx,dy,&axis,&angle);

RotateInCamera(angle,axis);

}

4.2.2节点的拾取与绘制

用于拾取与绘制节点的主要函数有:

public:

virtualSceneNode*Search(char*name){returnNULL;}

virtualvoidSelected(void){m_bSelected=TRUE;}

virtualvoidUnselected(void){m_bSelected=FALSE;}

virtualvoidDraw(void){};

virtualvoidDrawForMouseSelect(void){};

voidLoadMatrix(void);//在Draw,DrawForMouseSelect之前调用

一般情况下,节点用Draw函数绘制。

当场景的节点处于拾取状态时,OpenGL的绘制模式为GL_SELECT,此时要用DrawForMouseSelect函数绘制节点。

在执行Draw或DrawForMouseSelect函数前,应调用LoadMatrix函数。

Search、Selected、Unselected、Draw与DrawForMouseSelect均为虚函数,具体行为由派生类定义。

voidSceneNode:

:

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定义如下:

interfaceISceneNode:

IDispatch

{

HRESULTSetName(BSTRstrName);

HRESULTGetName(BSTR*strName);

HRESULTSetPosition(floatx,floaty,floatz);

HRESULTGetPosition([out]float*x,[out]float*y,[out]float*z);

HRESULTSetRotation(floatangle,floatnx,floatny,floatnz);

HRESULTGetRotation([out]float*angle,[out]float*nx,[out]float*ny,[out]float*nz);

HRESULTSetScale(floatsx,floatsy,floatsz);

HRESULTGetScale([out]float*sx,[out]float*sy,[out]float*sz);

HRESULTSetRotateStep(floatfRotateStep);

HRESULTGetRotateStep([out,retval]float*step);

HRESULTGetTranslateStep([out,retval]float*step);

HRESULTSetTranslateStep(floatfTransStep);

HRESULTSetScaleStep(floatfScaleStep);

HRESULTGetScaleStep([out,retval]float*step);

HRESULTResetTransform();

HRESULTScale(floatsx,floatsy,floatsz);

HRESULTTranslate(floatdx,floatdy,floatdz);

HRESULTRotate(floatangle,floatnx,floatny,floatnz);

HRESULTTranslateInCamera(floatdx,floatdy,floatdz);

HRESULTRotateInCamera(floatangle,floatnx,floatny,floatnz);

HRESULTMouseTrackStart(intiViewportWidth,intiViewportHeight,intmx,intmy);

HRESULTMouseTracking(intdx,intdy);

HRESULTLoadMatrix();

HRESULTLoadInverseMatrix();

HRESULTLoadMatrix_FWTO();

HRESULTLoadMatrix_FOTW();

HRESULTVertexTransform_FWTO([in,out]float*x,[in,out]float*y,[in,out]float*z);

HRESULTVertexTransform_FOTW([in,out]float*x,[in,out]float*y,[in,out]float*z);

HRESULTVertexTransform_FCTO([in,out]float*x,[in,out]float*y,[in,out]float*z);

HRESULTVertexTransform_FOTC([in,out]float*x,[in,out]float*y,[in,out]float*z);

HRESULTSetParent(ISceneNode*node);

HRESULTGetParent([out,retval]ISceneNode**node);

HRESULTGetType([out,retval]EnumNodeType*type);

HRESULTSearch(BSTRname,[out,retval]ISceneNode**node);

HRESULTDraw();

HRESULTDrawForMouseSelect();

HRESULTSelected();

HRESULTUnselected();

HRESULTIsSelected([out,retval]BOOL*bFlag);

};

4.3形体节点

形体节点可以引用图形对象,3D交互由节点提供,绘制则由所引用的图形对象实

现。

这样设计可使形体节点既简单又通用。

C++类库中的ShapeNode程序见Intra3D-DLL\Include\Layer3\ShapeNode.h和Intra3D-DLL\Layer3\ShapeNode.cpp。

COM库中的程序见Intra3D-COM\Layer3\ShapeNode.h和ShapeNode.cpp。

类ShapeNode的声明如下:

classShapeNode:

publicSceneNode

{

public:

voidSetBoundColor(floatred,floatgreen,floatblue);

voidShowBoundBox(void);

voidHideBoundBox(void);

voidSetGraphicalObject(GraphicalObject*object);

virtualvoidDraw(void);

virtualvoidDrawForMouseSelect(void);

...

protected:

virtualvoidFinalRelease(void);//Container.h

protec

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

当前位置:首页 > 小学教育 > 学科竞赛

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1