新版第四章场景的节点与数据结构课件docWord文件下载.docx
《新版第四章场景的节点与数据结构课件docWord文件下载.docx》由会员分享,可在线阅读,更多相关《新版第四章场景的节点与数据结构课件docWord文件下载.docx(29页珍藏版)》请在冰豆网上搜索。
node2->
AddChild(node3);
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;
//记录原始状态
}
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;
SetScale(floatsx,floatsy,floatsz)
m_scale.x=sx;
m_scale.y=sy;
m_scale.z=sz;
m_oldScale=m_scale;
函数Translate、Rotate与Scale用于实现对象坐标系中的平移变换、旋转变换与比例变换。
ResetTransform函数用于恢复原始状态。
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;
Rotate(floatangle,VECTORaxis)
ROTATIONR(axis,angle);
R.axis);
R.axis=VectorTransform(R.axis,m_rotation);
m_rotation=m_rotation*R;
//见Rotation.h
Scale(floatsx,floatsy,floatsz)
m_scale.x*=sx;
m_scale.y*=sy;
m_scale.z*=sz;
ResetTransform(void)
{//恢复初始状态
m_position=m_oldPosition;
m_rotation=m_oldRotation;
m_scale=m_oldScale;
TranslateInCamera与RotateInCamera是相机坐标系的平移变换与旋转变换函数。
MouseTrackStart与MouseTracking用于鼠标跟踪球交互。
TranslateInCamera(VECTORtrans)
if(GetType()!
=CAMERA_NODE)
VectorTransform_FCTO(&
trans);
Translate(trans);
RotateInCamera(floatangle,VECTORaxis)
axis);
Rotate(angle,axis);
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);
MouseTracking(intdx,intdy)
VECTORaxis;
floatangle;
m_trackball.Tracking(dx,dy,&
axis,&
angle);
RotateInCamera(angle,axis);
4.2.2节点的拾取与绘制
用于拾取与绘制节点的主要函数有:
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均为虚函数,具体行为由派生类定义。
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);
...
virtualvoidFinalRelease(void);
//Container.h
protec