分享

5.2.3 场景交互

 昵称7598251 2011-08-31
    VRML2.0相对VRML1.0的重大改进在于它能够支持动态的、交互式的3D场景。利用VRML2.0建立的场景,不仅可以展示其中运动的物体,而且还可以使用户跟这些物体进行交互。例如在某个场景中,门可开着,电梯在运行,出租车行驶着,更奇妙的是,用户可以将门打开或关上,选择电梯的上下按钮,或者招手叫出租车停下来。
    VRML2.0采用了事件机制来支持这种动态交互的场景。事件是包含一些数据的信息,它被用来作为事件的触发器(Sensor)。事件机制在Windows操作系统中也是普遍使用的,如键盘或鼠标的每次击键操作都会产生一个输入事件并被送到当前的应用程序中去。在VRML2.0中,每个事件包括两个部分:来源(eventIn)和目标(eventOut),它们都是由某个节点的字段表示的。
    VRML2.0提供了一组描述事件触发器的节点。如TouchSensor用于描述用户输入的消息;TimeSensor用于产生定时器消息;ProximitySensor用于相应用户进入某个区域的消息;VisibilitySensor用于判断某个包围盒(Box)区域的可见性等等。
    下面是一个处理用户输入(即鼠标消息)的例子。当用户在立方体上按下左(右)键时,视点进行一次切换。
 程序例touchme.wrl
#VRML V2.0 utf8
DEF view1 Viewpoint {
position 0 0 20
description "view1"
}
DEF view2 Viewpoint {
position 5 0 20
description "view2"
}
Group {
children [
DEF box Transform {
translation 5 0 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor 1 0 0 }
}
geometry Box { }
}
DEF touchBox TouchSensor { }
]
}
DEF sphere Transform {
translation 0 0 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor 0 1 0 }
}
geometry Sphere { }
}
]
}
DEF cone Transform {
translation -5 0 0
children [
Shape {
appearance Appearance {
material Material { diffuseColor 0 0 1 }
}
geometry Cone { }
}
]
}
] # end of Group children
}
DEF touchScript Script {
eventIn SFBool touchBoxIsActive
eventOut SFBool bindView2
 
url "vrmlscript:
function touchBoxIsActive(active) {
bindView2 = TRUE;
}"
}
ROUTE touchBox.isActive TO touchScript.touchBoxIsActive
ROUTE touchScript.bindView2 TO view2.set_bind
 
 
图5-2-8 视点view1的场景
 
 
图5-2-9 视点view2的场景
程序演示:交互式视点转换(点击立方体)
    在上述程序的开头,定义了两个视点(Viewpoint)节点。Viewpoint节点的各字段定义如下:
Viewpoint {
eventIn SFBool set_bind
exposedField SFFloat fieldOfView 0.785398
exposedField SFBool jump TRUE
exposedField SFRotation orientation 0 0 1 0
exposedField SFVec3f position 0 0 10
field SFString description ""
eventOut SFTime bindTime
eventOut SFBool isBound
}
    VRML允许在同一个.wrl文件中设置多个视点节点。浏览器在解释时,将这些视点节点归入一个栈结构,栈顶的视点节点就是当前的视点。可以通过调用视点节点的set_bind字段将某个视点节点置为栈顶元素,也即设为当前的视点。
    接下来,程序在box形体后插入一个TouchSensor节点touchBox。TouchSensor的定义如下:
TouchSensor {
exposedField SFBool enabled TRUE
eventOut SFVec3f hitNormal_changed
eventOut SFVec3f hitPoint_changed
eventOut SFVec2f hitTexCoord_changed
eventOut SFBool isActive
eventOut SFBool isOver
eventOut SFTime touchTime
}
    当输入设备(一般是鼠标)在box形体上时,各种输入消息就会通过该触发器的各个eventOut字段传送出来。其中,isActive字段只有在鼠标对box按下左键(或右键)时为TRUE,放开左键(或右键)时为FALSE。
    VRML2.0中利用路线(ROUTE)进行消息事件的连接,即把一个节点内的事件输出(eventOut)连接为另一个节点的事件输入(eventIn)。利用路线能够传播场景图内的节点变化。上面的程序中就用到了两个路线进行事件的传播。
    Script节点是事件处理的核心部分,这是一个特殊的节点。由于VRML本身的程序描述能力不够强大,需要利用其它的编程语言(如Java、JavaScript),Script节点就是用于这种延伸的,到达这些字段的事件会自动地移到和该Script节点相关的程序中。Script节点的各字段定义如下:
Script {
exposedField MFString url []
field SFBool directOutput FALSE
field SFBool mustEvaluate FALSE
# And any number of:
eventIn eventTypeName eventName
field fieldTypeName fieldName initialValue
eventOut eventTypeName eventName
}
    通常,Script节点内的eventIn和eventOut字段与其它节点进行事件连接(ROUTE),而在url字段内进行具体的程序处理。这相当于对这个消息事件作了一次过滤,或者可以把Script节点看成一个事件处理的暗箱。url字段包含一个有效的全球资源定位器(URL),它指向包含程序代码的文件,文件类型则表示了文件内部使用的脚本语言类型,如:
      #VRML V2.0 utf8
Script {
url [ "javascript: ...", # custom protocol JavaScript
"http:///foo.js", # std protocol JavaScript
"http:///foo.class" ] # std protocol Java byte
}
    注意在上面的程序中,eventIn字段的名称和url字段内的javascript函数名称是相同的。Script的eventIn字段均有一个相应的同名函数。该函数的作用就是每次有一个触发器的isActive消息事件(无论是TRUE或FALSE)发生时,都会发出一个值为TRUE的消息事件,从而将view2设为当前的视点。
    以上只是VRML2.0中场景交互最简单的例子,但也是最基本的。其它的触发器节点,如TimeSensor、ProximitySensor和插入器节点(Interpolator)以及VRML与Java程序之间的通讯等等,这些内容的引入,可以使场景交互变得很复杂和符合实际。限于篇幅,这里就不能对它们进行介绍了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多