第七章用Visual Basic 编写交互式三维图形程序.docx
《第七章用Visual Basic 编写交互式三维图形程序.docx》由会员分享,可在线阅读,更多相关《第七章用Visual Basic 编写交互式三维图形程序.docx(30页珍藏版)》请在冰豆网上搜索。
第七章用VisualBasic编写交互式三维图形程序
第七章用VisualBasic编写交互式三维图形程序
本章论述如何使用VisualBasic和Intra3D的COM库来编写交互式3D应用程序。
VisualBasic版本与VisualC++版本的3D示例程序功能完全一样,但各有优缺点。
程序复杂性方面,VisualBasic版本的3D程序要比VisualC++版本的简单。
速度方面,VisualBasic版本的3D程序则比VisualC++版本的慢。
7.1编译器设置与示例程序说明
四个示例程序存放于Intra3D标准版软件的Examples\VisualBasic目录下。
为了能编译这些示例程序,首先应正确引用Intra3D.ocx、OglWindow.ocx与OpenGL.ocx三个COM库文件。
Intra3D的安装程序将上述三个COM库文件安装到Windows的System目录下。
由于Intra3D.ocx与OglWindow.ocx含有ActiveX控件,应在VisualBasic的Components属性中添加Intra3D.ocx与OglWindow.ocx,如图7.1所示。
OpenGL.ocx不含有ActiveX控件,应在VisualBasic的Refrences属性中添加OpenGL.ocx,如图7.2所示。
每个示例程序的工程文件为Project.vbp,可执行文件为App.exe。
Project.vbp含三个文件(如图7.3所示):
(1)frmMain.frm为主界面程序,使用SceneView控件交互式绘制场景;
(2)frmAbout为About对话,使用OglWindow控件实现图标的3D动画;
(3)Scene.bas用于创建场景的SceneGraph。
图7.1在Components属性中添加Intra3D.ocx与OglWindow.ocx
图7.2在Referencs属性中添加OpenGL.ocx
图7.3工程文件Project.vbp
App.exe可用VisualBasic的MakeProject菜单生成,如图7.4所示。
注意不要用VisualBasic的Start菜单运行示例程序。
这是因为Start菜单是以解释方式运行程序的,往往不能正确运行交互式的3D应用程序。
图7.4生成可执行程序App.exe
7.2示例程序之一:
简单图形对象
示例程序存放于Examples\VisualBasic\SimpleObjects目录下,主要演示:
(1)简单图形对象的使用;
(2)材质对象与材质对话的使用;(3)光源节点与光源对话的使用;(4)编辑背景颜色、多重采样削锯齿、标准三维交互、辅助三维交互等功能的实现。
使用VisualBasic开发用户界面非常方便,frmMain.frm的界面如图7.5所示。
图7.5中“白色”的控件名为AppView,是Intra3D的SceneView类型的控件;程序运行时,AppView的窗口将扩大覆盖frmMain的用户区,3D图形绘制在AppView的窗口中,如图7.6所示。
图7.5示例程序SimpleObject的frmMain
图7.6示例程序SimpleObject的主界面
VisualBasic版本的示例程序与VisualC++版本的示例程序在功能上完全一致,用户界面也非常相似(对比图7.6与图6.3)。
但是程序的代码有较大的差异。
7.2.1全局对象与SceneGraph
全局对象与SceneGraph定义在Scene.bas程序中,在程序结束时VisualBasic将自动释放这些对象。
用VisualBasic的ObjectBrowser工具可以浏览COM对象的编程接口,如图7.7所示。
图7.7用ObjectBrowser浏览COM对象的编程接口
OptionExplicit
PublicoglAsNewOpenGL’OpenGL对象
Publicm_pMaterialAsNewMaterial’材质对象
Publicm_pBoxAsNewBoxObject’长方体对象
Publicm_pConeAsNewConeObject’锥体对象
Publicm_pCylinderAsNewCylinderObject’圆柱体对象
Publicm_pSphereAsNewSphereObject’球体对象
Publicm_pTorusAsNewTorusObject’圆环体对象
Publicm_pShapeAsNewShapeNode’形体节点
Publicm_pCameraAsNewCameraNode’相机节点
Publicm_pLight0AsNewDirLightNode’平行光源节点
Publicm_pLight1AsNewPointLightNode’点光源节点
Publicm_pLight2AsNewSpotLightNode’锥光源节点
Publicm_pGroupAsNewGroupNode’组节点
函数CreateScene用于创建SceneGraph,AppView将引用组节点m_pGroup。
要注意节点的初始化:
每个节点均有一个缺省接口和一个继承接口(ISceneNode),所以节点的初始化信息必须由两个接口分别设置。
例如形体节点m_pShape的缺省接口为IShapeNode,继承接口为ISceneNode。
以下语句可以获得形体节点的ISceneNode接口,功能相当于C++中的QueryInterface函数:
DimnodeAsSceneNode
Setnode=m_pShape’相当于C++中的QueryInterface函数
当一个COM对象含有多个接口时,均可用上述方法获取各个接口。
PublicSubCreateScene()
’---------------------------------初始化材质对象-----------------------------
m_pMaterial.ReadMaterialFromLibMAT_ARTDECO_03
’----------------------------------初始化长方体对象--------------------------
m_pBox.SetBox3,3,3,0,0,0
m_pBox.SetDrawModeSOLID
m_pBox.SetMaterialm_pMaterial
’----------------------------------初始化锥体对象-----------------------------
m_pCone.SetCone2,4
m_pCone.SetDrawModeSOLID
m_pCone.SetMaterialm_pMaterial
’----------------------------------初始化圆柱体对象--------------------------
m_pCylinder.SetCylinder2,4
m_pCylinder.SetDrawModeSOLID
m_pCylinder.SetMaterialm_pMaterial
’-----------------------------------初始化球体对象----------------------------
m_pSphere.SetSphere2,32
m_pSphere.SetDrawModeSOLID
m_pSphere.SetMaterialm_pMaterial
’----------------------------------初始化圆环体对象--------------------------
m_pTorus.SetTorus2,3
m_pTorus.SetDrawModeSOLID
m_pTorus.SetMaterialm_pMaterial
’----------------用于获取场景节点的ISceneNode接口-------------------
DimnodeAsSceneNode
’---------------------------------初始化形体节点-------------------------------
Setnode=m_pShape’使用m_pShape的ISceneNode接口
node.SetName"Shape"
node.SetPosition0,0,0
node.SetRotation0,1,0,0
node.SetScale1,1,1
node.SetTranslateStep0.1
node.SetRotateStep4
node.SetScaleStep0.1
m_pShape.SetGraphicalObjectm_pSphere’使用m_pShape的IShapeNode接口
m_pShape.SetBoundColor0.8,0.8,0.8
’---------------------------------初始化相机节点-------------------------------
Setnode=m_pCamera’使用m_pCamera的ISceneNode接口
node.SetName"Camera"
node.SetPosition0,0,20
node.SetRotation0,1,0,0
node.SetScale1,1,1
node.SetTranslateStep0.1
node.SetRotateStep1
node.SetScaleStep0.1
m_pCamera.SetProjectionModePERSPECTIVE’使用m_pCamera的ICameraNode接口
m_pCamera.SetViewVolume30,1,100,20
’---------------------------------初始化平行光源节点-------------------------------
Setnode=m_pLight0’使用m_pLight0的ISceneNode接口
node.SetName"DirLight"
node.SetPosition3,0,5
node.SetRotation30,0,1,0
node.SetScale1,1,1
m_pLight0.SetColor0,0,1’使用m_pLight0的IDirLightNode接口
m_pLight0.SetDiffuseIntensity0.8
m_pLight0.SetAmbientIntensity0.1
m_pLight0.SetSpecularIntensity1
m_pLight0.TurnOn
m_pLight0.ShowShape
’---------------------------------初始化点光源节点-------------------------------
Setnode=m_pLight1’使用m_pLight1的ISceneNode接口
node.SetName"PointLight"
node.SetPosition-2,-2,2
node.SetRotation0,1,0,0
node.SetScale1,1,1
m_pLight1.SetColor1,0,0’使用m_pLight1的IPointLightNode接口
m_pLight1.SetDiffuseIntensity0.8
m_pLight1.SetAmbientIntensity0.1
m_pLight1.SetSpecularIntensity1
m_pLight1.TurnOn
m_pLight1.ShowShape
’---------------------------------初始化锥光源节点-------------------------------
Setnode=m_pLight2’使用m_pLight2的ISceneNode接口
node.SetName"SpotLight"
node.SetPosition0,4,2
node.SetRotation-60,1,0,0
node.SetScale1,1,1
m_pLight2.SetColor0,1,0’使用m_pLight2的ISpotLightNode接口
m_pLight2.SetDiffuseIntensity0.8
m_pLight2.SetAmbientIntensity0.1
m_pLight2.SetSpecularIntensity1
m_pLight2.SetCutoffAngle60
m_pLight2.TurnOn
m_pLight2.ShowShape
’------------------------------------------初始化组节点---------------------------------------
Setnode=m_pGroup’使用m_pGroup的ISceneNode接口
node.SetName"pGroup"
m_pGroup.AddChildm_pCamera’使用m_pGroup的IGroupNode接口
m_pGroup.AddChildm_pLight0
m_pGroup.AddChildm_pLight1
m_pGroup.AddChildm_pLight2
m_pGroup.AddChildm_pShape
EndSub
函数ControlAnimate用于控制场景的动画,以下程序使形体节点绕X轴旋转,角度步长为5度:
PublicSubControlAnimate()
DimnodeAsSceneNode
Setnode=m_pShape’使用m_pShape的ISceneNode接口
node.Rotate5,1,0,0
EndSub
7.2.2场景的交互式绘制
一、场景与窗口的初始化
当应用程序的窗口尺寸发生变化时,控件AppView的窗口也作相应的变化,由函数Form_Resize实现。
其中tbStandard是标准交互工具条,tbDetailed是辅助交互工具条,tbApp是其它用途的工具条。
PrivateSubForm_Resize()
If(Me.WindowState=1)ThenExitSub'最小化
AppView.MovetbApp.Width,tbStandard.Height,
Me.ScaleWidth-tbApp.Width-tbDetailed.Width-3,_
Me.ScaleHeight-tbStandard.Height
EndSub
函数AppView_InitScene与AppView_ControlAnimate均是控件AppView的事件。
AppView_InitScene用于初始化场景,AppView_ControlAnimate用于控制场景的动画。
PrivateSubAppView_InitScene()
ogl.glDepthFuncGL_Less
ogl.glEnableGL_DEPTH_TEST
ogl.glEnableGL_NORMALIZE
ogl.glEnableGL_LIGHTING
CreateScene
AppView.SetClearColor0,0,0,1
AppView.SetSceneRootm_pGroup
EndSub
PrivateSubAppView_ControlAnimate()
ControlAnimate
EndSub
二、改变形体节点的图形对象
形体节点的函数SetGraphicalObject可引用图形对象。
本例中有5个图形对象可以分别被形体节点引用。
’--------------------引用长方体对象--------------------
PrivateSubmnuBox_Click()
m_pShape.SetGraphicalObjectm_pBox
AppView.Run
EndSub
’--------------------引用锥体对象--------------------
PrivateSubmnuCone_Click()
m_pShape.SetGraphicalObjectm_pCone
AppView.Run
EndSub
’--------------------引用圆柱体对象--------------------
PrivateSubmnuCylinder_Click()
m_pShape.SetGraphicalObjectm_pCylinder
AppView.Run
EndSub
’--------------------引用球体对象--------------------
PrivateSubmnuSphere_Click()
m_pShape.SetGraphicalObjectm_pSphere
AppView.Run
EndSub
’--------------------引用圆环体对象--------------------
PrivateSubmnuTorus_Click()
m_pShape.SetGraphicalObjectm_pTorus
AppView.Run
EndSub
三、编辑材质
编辑材质是使用CommonDialog对象的EditMaterialDialog函数实现的。
PrivateSubEditMaterial()
DimdialogAsNewCommonDialog
DimflagAsLong
flag=dialog.EditMaterialDialog("EditMaterial",m_pMaterial)
IfflagThenAppView.Run
EndSub
四、编辑光源
编辑光源是使用CommonDialog对象的EditDirLightDialog、EditPointLightDialog与EditSpotLightDialog函数实现的。
’-------------------------------编辑平行光源----------------------------
PrivateSubEditDirLight()
DimdialogAsNewCommonDialog
DimflagAsLong
flag=dialog.EditDirLightDialog("EditDirLight",m_pLight0)
IfflagThenAppView.Run
EndSub
’----------------------------------编辑点光源--------------------------------
PrivateSubEditPointLight()
DimdialogAsNewCommonDialog
DimflagAsLong
flag=dialog.EditPointLightDialog("EditPointLight",m_pLight1)
IfflagThenAppView.Run
EndSub
’----------------------------------编辑锥光源--------------------------------
PrivateSubEditSpotLight()
DimdialogAsNewCommonDialog
DimflagAsLong
flag=dialog.EditSpotLightDialog("EditSpotLight",m_pLight2)
IfflagThenAppView.Run
EndSub
五、编辑背景颜色
编辑材质是使用CommonDialog对象的EditColorDialog函数实现的。
PrivateSubEditClearColor()
DimredAsSingle,greenAsSingle,blueAsSingle,alphaAsSingle
AppView.GetClearColorred,green,blue,alpha’获取背景颜色
’----------------------------------颜色对话----------------------------------
DimdialogAsNewCommonDialog
DimflagAsLong
flag=dialog.EditColorDialog("EditBackgroundColor",red,green,blue)
IfflagThen
AppView.SetClearColorred,green,blue,alpha’设置背景颜色
AppView.Run
EndIf
EndSub
六、多重采样消锯齿
函数mnuAntialiasing_Click用于实现场景的消锯齿。
PrivateSubmnuAntialiasing_Click()
DimflagAsLong
DimtimesAsEnumJitterTimes
AppView.GetAntialiasingInfoflag,times
IfflagThen
AppView.DisableAntialiasing’取消Antialiasing
mnuAntialiasing.Checked=False
Else
AppView.EnableAntialiasingJITTER_TIMES_4
mnuAntialiasing.Checked=True’