可用于虚拟建筑环境的Web3D技术初探-4
4.2.1 使用KeyNavigatorBehavior对象实现场景漫游
com.sun.java.util.behaviors.keyboard包用于监听键盘事件产生,KeyNavigatorBehavior类实现了采用键盘控制视点的移动.KeyNaigatorBehavior的控制对象ViewPlatform对象所在的TransformGroup对象.如图4-2.
首先要获取该TransformGroup对象的实例,SimpleUniverse类提供了获取观察者位置的TransformGroup对象的方法:
TransformGroup viewTG=
simpleUniverse.getViewingPlatform().getViewPlatformTransform();
其中simpleUniverse是SimpleUniverse的一个实例.
使用KeyNavigator类,首先导入该类,
import com.sun.j3d.utils.behaviors.keyboard.*;
具体的应用如下:
…
BranchGroup objRoot = new BranchGroup();
Vector3f translate = new Vector3f();
Transform3D t3D = new Transform3D();
// 获得观察者所处的TransformGroup对象
TransformGroup vpTrans =
su.getViewingPlatform().getViewPlatformTransform();
translate.set( …);
t3D.setTranslation(translate);
// 设置观察者位置
vpTrans.setTransform(T3D);
// 添加KeyNavigatorBehavior对象
KeyNavigatorBehavior keyNavBeh =
new KeyNavigatorBehavior(vpTrans);
// 设置KeyNavigatorBehavior对象的作用范围
keyNavBeh.setSchedulingBounds(bounds);
// 添加到场景中接收输入
objRoot.addChild(keyNavBeh);…
其中TransformGroup实例vpTrans在构造KeyNavigatorBehavior时被引用.
4.2.2 响应鼠标事件的漫游行为
要实现复杂的交互行为,这种情况需要自己编写相应的行为类.Java3D可以支持鼠标,键盘传统的交互设备以外的多种输入设备.考虑到基于Web环境应用的复杂性以及硬件,技术的限制,本文及其涉及的工作仅限于采用鼠标和键盘的交互行为.
在Java3D中,可以通过Java的事件体系捕捉用户的键盘,鼠标等设备,控制观察点的位置和方向,实现虚拟漫游.
图4-3是一个虚拟漫游的实例,程序采用了AWT图形界面,用户可以在一个工具栏中选择不种模式观察虚拟场景.同时,程序可以在读取并存储VRML场景文件中预先定义的不同视点并在不同的视点切换.
程序定义了几个主要的类,JNavigator类定义了程序的入口,JNavigatorView类定义了视图子图,JNavigatorToolBar定义了一个直观的工具栏,用户可以在工具栏中选择Walk,Tilt,Pan不同的方式观察场景.JNavigatorMouseKeyboardInput类实现了MouseInputListener接口,JnavigatorMouseKeyboardInput用于监听用户的鼠标,调用相应的方法处理鼠标事件,处理方法是根据用户的输入不断的改变View对象的状态,从而改变视点的位置,方向等参数,形成漫游的动画效果.JNavigatorMouseKeyboardInput是基于Java AWT事件模型的.Transition类则实现了不同视点之间平滑的切换.
JNavigatorView类定义了视图子图
public class JNavigatorView{
…
private View view = new View();
private TransformGroup tgView = new TransformGroup();
…
以下是JNavigatorView的构造方法:
//JNavigatorView constructor:
// jNavigator is parent JNavigator class.
//jNavigatorCanvas3D is the parent Canvas3D object.
Public JnavigatorView
(JNavigator jNavigator,Canvas3D jNavigatorCanvas3D){
this.jNavigator = jNavigator;
this.jNavigatorCanvas3D = jNavigatorCanvas3D;
// ViewPlatform:
viewPlatform.setViewAttachPolicy(View.NOMINAL_HEAD);
viewPlatform.setActivationRadius(1000.0f);
// View:
view.setProjectionPolicy (View.PERSPECTIVE_PROJECTION);
view.setScreenScalePolicy(View.SCALE_EXPLICIT);
view.setWindowEyepointPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
view.setWindowResizePolicy(View.PHYSICAL_WORLD);
view.setWindowMovementPolicy(View.PHYSICAL_WORLD);
view.setFrontClipPolicy(View.PHYSICAL_EYE);
view.setBackClipPolicy(View.PHYSICAL_EYE);
view.setVisibilityPolicy(View.VISIBILITY_DRAW_VISIBLE);
view.setScreenScale (1.0);
view.setFrontClipDistance (0.1);
view.setBackClipDistance (100.0);
view.setCompatibilityModeEnable (false);
view.setSceneAntialiasingEnable (false);
view.setFieldOfView (Math.PI/3.0);
view.setPhysicalBody (physicalBody);
view.setPhysicalEnvironment (physicalEnvironment);
view.addCanvas3D (jNavigatorCanvas3D);
view.attachViewPlatform (viewPlatform);
// tgView:
tgView.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tgView.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
tgView.setCapability(Group.ALLOW_CHILDREN_EXTEND);
tgView.addChild(viewPlatform);
// bgView:
bgView.ad
dChild(tgView);
//
}
}
view.attachViewPlatform(viewPlatform) 方法将一个View实例关联到viewPlatform上,然后将而viewPlatform节点添加到 TransformGroup节点tgView上.
JNavigatorMouseKeyboardInput类实现了MouseInputListener接口,所以JnavigatorMouseKeyboardInput首先将实现MouseInputListener的方法.在mouseDragged(),mousePressed()等方法中调用processMouseEvent(mouseEvent).
public class JNavigatorMouseKeyboardInput implements MouseInputListener
{ //类变量
private JNavigator jNavigator;
public Transition transitionView;
private Canvas3D canvas3D;
private Canvas3D jNavigatorCanvas3D;
private View view;
private TransformGroup tgView = new TransformGroup();
private Transform3D t3dView = new Transform3D();
//...
// 实现MouseInputListener接口方法
public void mouseDragged (MouseEvent mouseEvent){
processMouseEvent(mouseEvent);
}
public void mousePressed (MouseEvent mouseEvent){
processMouseEvent(mouseEvent);
}
public void mouseReleased (MouseEvent mouseEvent){
processMouseEvent(mouseEvent);
}
public void mouseMoved (MouseEvent mouseEvent){}
public void mouseClicked (MouseEvent mouseEvent){}
public void mouseEntered (MouseEvent mouseEvent){
jNavigatorCanvas3D.requestFocus();
}
public void mouseExited (MouseEvent mouseEvent){}
//jNavigator is the parent.
//param jNavigatorCanvas3D is the Canvas object passed by the parent.
//param View is the View object passed by the parent.
//param tgView The UserPreferences object that should be used
//构造方法
public JNavigatorMouseKeyboardInput
(JNavigator jNavigator,Canvas3D jNavigatorCanvas3D,View view,TransformGroup tgView)
{
this.jNavigator = jNavigator;
this.jNavigatorCanvas3D = jNavigatorCanvas3D;
//引用view对象
this.view = view;
this.tgView = tgView;
this.canvas3D = canvas3D;
transitionView = new Transition(jNavigator,view);
// Timer:
....
this.tgView=tgView;
...
}
public Transform3D gett3dView(){return t3dView;}
private void processMouseEvent(MouseEvent mouseEvent)
{
eventModifyer = mouseEvent.getModifiers();
switch(mouseEvent.getID())
{
case MouseEvent.MOUSE_DRAGGED:
{ //...针对鼠标拖动处理
//...
if(cursorSelection==cursorWalk)
{ //Walk方式漫游场景
// Translate on Z:
//do something…针对tgView的变换
// Rotate around Y:
…
}
if(cursorSelection==cursorTilt)
{ //Tilt方式
// Rotate arround X,y:
//do something…针对tgView的变换
}
if(cursorSelection==cursorPan)
{
// Translate on X,Y:
//do something…针对tgView的变换
}
break;
}
case MouseEvent.MOUSE_PRESSED:
{ //...针对按下鼠标事件处理
}
case MouseEvent.MOUSE_RELEASED:
{ //...针对释放鼠标事件处理
break;
}
}//End switch
}
private void mouseReleased(){ }
public void setCursor(Cursor cursor) { }
private class ActionListenerTimer implements ActionListener{}
}
JnavigatorMouseKeyboardInput类中的类变量tgView是一个TransformGroup类,在应用中,tgView将引用JNavigatorView类中的tgView,在processMouseEvent()中对tgView的变换最终将改变view的状态从而改变观察者画面.
4.2.3替身(Avatar)
在场景中漫游经常提到替身(Avatar)的概念,替身可以是观察者的化身,也可以是一个导游,可以将视点,视方向等对象绑定到替身上,Awatar的身高用以指定视点的高度值,同时,替身具有自己的方法,如Walk(),Fly(),jump(),以及其它方法,替身的行为改变,将会关联到视对象,从而生成漫游画面.
public class Awatar {
//Awatar 的身高.
private float Height;
public Awatar(View view){…}
protected void setHeight( float height){…};
protected float getHeight(){…};
protected Path getWalkPath(){…};
protected void setWalkPath(){…};
…
protected void run(){…};
protected void Walk(){…};
protected void fly(){…};
}
可以设置Awatar的WalkPath,然后调用其Walk()方法,实现其自动漫游.替身还可以有多种行为功能,如语音提示.
4.2.4 地形跟踪
虚拟建筑环境经常是复杂的,当在一个起伏的地形环境中漫游的时候,须考虑地形的变化.图4-4是一个在虚拟环境中行走的示意:
地形跟踪需要不断的获取空间位置序列,使每一时刻该位置与其正下方投影线与"地面"(ground)的交点之间的距离为一定值.可以引用Awatar的概念,当Awatar
在"地面"上行走的时候,它的"眼睛"与地面之间总是Awatar的身高与二分之一头高尺寸之差.
在Java3D中,在观察方向上发出一条射线来寻找其与三维物体的交点称为Picking, Java3D的Picking API提供了该方法,可以采用该的方法不断的检测视点与地形垂直方向的距离,根据给定的视高,不断的调整视点的位置,图4-2说明了该方法.
图4-4所示的只是一种理想的状态,如果地形上有洞口的情况,Picking 对象将不能返回任何结果.另一种情况是漫游的路径上有一体积很大的物体,当Picking对象检测到该物体时,根据以前的算法视点将会突然上升,使画面显示产生大幅度变化.
虚拟建筑环境经常是复杂的,交互的漫游行为必须合乎人们日常的行为逻辑,比如人不能穿越墙体走进一个房间,不能徒步跨越水面,这些都是需要解决的问题,本文未涉及交互漫游的一些其它问题,留待下一步解决.
4.3 在三维虚拟场景中实现建筑物属性查询
当用户在一个虚拟的建筑环境中漫游的时候,或许还会想知道某栋建筑物的其它相关信息,如建筑物的名称,所有者,层数,面积等.
在三维的场景中实现建筑物的属性查询涉及几个问题:
(1) 建筑属性信息组织与存储.
(2) 在三维场景中对建筑对象进行拾取,获得该建筑物的标识.
(3) 根据建筑物标识提取及更新建筑属性数据.
4.3.1 建筑物属性数据的存储
根据不同的应用,建筑物可以包含各种属性信息,如建筑名称,建筑面积,层数,建成年代等,将这些信息存储在一个数据表中以便作其它应用.
在应用中将属性数据存储在一个Access表中,Java提供的JDBC-ODBC连接桥可以是Java方便的访问一个Accesss数据库文件.数据表的Building_id字段定义的是一栋建筑物的标识,某栋建筑物的名称应与其在VRML文件中的定义相匹配,如4.1节所述,在VRML文件被导入到Java3D中时可以根据节点的名称获取该节点的实例.当进行建筑物的属性查询时,用户的拾取(Pick)虚拟形体时可以首先获得该节点对象的类型及名称,然后将其作为查询的标识.
4.3.2 拾取Shape3D对象
在Java3D中,拾取(Pick)技术允许用户在3D空间拾取一个3D对象,当用户在屏幕上看到一个物体,然后移动鼠标到目标位置上并按下鼠标键时,Java3D从视点向投影平面上的鼠标点击点画一条射线,沿射线的方向检测是否有物体与该射线相交并可返回指定的物体.
在图形学的算法中,求交运算的计算量是很大的.Java3D通常不允许拾取,如果要拾取,需要明确调用场景的setPickable()方法或指定Group或Shape3D对象的ENABLE_PICK_REPORTING属性.另外,一些与拾取相关的类的构造方法中可以指定USE_BOUNDS或者USE_GEOMETRY属性.当指定了USE_BOUNDS属性时,求交运算只是判断Picking Ray是否和物体的大致轮廓相交,而不需判断其是否与真正的几何体相交,这样虽然使得点取的精度降低,但可以简化计算.
com.sun.j3d.utils.behaviors.picking包中是最常用的拾取行为类,可以根据这些工具类构造特定的鼠标拾取行为类.常用的类包括PickMouseBehavior类,PickObject类和PickCallback类.
PickMouseBehavior类是特定拾取类的父类,编写用户的拾取行为类一般要继承该类.PickMouseBehavior类常用的方法有:
Void initialize():该方法应被重载以提供出始状态和出始状态.
Void processStimulus(java.util.Enumeration criteria):该方法应被重载以提供对唤醒条件的响应.
Void updateScene(int xpos,int ypos):实现场景的更新.
PickObject类提供了哪一个对象被用户的拾取操作的方法,该类提供了多种适用于各种可能的拾取应用的方法.PickMouseObject是为给定的Canvas3D和BranchGroup创建的,以便在特定的Canvas3D内检测给定的SceneGraphObject是否被点取.
PickObject类常用的方法有:
PickObject(Canvas3D c,BranchGroup bg):构造方法,创建一个PickObject对象.
PickShape generatePickRay(int xpos,int ypos):创建一个PickRay对象,该射线以观察点为起点,以(int xpos,int ypos)为方向指向场景.
SceneGraphPath[] pickAll(int xpos,int ypos):该方法返回以观察点为起点,沿(int xpos,int ypos)方向的射线经过的可拾取的对象数组.
SceneGraphPath[] pickClosest(int xpos,int ypos):该方法返回以观察点为起点,沿(int xpos,int ypos)方向的射线经过的最近的可拾取的对象.
Node pickNode(SceneGraphPath sgPath,int Nodetypes): 该方法根据指定的类型从指定的SceneGraphPath中返回一个可拾取的Node对象的引用, Nodetype可以是下列类型:PickObject.BRANCH_GROUP,PickObject. GROUP,PickObject.PRIMITIVE,PickObject.SHAPE3D,PickObject.TRANSFORM_GROUP等.
对一个描述一栋建筑物的Shape3D对象进行拾取:
定义用户的拾取行为类,该类继承了PickMouseBehavior类:
class UserPick extends PickMouseBehavior{
private String BuildingId;
…
//构造方法
public UserPick(Canvas3D canvas,BranchGroup root,Bounds bounds)
{
super(canvas,root,bounds);
this.setSchedulingBounds(bounds);
root.addChild(this);
}
public void updateScene(int xpos,int ypos){
Shape3D shape;
shape=(Shape3D)pickScene.pickNode(pickScene.pickClosest(
Xpos,ypos,PickObject.USE_BOUNDS),pickObject.SHAPE3D);
If (shape !=null){
//获取被拾取的Shape3D形体对象的名称
if (shape.equals(TownHouse_01))
String BuildingId="Building_01";
}
}
}//End updateScene
…
}
pickScene.pickNode()返回一个可拾取的Node对象的引用,并被造型为Shape3D类型.
4.3.3 拾取TransformGroup对象
三维虚拟建筑环境中的建筑对象经常是复杂的,这种情况可以将其用多个Shape3D对象来表示,在将多个Shape3D对象封装在一个TransformGroup对象中.对整个建筑对象的拾取操作就可以通过其对应的TransformGroup对象的操作来实现.以4.3.2所述为例,首先将表示该建筑的Shape3D对象封装在TransformGroup对象tgBuilding_01中.
TransformGroup tgBuilding_01=new TransformGroup();
tgBuilding_01.addChild(building_01);
…
拾取tgBuilding_01对象:
TransformGroup tg;
TransformGroup=(Shape3D)pickScene.pickNode(pickScene.pickClosest(
Xpos,ypos,PickObject.USE_BOUNDS),pickObject. TransformGroup);
If (tg !=null){
//获取被拾取的TransformGroup对象的名称
if (tg.equals(tgBuilding_01))
String BuildingId="Building_01";
}
}
…
这样就实现了对该TransformGroup对象的拾取操作.
4.3.4 查询建筑属性
要实现建筑属性的查询,Java需要访问一个存储建筑属性的数据库文件.Java的数据库连接(Java DataBase Connectivity,JDBC)提供了Java程序跨平台,跨数据库的访问的能力.JDBC[5]分为两部分:Java中提供的可移植的JDBC API和通常由DBMS厂商或第三方提供的数据库专用的驱动程序,这些驱动程序遵守一定的接口,以保证一致的数据库访问代码.
JDBC定义了一套API对象和方法,用于与底层的数据库交互.一个Java程序首先打开与数据库的一个连接,并声明一个Statement语句对象,使用该Statement语句对象传送SQL语句到底层的DBMS.一般来说,JDBC类文件和Java Applet小程序驻留在客户端或是从网络上下载.而DBMS和数据源一般位于一个远程服务器上.
JDBC设计主要使用了ODBC的抽象和方法,对于具有ODBC开发经验的人员来讲,实现和使用JDBC更为容易.另外,Sun公司提供了JDBC-ODBC连接桥,利用JDBC-ODBC桥接器,这个驱动程序把JDBC的方法映射到ODBC上,这样就可以和任何可用的ODBC驱动程序进行交互了.
下面是实现JDBC查询的具体方法:
首先装载数据库的驱动程序,
try{
//装载JDBC-ODBC桥连接驱动程序
Class c =Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}catch (ClassNotFoundException ex){
//do something…
}
连接数据库,应用静态方法DriverManager.getConnection()建立数据库连接.数据源名称为"VRDataBase".
String dbURL="jdbc:odbc:VRDataBase";
Try{
…
Connection conn=
DriverManager.getConncetion(dbURL,"" ,"");//用户,密码
…
conn.close();//关闭连接
}catch(ClassNotFoundException e){
//do something
}catch(SQLException e){
//do something
}
发送一个JDBC查询并返回结果.
首先创建一个Statement语句对象,Statement对象执行一个SQL查询, BuildingId将作为SQL语句的一个条件来查找建筑名称与之匹配的记录,查询的结果以一个ResultSet对象返回.
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery
("Select * from BuildingInfo where building_name=BuildingId");
//打印返回记录的每个字段
while (rs.next()){
String building_id=rs.getString(1);
String building_name=rs.getString(2);
……
System.out.println("building_id"+building_id +" building_name " + building_name );
}
rs.close();
stmt.close();
conn.close();
可以利用AbstactTableModel类实现一个表模型,将返回的ResultSet对象格式化输出,这里不在赘述.
这样,就实现了在三维场景中通过拾取行为获得该虚拟建筑的属性信息的功能.关于其它数据操作,与Java3D并无直接关系,本文未作讨论.
4.4 基于Java3D和VRML的虚拟建筑环境的其它问题
4.4.1 场景图的优化
一个实时的三维系统涉及到高效的渲染系统,Java3D是基于场景图的结构的,一个Java3D程序创建的场景图可以被直接渲染,然而这样的效率并不高.Java3D提供了编译场景图的方法来将场景图结构进行可能的优化,提高渲染的效率.
图4-5是一个场景优化的例子,沿着场景图路径合并TransformGroup对象,左边的场景图被编译优化成右边的结构,该图只是说明优化的概念,并非Java的实际操作.
要提高图形显示速度,非常有效的方法是降低场景的复杂度,即降低图形系统需处理的多边形
数目.目前比较常用的方法有:预测计算,场景分块,可见消隐,细节层次模型(LOD)等[6].Java3D提供了LOD类来实现LOD技术.另外,本文讨论的虚拟建筑环境主要采用VRML作为场景的描述工具,VRML的LOD节点实现起来更为简单有效.另外,当场景较大时,可以根据观察者的状态采取一定的策略调入三维场景,将暂时不能被观察到的三维对象暂时从场景图中排除.
4.4.2 阴影
阴影对于建筑物造型来说具有重要的意义,它可以大大增加建筑物的层次感和形体表现能力.阴影计算往往涉及大量的计算,所以一般的实时渲染系统大多不涉及阴影的生成.在实际应用中,可以根据日常观察的经验大致的在地面上勾勒出建筑物平时的影子,做一多边形的来模拟阴影,实践证明,这一方法是有效的.
建立一个虚拟的建筑环境涉及诸多问题,特别是基于Internet的环境,本文只是初步涉及.
4.5 在互连网上发布程序
在互连网上发布Java3D程序,经编译的Java3D程序被包含在一个HTML文件的标签之间,当用户访问到包含Java3D的Web页面时,应检查用户是否已安装Java及Java3D运行环境,如未配置Java及Java3D运行环境,应提示用户到指定位置下载并安装,或给出错误信息.具体如下:
If you were using a Java-capable browser,
you would see ...! instead of this paragraph.
当这个HTML页面被浏览时,会自动检查客户端是否安装Java及Java3D的运行环境,如果该环境未安装,将自动从指定的网站下载并安装,具体流程如下:
4.6本章小结
1.VRML提供了虚拟环境的描述能力,Java3D丰富的Java及Java3D类库支持可用于实现复杂的编程行为.特别是应用Java3D可以快速的开发Web上的3D应用.本章提出综合采用VRML及Java3D建立虚拟建筑环境的应用框架.
2.实现对虚拟建筑环境中的场景对象的操作需要获取该对象,本章给出了在Java3D中获取场景对象实例的方法.
3.本章给出了在Java3D场景中实现虚拟场景中漫游的方法.
4.本章给出了在三维场景中实现虚拟建筑中查询建筑属性的方法,这里给出的只是一个简单应用模型.
本章参考文献:
[1] SGI CosmoCreate[OL]. http://www.sgi.com/cosmo.
[2] Dennis J Bouvier . Getting Started with the Java 3D API[OL]. http://java.sun.com/ products/java-media/3D/collateral/.
[3] Collision Detection System[OL]. http://www.j3d.org/implementation/collision.html.
[4] The Java 3DTM 1.2 API Specification[OL]. http://java.sun.com/products/java-media/3D/
[5] JDBC API[OL]. http://www.javasoft.com/products/jdbc/.
[6]潘志庚.马小虎.石教英.虚拟现实中多细节层次模型自动生成技术综述[J]. 中国图象图形学报,1998,(4):754—759
第五章 未来工作展望
将Internet与交互式的三维技术结合起来确实是一项激动人心的事情.将三维技术引入互连网的意义远远不止是为Web页面增添了一种表现形式,更在于借此可以建立跨越空间限制的虚拟的三维世界,实现Cyber空间①的梦想.
在Internet上建立虚拟的建筑环境将为建筑师,规划师提供更好的设计,交流,展示的手段.直接通过三维模型的方式进行交流是建筑师和规划师们喜欢的方式,而Internet将会最大限度的扩大了他们之间的交流范围.
然而,真正实现这一目标涉及大量的细节问题,本文只能是初步的涉及,更多的工作需要展开.要使得基于Web的虚拟建筑环境应用成为一个长期发展的项目,平台及工具的选择具有很大的重要性.本文的一个重要的工作是对实现虚拟建筑环境所选的开发平台做了必要的分析,在论文的前期,本人对目前流行的多种Web3D实现方案进行了一定的分析,认为采用Java3D与VRML具有更大的优势.
如3.8节所述JDK工具以及Java3D,JDBC,JMF等包是SUN公司免费的开发工具,通过Java3D建立的虚拟建筑环境应用不会涉及一般商业及授权问题,具有更大的长期效益. 选用Java3D作为基于网络的虚拟建筑环境的开发平台,有助于在应用中不断采用更为先进的算法,形成独立的技术核心.事实上,虚拟现实系统是一个极为复杂的系统,仅仅是图像生成部分,已有大量的研究集中于此,仍有大量的问题远未解决,尤其是如何快速的处理大规模的场景数据并实现实时渲染.
在Web上实现交互式的实时三维系统需要跨越更大的障碍.首先是网络的带宽,目前的网络传输条件对于传送复杂的三维场景数据来说远远不够,所以实际的应用中只能是尽可能的简化场景内容,这往往以牺牲场景的真实性为代价.
另一个障碍是三维场景的渲染引擎位于Internet的客户端,必然受到客户端软硬件条件的限制,Web3D程序运行在浏览器内,不能完全使用客户端的全部资源,必然影响程序的执行效率,这就需要采用更高效的算法提高场景渲染的速度.
在网络带宽一定的条件下,提高传输速度的有效方法是采用文件压缩技术,比如Shout3D也采用VRML作为场景的描述,同时Shout3D也提供了可选用.s3z的文件格式,对VRML文件进行了有效的压缩.随着应用的深入,关于Web3D资源的压缩问题必然成为一个不容回避的问题,值得指出的是,即
便网络的带宽在逐步提高,采用高效的压缩算法也是提高性能的有效方法之一.
本文只是提出了采用Java3D及VRML开发虚拟建筑环境的应用框架并实现了其基本功能,对于这些功能的实现还需完善及优化.以下是下一步的工作展望.
5.1 采用X3D描述三维虚拟场景
X3D是Web3D 联盟制定的下一代的开放式的网络三维的标准,X3D沿袭了VRML97的节点,域,域值的结构,并兼容VRML97标准,除此以外X3D支持MPEG-4.
X3D最大的特点在于X3D支持XML的编码格式,XML(eXtensible Markup Language)是一种具有数据描述功能,高度结构化及可验证的语言.在XML文件中,使用标记来描述数据,或配合属性来辅助描述数据, 因此,XML特别适合用于作为对象或标准的描述语言.XML可以借助验证规则(DTD Document Type Define或XML Schema)来规范一个XML的文件内容和结构,所以XML特别适合于作为多种应用的数据交换格式.
X3D采用XML编码具有以下的优势:
可移植性 – VRML本质上是一种标记语言,VRML97的结构和符号是基于Open Inventor的场景语法的,大多数网络应用几乎不支持VRML97语法.而XML目前已成为互连网上应用最广泛的标记语言,采用XML标记语言有助于获得其它网络应用的支持,在不同的应用中方便的移植.
页面整合性 - 在开发Web页面时,基于XML页面整合的系统,场景内容和执行都变得简单.
易于和下一代的网络技术整合 - W3C联盟(World Wide Web Consortium)的成员付出了巨大努力去发展XML.XML 获得了Netscape Communicator 和Internet Explorer等浏览器的广泛支持.X3D需要能和下一代的网络技术紧密结合,而XML正好是下一代的网络技术的趋势.
对于浏览采用X3D描述的三维虚拟场景,Yumetech发布了一个Java开放源代码版本Xj3D[1].Xj3D最初是由Sun Microsystems开发,现在是Web3D联盟的项目.发布Xj3D其目的之一是为X3D搭建了一个交流与测试的平台.Xj3D对XML的解析是基于DOM(Document Object Model)的,因此,对于一个比较大的XML文件,效率并不高.Xj3D正在进行的工作是将VRML/X3D应用到Java3D中,这意味着可以采用Java3D编写X3D的浏览工具.目前Xj3D最大的问题在于渲染的优化.
虚拟建筑环境的描述采用X3D,可以使其更容易的集成其它网络技术,一个重要的应用就是建立基于XML的三维场景数据库.
另外,基于XML的描述可以方便的扩展以适应不同的需要.如文献[2]提出采用XML建立的装修工程数据模型,将其链接施工进度管理信息,从而建立4D管理模型.
5.2 应用碰撞检测完善漫游行为
4-2节中提到关于漫游的相关的一些问题,如地形的跟踪,类似的如爬楼梯以及避免穿越场景对象等,解决此类问题涉及到碰撞检测的问题.
虚拟环境中,由于用户的交互和物体的运动,物体间可能会发生碰撞,此时为保持环境的真实性,需要及时检测到这些碰撞,并给出相应的处理,更新绘制结果,否则物体间会发生穿透现象,破坏虚拟环境的真实感.
虚拟环境中的物体采用的模型大致可分为体模型和面模型,目前的碰撞检测的研究工作的多数是基于面模型的.面模型又进一步分为很多种,如多面体模型,CSG,参数化曲面等.针对不同的模型有不同的碰撞检测算法[3].
碰撞检测还和场景的动态特征有关,一个场景可按场景对象的运动状况分为静态部分和动态部分,动态物体越多,碰撞发生的概率越大,碰撞检测的复杂度也越高,对于一个建筑漫游环境,场景中的大部分还是静态物体.
在Java3D中,可以利用特定的一组Java类实现碰撞检测,该类属于一种特殊的Behavior类.定义一个用于检查形体之间碰撞情况的行为对象,应在Behavior类的wakeupOn()方法的触发条件中根据不同情况指定下列对象:
WakeupOnCollisionEntry,
WakeupOnCollisionExit,
WakeupOnCollisionMovement.
其中WakeupOnCollisionEntry在指定的物体与场景中的其它虚拟物体第一次碰撞的时候被触发;WakeupOnCollisionExit在指定的物体与场景中的其它虚拟物体第一次从碰撞到脱离的时候被触发;WakeupOnCollisionExit在指定的物体与场景中的其它虚拟物体碰撞持续的时候被触发.
在Java3D中,为防止出现在漫游中出现的穿透建筑物的现象,应为viewPoint对象设置一个激活的区域,当该区域其与一个设定了collidable属性的场景对象之间相交或它们自己之间的距离答到一个设定的阀值时,Behavior对象将被激活,并调用processStitmulus()方法进行相应的处理.图5-1说明了该种情况.
应当指出,Java3D 的碰撞检查功能还处于不断的改进阶段,碰撞检测需要较多的计算时间.在实际的应用中,为提高碰撞检测的效率,还需选用高效的算法.文献[4]给出了一系列碰撞检测的公开算法包的简介.
5.3基于Web的虚拟建筑环境与数据库,GIS相结合
4.3节讨论了在虚拟建筑环境中实现建筑属性的查询,只是简单的通过JDBC访问一个建筑属性表,属性数据与场景的描述是单独设置的.三维场景采用XML描述,借助于XML的扩展能力,可以将建筑属性数据直接扩展到XML文件的内部,将建筑属性直接封装在建筑对象内部,实现类似"面向
对象"的思想.
更进一步的应用是建立基于XML的三维数据库,实现大规模的场景数据管理.另一种应用是实现三维图形界面的数据管理系统.
基于Web的虚拟建筑环境可以用来作为VRGIS,三维GIS及WebGIS的三维部分的支持.
本章参考文献:
[1] Xj3D Open Source VRML/X3D Toolkit[OL]. http://www.web3d.org/TaskGroups/ source/xj3d.html.
[2] 张建平. 基于Web和虚拟现实的建筑装修设计与管理系统[A]. 计算机辅助工程与建设系统信息化-第5届全国多媒体辅助工程学术会议论文集[C].新疆.2002-7.
[3]石教英. 虚拟现实基础及使用算法. 北京:科学技术出版社 2002, 216-246.
本章注释:
① CyberSpace一词最早出现于美国科幻小说家William Gibson,William Gibson是美国作家,描写电脑文明的先锋之一,在他的小说中描写了大量以复杂的计算技术为基础的离散的社会.1984年William Gibson出版了他的小说Neuromancer,Neuromancer中的不少词汇后来成为通用的词汇,如Cyber Space,Virtual Reality等等.
结 论
本文旨在结合建筑环境的特点,综合应用Java3D及VRML建立基于Web的虚拟建筑环境应用框架.
本文所述具体内容及相关工作内容如下(按在文章中出现的先后顺序排列):
1.分析当前Wed3D的发展现状和流行的实现技术手段,根据面向虚拟建筑环境的Web3D应用特点,提出了综合采用Java3D和VRML的实现方案.
2.分析VRML的技术特点,给出了采用LOD, 绿化植物造型采用纹理替代等有效的简化场景的方法,借以说明虚拟建筑环境应用的特点.
3.分析Java3D的技术特点,结合虚拟建筑环境应用的特点,讨论了Java3D的一些实现细节.
4.给出了综合采用Java3D及VRML的应用模型,并给出了虚拟建筑环境应用的基本功能的实现过程,论文还给出了在三维场景中直接拾取场景对象的方式获取虚拟建筑属性的实现方法,借以说明Java3D在建立虚拟建筑环境应用中一般应用.
论文的侧重点在于三维虚拟系统在网络环境特别是在Internet上的实现,侧重于虚拟建筑环境应用的特殊性和技术实现过程的一般性.可以得出结论,综合采用Java3D及VRML建立虚拟建筑环境应用的方法是非常有效的,采用VRML描述三维场景有助于场景资源的获取,而Java3D提供了开发基于Web的3D应用的理想工具.选用Java3D作为基于网络的虚拟建筑环境的开发平台,有助于在应用中不断采用更为先进的算法,形成独立的技术核心,更利于基于网络的虚拟建筑环境作为一个长期的项目发展.
文章最后提出了几个相关的待解决的问题,如场景渲染的进一步优化等问题,类似的问题很多,尚须逐步加以解决.
值得指出的是,基于建筑的虚拟建筑环境涉及的问题大都涉及到CAD,计算机图形学等专业的问题,尤其是一些底层的实现细节,限于本人进度和能力所限,一些想法未加以总结,所做工作也涉及不深,以期抛砖引玉或日后加以解决.
Web3D是相对较新的事物,甚至X3D的标准目前还在制定当中,致力于这方面研究的大量是各地的Web3D爱好者,是Internet将大家聚在一起。
上一页1234567