基于java+Java3D的网络三维技术设计与实现(毕业论文+程序源码)
大家好,今天给大家介绍基于java+Java3D的网络三维技术设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文答辩PPT模板等的小伙伴,可以进入我的博客主页查看左侧最下面栏目中的自助下载方法哦
文章目录:
1、项目简介
-
互联网的出现及飞速发展使IT业的各个领域发生了深刻的变化,它必然引发一些新技术的出现。3D图形技术并不是一个新话题,在图形工作站以至于PC机上早已日臻成熟,并已应用到各个领域。然而互联网的出现,却使3D图形技术发生了和正在发生着微妙而深刻的变化。Web3D协会(前身是VRML协会)最先使用Web3D术语,这一术语的出现反映了这种变化的全貌,没有人能严格定义Web3D,在这里我们把Web3D理解为:互联网上的3D图形技术,互联网代表了未来的新技术,很明显,3D图形和动画将在互联网上占有重要的地位。
-
Java3D API是Sun定义的用于实现3D显示的接口。使用Java 的重要理由之一是它的平台无关性。Java3D提供了基于Java的上层接口。Java3D把OpenGL和DirectX这些底层技术包装在Java接口中。这种全新的设计使3D技术变得不再繁琐并且可以加入到J2SE、J2EE的整套架构,这些特性保证了Java3D技术强大的扩展性
-
本文以Java3D为开发平台,利用Java语言强大的网络功能,实现了在网页上对3D动画进行显示和操作。
2、资源详情
项目难度:中等难度
适用场景:相关题目的毕业设计
配套论文字数:15643个字39页
包含内容:整套源码+完整毕业论文+答辩PPT
3、关键词
Java3D、Web3D、三维4、毕设简介
提示:以下为毕业论文的简略介绍,项目源码及完整毕业论文下载地址见文末。
第一章 绪论
§1.1 引言
互联网的出现及飞速发展使IT业的各个领域发生了深刻的变化,它必然引发一些新技术的出现。3D图形技术并不是一个新话题,在图形工作站以至于PC机上早已日臻成熟,并已应用到各个领域。然而互联网的出现,却使3D图形技术发生了和正在发生着微妙而深刻的变化。Web3D协会(前身是VRML协会)最先使用Web3D术语,这一术语的出现反映了这种变化的全貌,没有人能严格定义Web3D,在这里我们把Web3D理解为:互联网上的3D图形技术,互联网代表了未来的新技术,很明显,3D图形和动画将在互联网上占有重要的地位。
§1.2 互联网3D图形技术的应用
当前,互联网上的图形仍以2D图像为主流。但是,3D图形必将在互联网上占有重要地位。互联网上的交互式3D图形技术— Web3D正在取得新的进展,正在脱离本地主机的3D图形,而形成自己独立的框架。互联网的需求是它发展的动力。互联网的内容提供商和商业网站不断使用新的工具与技术使网站更具吸引力,Web3D图形是最新的和最具魅力的技术。Web3D图形将在互联网上有广泛应用,从目前的趋势来看主要有:
1.电子商务:
用3D图形展示商品,更能吸引客户。虚拟商场是人们热中的话题。客户可以在虚拟商场中漫游,挑选商品。许多Web3D图形技术的软件厂商是瞄准了电子商务的,如cult3D和viewpoint,其图形技术主要是用于商品的3D展示,您甚至于可以在网上操作或使用要购买的商品。然而,Web3D图形的商业利益究竟有多大,网上的商品销售商只有在能增加销售额的情况下,才肯出资制作Web3D图形。
2. 联机娱乐休闲与游戏:
多用户联机3D游戏将搬上互联网,现在您已经可以在网上经历简单的赛车或空中射击游戏,下载文件不超过2M。当然,如果您想运行大的联机游戏仍然需要CD-ROM的支持。娱乐休闲网站对Web3D图形有更多的需求,如:城市景观或风景点的虚拟旅游,虚拟博物馆,展览会,艺术画廊等等。
3. 医学:
医疗培训,医疗商业的B2B和B2,许多医学图像的处理将使用Web3D图形技术。
4. 地理信息系统的数据可视化:
将GIS与Web3D结合起来,可以在互联网上建立许多应用系统,如地图,导游,城市建设,交通运输等等。
5. 多用户虚拟社区(virtual-community):
虚拟社区是建立一个大型的虚拟场景,每个虚拟场景的访问者都可以指定一个"替身", "替身"在场景中可以漫游。当几个远程访问者同时访问虚拟社区时,它们可以用语音或文字通讯。虚拟社区可以是一个会场,教室,俱乐部,展览会,画廊等。它真正实现了虚拟现实,在互联网上仿真虚拟社会的各种活动,分布在世界各地的人可以借助互联网开展各种文化科技,娱乐活动。而此时虚拟场景就是他们的三维环境。虚拟社区很可能是Web3D图形在互联网上的一种主要应用形式。
§1.3 JAVA3D在Web中的成功
省略
第二章 Java3D技术的简介
Java3D用其自己定义的场景图和观察模式等技术构造了3D的上层结构,实现了在Java平台使用三维技术。本章将介绍Java3D特有的两个重要概念:场景图(Scene Graph)、观察模式(View Model)。在接口使用上的介绍分为两部分:说明如何使用Java3D接口;说明如何将Java3D技术与Java原有的Web技术(JSP、Serverlet)相结合,在网页上实现三维显示。
§2.1 Java3D概述
2.1.1 Java3D简介
Java3D API是Sun定义的用于实现3D显示的接口。3D技术是底层的显示技术,Java3D提供了基于Java的上层接口。Java3D把OpenGL和DirectX这些底层技术包装在Java接口中。这种全新的设计使3D技术变得不再繁琐并且可以加入到J2SE、J2EE的整套架构,这些特性保证了Java3D技术强大的扩展性。
JAVA3D建立在JAVA2(JAVA1.2)基础之上,JAVA语言的简单性使JAVA3D的推广有了可能。它实现了以下三维显示能够用到的功能:
- 生成简单或复杂的形体(也可以调用现有的三维形体)
- 使形体具有颜色、透明效果、贴图
- 在三维环境中生成灯光、移动灯光
- 具有行为的处理判断能力(键盘、鼠标、定时等)
- 生成雾、背景、声音
- 使形体变形、移动、生成三维动画
- 编写非常复杂的应用程序,用于各种领域如VR(虚拟现实)
2.1.2 Java3D与其他三维技术的比较
JAVA3D可应用在三维动画、三维游戏、机械CAD等多个领域。但作为三维显示实现技术,它并不是唯一选择而且是一个新面孔。在Java3D之前已经存在很多三维技术,这些三维技术在实现的技术、使用的语言以及适用的情况上各有不同,我主要介绍与Java3D又密切关系的三种技术:OpenGL、DIRECT3D、VRML
OpenGL
OpenGL是业界最为流行也是支持最广泛的一个底层3D技术,几乎所有的显卡厂商都在底层实现了对OpenGL的支持和优化。OpenGL同时也定义了一系列接口用于编程实现三维应用程序,但是这些接口使用C(C++)语言实现并且很复杂。掌握针对OpenGL的编程技术需要花费大量时间精力。
DIRECT3D
DIRECT3D是Microsoft公司推出的三维图形编程API,它主要应用于三维游戏的编程。众多优秀的三维游戏都是由这个接口实现。与OpenGL一样,Direct3D的实现主要使用C++语言。
VRML2.0(VRML97)
自1997年12月正式成为国际标准之后,在网络上得到了广泛的应用,这是一种比BASIC、JAVASCRIPT等还要简单的语言。脚本化的语句可以编写三维动画片、三维游戏、计算机三维辅助教学。它最大的优势在于可以嵌在网页中显示,但这种简单的语言功能较弱(如目前没有形体之间的碰撞检查功能),与JAVA语言等其它高级语言的连接较难掌握,因而逐渐被淹没在竞争激烈的网络三维技术中。
§2.2 Java3D的场景图结构
Java3D实际上是Java语言在三维图形领域的扩展,与Java一样,Java3D有纯粹的面向对象结构。Java3D的数据结构采用的是Scene Graphs Structure(场景图),就是一些具有方向性的不对称图形组成的树状结构(图1)。
实际由Java3D定义的一系列的对象,这些对象不是杂乱无序,对象之间也不是毫无关系。如果想让三维图像正常显示,必须在这两点上遵循Java3D场景图的规定。观察图1,Java3D场景图的树结构由各种各样的对象组成:
在图中出现的这些对象都实现了Java3D中有重要的意义的类,从逻辑上我将它们分为三类:
• 根节点(Root):Virtual Universe Object
• 节点(Node):Local Object、Branch Group Nodes、Behavior Node、Shape3D Node…
• 叶子节点(Leaf):Appearance、Geometry…
场景图中线和线的交汇点称为节点(Node),这些节点都是Java3D类的实例(Instance of Class),节点之间的线表示各个实例之间的关系。
• Virtual Universe是根节点,每一个场景图的Virtual Universe是唯一的。
• 在Virtual Universe下面是Locale节点,每个程序可以有一个或多个Locale,但同时只能有一个Locale处于显示状态,就好像一个三维世界非常大,有很多个景点,但我同时只能在一个景点进行观察。Java3D允许从一个Locale跳到另一个Locale,不过绝大多数程序只有一个Locale。
• 每一个Locale可以拥有多个Branch Group节点。所有三维形体的其位置信息(Transform Group Nodes)都建立在Branch Group节点之上。
• Transform Group Node用来设定Shape3D在Virtual Universe中的位置。
• Spape3D Node是三维图形节点,这个节点的实体放映在最后的显示画面中,就是三维世界中的每个形体。包括正方体、球体以及任何形状和外观的三维形体。
• 位于场景图最下层的是两个叶子节点:三维体的外观(Appearance)和几何信息(Geometry),这两个节点定义了一个三维体的显示效果。
• View Platform位于图1的另一个分枝上,与前面所有描述三维体的性质的概念不同,View Platform和View都是用来定义观察者的信息。
对于建立一个简单的Java3D程序,我至少需要了解三个概念:虚拟宇宙(Virtual Universe)、场景(Locale)、坐标系统。
2.2.1 虚拟宇宙(Virtual Universe)
在Java3D中,虚拟宇宙被定义为结合一系列对象的三维空间。虚拟宇宙被用作最大的聚集体表现单位,同时也可被看作一个数据库。不管是在物理空间还是逻辑内容,虚拟宇宙都可以很大。实际上在大多数情况下,一个虚拟宇宙就可以满足一个应用程序所有的需求。
虚拟宇宙是各自独立的个体,原因是在任何时候一个结点对象都不能在超过一个的虚拟宇宙中存在。同样的,在一个虚拟宇宙中的结点对象也不能在其他的虚拟宇宙中可见或者与其他的对象结合。 对于一个Java3D应用程序,必须定义一个虚拟宇宙才可以在这个"宇宙"中显示三维图像。
2.2.2 Java3D的坐标系统
默认情况下,Java3D的坐标系统是右旋的,用方位语义学来解释就是:正y方向是本地重力的上,正x方向是水平的右,正z是这对着观察者的方向。默认的单位是米。 双精度浮点、单精度浮点甚至是定点来表示的三维坐标都足够来表示和显示丰富的3D场景。不幸的是,场景不是真实世界,更不必说整个宇宙了。如果使用单精度坐标,有可能出现下列情景:
- 离原点仅有一百公里的距离,被描绘得相当量子化,所能达到的最好效果就是三分之一英寸,在实际应用中这样的精度比要求的粗糙的多。
- 如果要缩小到一个很小的尺寸(例如表现集成电路的大小),甚至在离原点很近的地方就会出现同坐标问题。
为了支持一个大型的邻接虚拟宇宙,Java3D选择了有256位的高分辨率坐标:
Java3D高分辨率坐标由三个256位的定点数组成,分别表示x、y、z。定点被固定在第128位,并且值1.0被定义为真实的1米。这个坐标系统足够用来描述一个超过几百万光年距离的宇宙,也可以定义小于一质子大小(小于一普朗克长度)的对象。
在Java3D中,高分辨率坐标仅仅用于将更加传统的浮点坐标系统嵌入更高分辨率的底层系统。用这种方法,可以创造出一个具有任意大小和规模的在视觉上无缝的虚拟宇宙,而且可以不必担心数字上的精度。(参看表2)
一个256位的定点数还具有能够直接表示几乎任何的合理适当的单精度浮点值。
Java3D用有符号的、两位补码的256位定点数字来表示高分标率坐标。尽管Java3D保持内部高分辨率坐标表示的不透明,但用户用有八个整型变量的数组来表示256位的坐标。Java3D把数组中从索引号由0到7分别看作高分辨率坐标的从高到底位上的数。第128位上是二进制的小数点,也可以说在索引号为3和4的整数之间。高分辨率坐标的1.0就是1米。 如果是"小"的虚拟宇宙(类似于相对比例的几百米),在虚拟宇宙对象下(0.0,0.0,0.0)点建立一个带有高分辨率坐标的Locale作为根节点就足够使用了;装入程序在装入过程中能自动构建结点,而在高分辨率坐标下的点不需要任何外部文件的直接描述。 大一些的虚拟宇宙期待被构建为有如同计算机文件那样的层次,这意味着一个根宇宙要包含由外部文件引用的嵌入虚拟宇宙。就这样,文件引用的对象(用户指定的Java3D组或高分辨率结点)定义了被读入现存虚拟宇宙的数据的位置。
2.2.3 场景(Locale)
为了支持大型虚拟宇宙,Java3D提出了"Locale"的概念。Locale把高分辨率坐标作为起源。把高分辨率坐标看作精确的定位,它在高分辨率坐标的影响范围之内使用精度较低的浮点坐标指定对象的位置。
一个Locale和与它结合的高分辨率坐标一起组成了在虚拟宇宙之下的一个表现层。所有虚拟宇宙包含一个或多个高分辨率Locale。而所有其他的对象都是附加在一个Locale上的。在整个体系中,高分辨率坐标扮演的是上层的仅供翻译的转换结点。例如,附加到一个特定Locale的所有对象的坐标都会与这个Locale位置的高分辨率坐标有关。(图2)
图2:高分辨率坐标指定场景
如果一个虚拟宇宙与传统的计算机图像的概念相近,给定的虚拟宇宙可能会变得太大。所以在通常情况下最好把一个场景图看作是一个高分辨率坐标场景的子结点。构造一个三维场景,程序员必须运行一个Java3D程序。这个Java3D应用程序必须首先创建一个虚拟宇宙对象并且至少把一个Locale对象附加之上。然后,构建出需要的场景图像,它由一个分支组结点开始并且包括至少一个观察平台对象,而场景图就是附加于这个观察平台。当一个包含场景图的观察对象被附加于一个虚拟宇宙,Java3D的渲染循环就开始工作。这样,场景就会和它的观察对象一起被绘制在画布上。
§2.3 实现三维世界
2.3.1 Java3D的观察模式
Java3D引入了一种新的观察模式,这种模式使Java编写的显示效果符合"编写一次,随处运行"的原则。Java3D还把这种功能推广到显示设备或六等级自由度输入外部设备,例如跟踪摄像头。这种新的观察模式的"一次编写,随处观察"的特性意味着用Java3D观察模式编写的应用程序和Applet可以广泛应用于各种各样的显示设备。在不修改场景图的条件下,图像可以在包括标准电脑显示、多放射显示空间和安装摄像头设备的显示设备上被渲染。这也意味着在不需要修改场景图的情况下,同一个应用程序既能够渲染立体景象,还能通过摄像头的输入控制渲染过的观察图。 Java3D的观察模式通过完全分离虚拟和现实世界来实现这种多功能性。这种模式区分了以下两种情况:
- 一个应用程序通过控制观察平台的位置和方向在虚拟宇宙中对一个观察台对象(ViewPlatform)定位、定向和设定比例尺;
- 渲染器使用已知位置和方向计算出要使用的观察对象,对终端用户物理环境的描述确定用户在物理环境中的位置和方向。
为什么使用一个新的模式,由于在底层的编程接口中可以找到基于照相机的观察模式,开发者通过它可以控制所有渲染图的参数。它可以应付处理常规的应用程序,但是处理有更广阔的适应性的系统的时候就显得力不从心,这些系统包括:把整个世界作为一个单元装入和显示的观察器或浏览器、可供终端用户观察、操纵、显示、甚至与虚拟世界交互的系统。
基于照相机的观察模式仿效在虚拟世界中放置一个照相机而不是一个人。开发者必须持续重新配置一个照相机来模拟"在虚拟世界中有一个人"。Java3D观察模式直接和跟踪摄像头结合。在有摄像头的情况下,用户会有好像他们是真实的存在在那个虚拟世界的错觉,而开发者可以不做任何附加的工作就可以为用户带来这种效果。在没有摄像头并且只是用来表现一个单一的标准显示的情况下,Java3D观察模式表现得更像传统的基于照相机的观察模式,只是加上了能够产生立体透视图的功能。在一个需要由物理环境规定一些观察参数的系统中,让应用程序来控制所有的观察参数并不合理。例子就是:一个带有摄像头的显示设备可以用其光系统直接决定应用程序中的观察领域。不同的设备有不同的光系统,程序开发者硬绑定这样的参数或允许终端用户改变这样的参数都是不合理的。另外一个例子是:一个可以由用户当前的头部位置自动计算出观察参数的系统。只有一个对世界的说明和一条预先定义的轨迹可能不会严密的定义一个终端对象的观察。对于有摄像头设备用户,他们可能会期待在沿着一条固定的路线前进的时候能够看到他们左右两旁的物体。就好像在一个游乐场中,游客乘坐观光车按照固定的路线参观游乐场,但是在这过程中,游客可以持续转动他们的头。
由于依靠终端用户的具体物理环境,观察的各个参数,尤其是观察和投影的基体变化很大。影响观察和投影基体的因素包括显示设备的物理尺寸,显示设备的安装方法(在用户的桌面或用户的头顶上),计算机是否知道用户的头在三维空间的位置,头顶装置真实的观察领域,显示设备上每平方英寸的像素数,还有其他类似的参数。Java3D建立的观察模式完全可以满足上述所有的需求。
2.3.2 Java3D中用来定义观察的对象
Java3D通过几个对象来发布它的观察模式。特别是View对象和与它相关的组件对象: PhysicalBody对象、PhysicalEnvironment对象、Canvas3D对象、Screen3D对象。图3描述了View对象的中心角色和组件对象的辅助角色。
观察有关的对象都在图3中,它们起的作用如下:
ViewPlatform(观察平台):一个view用一个叶子结点来在场景图为自己定位。观察平台的起始结点指定了它的位置、方向和在虚拟世界中的比例尺。
View(观察):主要的观察对象包含了很多观察的状态。
Canvas3D:抽象窗口工具箱中画布对象的3D版本。它描绘了一个可以让Java3D在上面画图像的窗口。它包括了一个对Screen3D对象的引用和描述一个Canvas3D要用到的尺寸、形状和位置信息。
Screen3D:一个包含描述显示荧屏物理属性信息的对象。Java3D把显示荧屏信息分别放在单独的对象中,这样做可以防止在每一个Canvas3D对象中不同的显示屏幕信息共享一个屏幕。
PhysicalBody:一个包含刻度信息的对象,它描述了用户的物理身体。
PhysicalEnvironment:一个包含刻度信息的对象,它描述了物理世界。主要的信息描述了环境的六自由度硬件。
图3:View和它的组件对象以及它们的相互联系
这些对象一起描述观察的几何体胜于明白的提供观察或投影基体。Java3D的表现工具用这个信息来构造适合的观察和投影基体。这些观察对象的几何中心为产生一个观察提供了更大的弹性,这种弹性需要支持可以选择的显示配置。
ViewPlatform: 在虚拟世界中的位置 一个ViewPlatform结点定义了一个坐标系统。这样,在虚拟世界中就有了一个有原点或参考点的参考系。观察平台是一个附加在观察对象的点并且作为决定描绘工具观察的基础。图4表示了一个场景图的一部分,它包括一个观察平台结点。直接在观察平台之上的结点决定了它在虚拟世界中的位置和方向。应用程序和行为通过修改直接在观察平台之上任何与TransformGroup结点结合的Tramsform3D对象可以在虚拟世界中任意移动ViewPlatform。一个简单的应用程序可能直接在一个观察平台上定义一个TransformGroup结点。一个虚拟宇宙可能有很多不同的观察平台,但是一个特定的View对象只能附加于一个单一的观察平台之上。这样,每个画在Canvas3D上的图画都是从一个单一的观察平台开始。
图4:包含观察平台的一部分场景图
2.3.3 在三维世界中建立、移动观察点
应用程序通过修改观察平台的上级TransformGroup在虚拟世界中航行。修改一个观察平台的位置和方向的应用程序的例子包括:浏览器、提供航行控制的阅读器、做建筑预设计的程序、甚至是搜寻和毁坏游戏。
控制观察平台对象能产生很有趣和有用的结果。我可以定义一个简单的场景图,这个程序的目的是在窗口的正中画了一个对象并且绕自己的中心转动。不管在中心的对象,而让ViewPlatform在虚拟世界中绕圈。如果形体结点包括一个地球模型,这个程序可能产生一个类似于绕地球的远航员观察对象。如果在这个世界中加入更多的对象,这个场景图允许经由行为结点来浏览整个虚拟世界。
图5:一个由观察控制的简单场景图
应用程序和动作通过TransformGroup的可访问方法操纵它。这些方法允许应用程序得到和设置组结点的Transform3D对象。Transform3D结点有setTransform和getTransform两个方法。
形体移动的实现向来都是三维实现的难点和复杂之处,传统三维技术的实现多是注重模拟三维物体的真实移动。而Java3D除了提供传统的方案,还可以在一个存在的三维世界中移动一个观察点,借助观察点的移动模拟物体的移动。如同物理所学的切割磁力线发电,转子和静子本来就是一对可以互逆的对象,结果都是把动能转化为电能。例2的代码显示了在Virtual Universe中建立Viewer、ViewPlatForm、和如何通过绑定OrbitBehavior实现移动ViewPlatform。
2.3.4 Java3D的网络基础
将Java3D与Java平台技术的结合。Java3D可以很容易的与Java平台的其他技术相结合,如Applet、JSP、Serverlet、JDBC、EJB等。100%的纯Java实现是Java3D可以与如此多的Java平台技术结合的根本原因:
- 同是Java平台保证Java3D可以在Applet中实现;
- Applet使Java3D可以轻易的在网页中显示;
- JSP、Serverlet技术保证将动态网页技术用于Java3D显示;
- Serverlet本身就是J2EE平台的核心技术,这使得Java3D可以搭建于J2EE平台。更可以使用所有J2EE的其他技术:JDBC、EJB、JMS…
第三章 实现JAVA3D结构体系的方法
§3.1 总体设计
设计思想是:以JAVA3D为平台,使用JBuilder编译器,生成一个三维小场景,实现简单实体建模,物体运动,场景移动,各种灯光,雾等场景变换操作以及更换背景图片增加背景音乐等三维体系的基本功能。
§3.2 基本形体的生成
和VRML不同,JAVA3D没有基本形体类,因而在程序中无法直接生成大量应用的基本形体,如BOX、CONE、SPHERE等。我们可以通过复杂的编程生成这些基本形体,也可以直接调用JAVA3D为我们提供的geometry classes,利用它生成程序所需要的BOX、COLORCUBE、CONE、SPHERE、CYLINDER。下面是这些基本体的生成方法。
3.2.1平板的生成
UTILITY里BOX的构造函数有:
1.Box():成一个各边尺寸均为2的BOX,要说明的是,BOX、COLORCUBE、SPHERE的坐标原点均在其中心点,CONE、CYLINDER的则在其轴线的中点上。
6. Box(float xdim, float ydim, Appearance ap) :成一个给定尺寸、给定外观属性的BOX ,例Box(.5f, .6f, .4f, myApp)
7. Box(float xdim, float ydim, float zdim, int primflags, Appearance ap):生成一个有特定说明的BOX,例如:Box(.4f,.6f,.3f,Primitive.ENABLE_APPEARANCE_MODIFY, ap)表示程序在运行时可以改变其外观属性。
3.2.2 立方体的生成
UTILITY里COLORCUBE的构造函数有:
8. ColorCube()
生成一个边长均为2的COLORCUBE
9. ColorCube(double scale)
将边长均为2的COLORCUBE按比例放大缩小。
3.2.3 圆锥的生成
UTILITY里CONE的构造函数有:
10. public Cone()
生成一个底半径为1,高为2的CONE。
11. Cone (float radius, float height)
12. Cone (float radius, float height, int primflags, Appearance ap)
13. Cone(float radius, float height, int primflags, int xdivision, int ydivision, Appearance ap)
这里,xdivision、ydivision可用来表示圆锥的显示是高精度的显示,或是底精度的显示,缺省时的中等精度时xdivision = 15; ydivision = 1; 我们可利用这两个参数来改变显示的效果,使显示圆锥的三角片更多或更少些。
3.2.4 球体的生成
UTILITY里SPHERE的构造函数有:
14. Sphere()
生成一个半径为1的SPHERE。
15. Sphere (float radius)
16. Sphere (float radius, Appearance ap)
17. Sphere(float radius, int primflags, Appearance ap)
18. Sphere(float radius, int primflags, int divisions)
19. Sphere(float radius, int primflags, int divisions, Appearance ap)
这里,divisions的作用和圆锥的xdivision、ydivision相似。
3.2.5.圆柱体的生成
UTILITY里CYLINDER的构造函数有:
20. Cylinder()
生成一个底半径为1,高为2的CYLINDER。
21. Cylinder (float radius, float height)
22. Cylinder (float radius, float height, Appearance ap)
23. Cylinder (float radius, float height, int primflags, Appearance ap)
24. Cylinder(float radius, float height, int primflags, int xdivision, int ydivision, Appearance ap)
§3.3 点、线、面的生成
3.3.1点的生成
编写JAVA3D程序实际上是编写一个特定的场景图,给出了场景图中带有形体及其属性的一个分支(BranchGroup)和表示观察位置等数据的另一个分支(View Platform)。一般来说,表示观测位置的分支可以用JAVA3D的UTILITY来完成,即createSceneGraph方法的定义。
在这个方法里,程序先定义了一个分支objRoot,然后用数组的形式定义了顶点坐标vert和颜色color,再用PointArray 定义了一组点point,并将顶点坐标及颜色赋值给point,由于JAVA3D中的PointArray点是Shape3D的子类,它不能直接放入一个BranchGroup,因而我们还要先定义一个Shape3D对象shape,再将point赋予shape,这样point就可以放入BranchGroup类型的对象objRoot中了。
JAVA3D提供的API中,可用于生成Point的对象有: PointArray IndexedPointArray
25. PointArray
PointArray的构造函数为:
PointArray( int vertexCount, int vertexFormat );这里,vertexCount表示应生成的点的数目,vertexFormat表示所需要的顶点的格式。
点、线、面几何体所需要的顶点的格式有:
COORDINATES 顶点坐标数组
NORMALS 顶点法向数组
COLOR_3 不带alpha值的颜色数组
COLOR_4 带alpha值的颜色数组
TEXTURE_COORDINATE_2 二维纹理坐标数组
TEXTURE_COORDINATE_3 三维纹理坐标数组
26. IndexedPointArray
IndexedPointArray的构造函数为:
IndexedPointArray( int vertexCount, int vertexFormat,int indexCount );
利用本函数,我们可以从众多的点中,选择特定的点来显示。这里,vertexCount表示顶点坐标数组所提供的点的总个数,indexCount表示最终应生成的点的个数。JAVA3D可以生成任意大小的点,并且可以使点为方点或圆点。
3.3.2直线的生成
利用JAVA3D的一些对象,生成各种直线。可以生成直线的对象有:
27. LineArray
28. LineStripArray
29. IndexedLineArray
30. IndexedLineStripArray
我们可以根据各种不同的情况,生成不同的直线,如给定宽度的直线、虚线等。相应的的方法有:setLineWidth(float lineWidth)
setLinePattern(int linePattern)
setLineAntialiasingEnable(boolean state)
对于线型linePattern有以下数据可选:
int PATTERN_SOLID,int PATTERN_DASH,int PATTERN_DOT,int PATTERN_DASH_DOT
这些内容对所有种类的直线都有效。
3.3.3面的生成
生成平面的对象及其定义
JAVA3D可通过编程显示出面来,面有两种:三角形和四边形,相应的对象为Triangle和Quad。
JAVA3D用于生成平面的对象有:
31. TriangleArray
32. QuadArray
33. TriangleStripArray
34. TriangleFanArray
35. IndexedTriangleArray
36. IndexedTriangleStripArray
37. IndexedTriangleFanArray
§3.4 外部复杂形体的调用
利用前面介绍的方法生成我们所需要的基本形体,生成点、线、平面。但有的时候,我们需要用到其它格式的三维形体,如VRML2.0格式的图形文件,AUTOCAD绘出的DWG格式的三维形体,3DS MAX绘制出的复杂形体。对于这些形体,我们可以非常方便地将其用到JAVA3D程序中去。下面我们介绍一些图形格式在JAVA3D中的应用方法。
一. Wavefront的OBJ格式的图形文件的调用
JAVA3D编译环境所带的UTILITY有两个LOADER,一个可用来调用Wavefront软件的OBJ格式的三维图形格式文件,一个可用来调用Lightwave软件的LWS及LWO格式的三维图形格式文件。
为了使JAVA3D能够调用Wavefront的OBJ格式的图形文件,程序的头四行import语句就是用来处理Wavefront的OBJ格式的图形文件,第五行的import语句则是打开外部文件之用。
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.Scene;
import java.io.*;
二. VRML2.0(VRML97)图形文件在JAVA3D中的应用简介
利用VRML97的LOADER我们可以在JAVA3D程序中方便地调用VRML图形。调用VRML97程序就象调用Wavefront的OBJ一样简单。
三. AUTOCAD R14的DWG图形及3DS MAX图形在JAVA3D中的应用。
在三维图形生成过程中,国内目前大量使用AUTOCAD及3DS MAX等软件。对于3DS MAX软件,处理起来非常方便 3DS MAX可以将其图形直接输出成VRML97格式。对于AUTOCAD R14来说,目前还不太方便,需借助第三方软件转换成JAVA3D支持格式。
§3.5背景变换的实现方法
3.5.1 灯光
光用于照亮场景中的几何对象。有几种不同的光类型,它们都是抽象 Light 类的子类。所有光都有一个颜色值,即开/关位,以及一个描述它照亮的场景区域的绑定对象。在现实世界里,周围的对象被几个不同的光源照亮。从窗户射进的阳光和屋顶的灯光一起照亮了屋内的一切。两种光都会影响屋内对象的颜色和外观。在 Java 3D 中,可以通过使用多个光源来模拟实际的光照效果。
光的类型
环境光:在场景中 AmbientLight 无处不在。它不发自某个特定点,也不指向某个特定方向。
它的方法:
AmbientLight ( )
点光:
Point Light 从一个指定位置向各个方向辐射,并随着距离的增加而减弱。点光源的一个例子是没有灯罩的台灯。
它的方法是:
PointLight( )
void setPosition( Point3f pos )
Spotlight PointLight的继承,是一种将光的范围限制在一个圆锥形内的点光源。聚光源的一个例子是手电筒。
直射光:DirectionalLight 的光线射向某一个特定方向,却不发自任何特定的位置。这种定向光的所有光线都平行发射。虽然从技术上说,太阳是一个点光源,但使用 DirectionalLight 可以更准确地模拟太阳光。
所有的 Light 节点都是场景图中的叶节点。创建它们时,需要指定 Bounds 对象;我们使用 BoundingSphere。光将仅仅影响那些位于光的 BoundingSphere 所定义的空间内的几何对象,因此我们需要确保 BoundingSphere 足够大。在创建完光之后,我们用Scene1.addChild( Node );将其附加到场景图的顶部 BranchGroup。光、行为和材质都在场景图的上面添加。
3.5.2 纹理贴图
装入纹理 同光照一样,纹理贴图影响整个几何对象。再一次使用 Appearance 类来指定纹理贴图效果。
Java 3D 简化了装入纹理图像的过程。TextureLoader 类位于 Java3D 实用类中。为了看起来更真实,请总是将纹理图像的宽度和高度设置成 2 的幂。其它的值会导致 TextureLoader 将纹理压变形。
Primitive 类将生成纹理坐标――就象它们为计算光照生成法线一样。
3.5.3 雾
雾效果可以增添场景的真实感,也可以使远处的形体变模糊或是屏蔽它们,也可以使场景产生透视效果。
Java3D中可以用ExponentialFog类添加雾效果。
它的方法:
ExponentialFog ( )
§3.6 动画的生成
所有的内插器节点在使用时都需要与TimeSensor(时间传感器)配合使用。TimeSensor把给定的时间周期归一化,虽然时间的周期 cycleInterval 有给定的秒数,但计算机内部将其处理成从0.0到 1.0,即起始时间为0.0,终止时间为1.0,假如一个时间周期为 20(单位均为秒),则第6秒的归一化结果是0.3,第10秒的归一化结果是0.5,第20秒的归一化结果是1.0。 Alpha可以输出从0到1之间的数值给特定的内插对象,当Alpha输出的数值为0时,对应的特定内插对象的值为最小;当Alpha输出的数值为1时,对应的特定内插对象的值为最大;当Alpha输出的数值为0到1之间的数值时,对应的特定内插对象生成和Alpha成相同比例的数值。假设某一时刻Alpha输出的数值为0.2,则对应的特定内插对象的当前值为最小值加上最大最小值之差乘以0.2。(当前值-最小值)/(最大值-最小值)=0.2
JAVA3D里的各种Interpolator对象可用来旋转形体、移动形体的坐标、变化形体的颜色等。假设我们要让一个形体在规定的时间内按照指定的方式运动,我们首先要给出时间段的大小,还要指出时间是否要循环。这些内容都是由Alpha类来完成的。基本上我们用它以及一个旋转内插器RotationInterpolator来使形体绕着其所在的局部坐标系不停地旋转。
第四章JAVA3D场景的实现
§4.1Java3D的实现流程
本次毕业设计中实现一个JAVA3D场景,其中包括各类灯光的实现,三维场景的移动,任意物体的运动,场景背景变换,指数雾的实现以及与之配合的背景音乐.
该3D场景设计中运用到立方体、圆锥及椭圆等基本形体,生成Temple和Tower;各种点、线、面生成地面及背景环境。以下即是其设计流程图:
图6 结构设计流程图
§4.2 JAVA3D的建模
4.2.1 生成场景:(SimpleUniverse在哪生成的并没说清楚)
先生成一个Scene1场景作为父结点,以后在此结点下加入子结点完成各种操作及图形显示。:
public Group buildScene( SimpleUniverse u) // 继承Group类
{
Group Scene1= new Group ( );
……
return Scene1;
}
这里的SimpleUniverse是对VirtualUniverse的继承,一个应用程序只有一个SimpleUniverse(VirtualUniverse)。它同时定义了其下的Locale、Node、Group及BranchGroup结点。
4.2.2 Temple的圆柱体的构建
在程序中定义了一个函数buildColumns来生成一对圆柱体
// 开始构建柱体
Vector3f trans = new Vector3f( );
Transform3D tr = new Transform3D( );
TransformGroup tg;
for ( int i = 0; i < NumberOfColumns; i++ )
{
// 左边的圆柱
trans.set( x, y, z );
tr.set( trans );
tg = new TransformGroup( tr );
tg.addChild( new Link( column ) );
group.addChild( tg );
z += zSpacing;
}
// 柱体构建完毕
return group;
}
然后创建一个函数ColumnScene设置光线、纹理,并将buildColumns加入
public ColumnScene (Component observer)
{
// 在地面上构建一系列圆柱
SharedGroup column = buildSharedColumn ( );
Group columns = buildColumns (column);
addChild (columns);
}
在4.1.1生成的场景中利用addChild方法调用ColumnScene函数,
Scene1.addChild (new ColumnScene (this));
即在场景中显示构建好的圆柱体。
图7利用Java3D构建的Temple
4.2.3 Tower的构建
创建函数TowerScene构建Tower场景,并加到Scene1中
public TowerScene (Component observer)
{
……
// 构建粗糙的地面
CraterGrid grid = new CraterGrid (
50, 50, // 栅格范围
1.0, 1.0, // 位置
4.0, // 高度放大比例
craters, // 栅格仰角
moonApp ); // 显示
addChild (grid);
……
// 构建金字塔
Arch towerShape = new Arch (
0.0, // 起始λ角
1.571, // 结束λ角
2, // nλ
0.0, //起始θ角
Math.PI*2.0, // 结束θ角
5, // nθ
3.0, // 起始半径
8.0, // 结束半径
0.0, // 起始λ层
0.0, // 结束λ层
towerApp); // 显示
tower.addChild (towerShape);
}
插入到Scene1场景中,
Scene1.addChild(new TowerScene (this));
在这里面函数CraterGrid是建立粗糙栅格表面,Arch是建立给定参数的一个弧面。这两个函数是Java3D里已经定义好的功能所以这里就直接拿来调用,而不给出具体建模的算法了。
图8加入TowerScene后的场景效果
§4.3 动画的实现
4.3.1 调用galleon.obj文件
将galleon.obj文件调入到场景中要加入五行import ,
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.Scene;
import java.io.*;
下面这段代码就是用来调用外部OBJ文件的,
TransformGroup trans = new TransformGroup ();
trans.setCapability(trans.ALLOW_TRANSFORM_READ);
trans.setCapability(trans.ALLOW_TRANSFORM_WRITE);
int flags = ObjectFile.RESIZE;
ObjectFile f = new ObjectFile(flags, (float) (49.0 * Math.PI / 180.0));
Scene s = null;
try {
s = f.load("galleon.obj"); // 读出obj文件在工程目录下
}
然后再把它加到场景中去,
trans.addChild(s.getSceneGroup());
Scene1.addChild(trans);
4.3.2 物体转动
要使galleon转动学要用到interpolator behaviors,它继承了Behavior类。转动的类是RotationInterpolato。
Alpha spinAlpha = new Alpha (-1, 4000);
spinAlpha.setCapability (Alpha.DECREASING_ENABLE);
spinAlpha.setCapability (Alpha.INCREASING_ENABLE);
spinner =
new RotationInterpolator(spinAlpha, trans);
spinner.setEnable(false);
spinner.setSchedulingBounds (
new BoundingSphere (new Point3d(), 1000.0));
trans.addChild (spinner);
这样就使得galleon.obj的帆船在场景中转动了。
图9物体转动效果图
4.3.3场景的移动
1.鼠标交互移动
主要实现了“行走模式”和“视检模式”两种模式,具体方式可用Java3D封装的WalkViewerBehavior以及ExamineViewerBehavior两个类来实现,这两个类都是对ViewerBehavior类的继承。
examineBehavior = new ExamineViewerBehavior(
exampleSceneTransform,
exampleFrame);
examineBehavior.setSchedulingBounds (allBounds);
sceneRoot.addChild (examineBehavior);
walkBehavior = new WalkViewerBehavior(
exampleViewTransform,
exampleFrame );
walkBehavior.setSchedulingBounds (allBounds);
sceneRoot.addChild (walkBehavior);
2.场景的自动移动
在这个小场景中,使用了PositionInterpolator类来实现场景位置的前后来回自动移动,
TransformGroup vpTrans =
universe.getViewingPlatform().getViewPlatformTransform(); //这条语句是让操作对整个场景的,而不是某个物体
Transform3D axisOfTranslation = new Transform3D ();
Alpha transAlpha = new Alpha (-1,
Alpha.INCREASING_ENABLE |
Alpha.DECREASING_ENABLE,
0, 0,
5000, 0, 0,
5000, 0, 0);
axisOfTranslation.rotY(-Math.PI/2.0); // 延X轴平移
translator = new PositionInterpolator(transAlpha,
vpTrans,
axisOfTranslation,
-4.0f, 20.5f); // 起始位置,中止位置
translator.setSchedulingBounds(bounds);
translator.setEnable(false);
objScale.addChild(translator);
Scene1.addChild (objScale);
这样场景就可以自动从-4.0到20.5的位置移动了。
§4.4 背景变换
4.4.1 创建灯光
在这个场景中创建了强弱不同的两组Ambient光,照射方向不同的两组Directional光,分别为红色和黄色,以及一组橙色的Point光。
1.创建一个环境光:
AmbientLight ambient = new AmbientLight( ); // 光的类型为AmbientLight
ambient.setEnable (ambientOnOff); // 根据ambientOnOff的值设置为true或
false
ambient.setColor (new Color3f (0.3f, 0.3f, 0.3f)); // 光的颜色
ambient.setCapability (AmbientLight.ALLOW_STATE_WRITE);
ambient.setInfluencingBounds (worldBounds);
Scene1.addChild (ambient); // 加到场景中
设置包围球:
BoundingSphere worldBounds = new BoundingSphere (
new Point3d ( ), 1000.0);
myLight.setInfluencingBounds (myBounds);
运行结果如下:
图10无灯光效果的场景
图11加入AmbientLight效果的场景
2.创建PointLight
PointLight orangePoint = new PointLight ( );
orangePoint.setEnable (orangePointOnOff);
orangePoint.setColor (new Color3f (1.0f, 0.5f, 0.0f)); / / 同样为光的颜色,橙色
orangePoint.setPosition (new Point3f (0.0f, 0.5f, 0.0f)); / / 设置光的位置
orangePoint.setCapability (AmbientLight.ALLOW_STATE_WRITE);
orangePoint.setInfluencingBounds (worldBounds);
Scene1.addChild (orangePoint);
运行结果如下:
图12加入PointLight效果的场景
3.创建一个DirectionalLight:
DirectionalLight redDirectional = new DirectionalLight ( );
redDirectional.setEnable (redDirectionalOnOff);
redDirectional.setColor (new Color3f (1.0f, 0.0f, 0.0f));
redDirectional.setDirection (new Vector3f (1.0f, -0.5f, -0.5f));
redDirectional.setCapability (AmbientLight.ALLOW_STATE_WRITE);
redDirectional.setInfluencingBounds (worldBounds);
Scene1.addChild (redDirectional);
执行结果如下:
图13加入DirectionalLight效果的场景
4.4.2 创建背景图片
这里的背景图片实际上就是一张640×480的jpg图片,所以就是么把2D图片读到场景中。为了同时实现交互式更换背景图片,这里也加入了菜单。
读入2D图片要用到ImageComponent2D和TextureLoader两个类。其中ImageComponent2D用于定义一个二维组件,TextureLoader则是读取ImageComponent2D定义的二维组件。
// 预载背景图片
// 使用TextureLoader读图片
// 将要读取的图片装入ImageComponent2D[ ]中
if ( debug ) System.err.println( " background images..." );
TextureLoader texLoader = null;
String value = null;
imageComponents = new ImageComponent2D[images.length];
for ( int i = 0; i < images.length; i++ )
{
value = (String)images[i].value;
if ( value == null )
{
imageComponents[i] = null;
continue;
}
texLoader = new TextureLoader( value, this );
imageComponents[i] = texLoader.getImage( );
}
图14纹理背景--白云
4.4.3 指数雾
用ExponentialFog可以产生雾的效果
雾的密度通过指数控制厚度:
effect = e(-density * distance)
color = effect * shapeColor + (1-effect) * fogColor
下面是场景中对雾的初始化
// 设置雾的颜色、密度和范围
fog = new ExponentialFog();
fog.setColor(color);
fog.setDensity(density);
fog.setCapability(Fog.ALLOW_COLOR_WRITE);
fog.setCapability(ExponentialFog.ALLOW_DENSITY_WRITE);
fog.setInfluencingBounds(worldBounds);
Scene1.addChild (fog);
图15各种不同的雾效果
4.4.4 背景音乐
在场景中加入背景音乐可以是气氛更加活跃。
首先要把音乐加入到背景中,
if ( debug ) System.err.println( " sounds..." );
String path = getCurrentDirectory( );
MediaContainer backgroundMedia = new MediaContainer(
path + "canon.wav" );
backgroundMedia.setCacheEnable( true );
然后对背景音乐初始化,
backgroundSound = new BackgroundSound( );
backgroundSound.setEnable( true );
backgroundSound.setLoop( Sound.INFINITE_LOOPS ); // 设置音乐循环播放
backgroundSound.setSoundData( backgroundMedia );
backgroundSound.setInitialGain( 1.0f ); // 设置音量
backgroundSound.setSchedulingBounds( worldBounds );
backgroundSound.setCapability( Sound.ALLOW_ENABLE_WRITE );
backgroundSound.setCapability( Sound.ALLOW_INITIAL_GAIN_WRITE );
backgroundSound.setCapability( Sound.ALLOW_PAUSE_WRITE);
backgroundSound.setCapability( Sound.ALLOW_PAUSE_READ);
Scene1.addChild( backgroundSound );
§4.5 在网页上显示3D图形
Java3D一个最大的特性是可以使用Applet作为显示容器,
<HTML>
<BODY>
<APPLET code= ExExponentialFog.class width=400 height=400>
</APPLET>
</BODY>
</HTML>
第五章 实践和展望
§5.1 Web3D技术发展前景
虽然,Web3D技术将有好的发展前景,但仍然不可乐观,它面临下述问题:
网络带宽仍然是Web3D主要瓶颈:当前处理器的速度与网络的带宽只能初步满足Web3D图形联机操作的要求,随着 Cable modems 和 DSL 连接的应用,网络带宽将有更大的改进,当一个10MB左右的Web3D模型文件只需要几秒钟下载时,Web3D图形的质量将有很大的改善,而现在的带宽还不能满足要求。Flash作为2D动画在互联网上的成功的关键是只有唯一的技术和标准。现在的Web3D图形是有几十种可供选择的技术和解决方案,多种文件格式和渲染引擎的存在是Web3D图形在互联网上应用的最大障碍,而这种局面在今后若干年还将存在。从现在的发展态势来看,有几种技术可能在未来有一定的优势:
X3D:由Web 3D Consortium制定,得到大学,政府机构及一些Web3D图形公司的支持,由于它是VRML97下一代新的国际标准,有比较广泛的社会基础。
Pulse3D:在游戏娱乐领域内领先,使用它的技术的游戏网站有100多个,它得到Discreet 和Entertaindom公司的资金支持,现在它正在把游戏领域的技术优势应用到e-commerce。它的插件支持QuickTime 5 and RealPlayer。
Viewpoint:前身是MetaCreations(3D图形应用软件开发商),它卖掉了所有的其他软件产品,改名为Viewpoint,专们从事Web3D图形技术。其渲染引擎的模块化结构极易扩充,并且能与QTVR-, iPix-, and XML-等标准集成。它的目标是e-commerce。它的技术的最大特色是与XML集成。
Cult3D:开发了e-commerce的全套解决方案,已经有450 e-commerce网站使用了 Cult3D技术,近10000个商业模型,它也在向娱乐领域扩充,提供全面解决方案,提供最稳定可靠的渲染引擎。
Shockwave3D: 这是Macromedia公司Flash插件,有着极为广大的用户群,更引人注目的是Intel把它的Web3D 图形集成到Shockwave。IntelWeb3D图形极具特色:动态调节3D内容的分辨率,曲面光滑技术,照片级逼真材质及各种特色效应。
在今年的SIGGRAPH 2002世界计算机图形会议上, Intel宣布建立 Web3D/CAD工作组, 其主要目标是:建立一个统一的,开放的文件格式,用于在Web上显示实时的3D图形。与此同时Web3D Consortium在SIGGRAPH 2002会议上了发布X3D最终工作草案。X3D是一个成熟的标准,是VRML的下一代标准,但是Intel完全没有提到它,如果Intel重新制定另外一个新标准,X3D的将面临尴尬,就Intel公司的实力和威望,X3D很难成为真正的国际标准。Intel公司很可能将左右新标准的制定与推行。
预测未来谁是最后的胜利者是困难的,也许很长一段时间内将是多种技术同时共存而又相互竞争。而Intel和微软都具有左右Web3D发展前景的实力。
§5.2 论文总结
感谢老师、师兄的热心指导和帮助,使我能够顺利地完成毕业设计。
本次的毕业设计就是不断学习的过程。本人初次基础Java3D这种全新的3D开发工具,在编程方面,不断的接触、认识、克服了一些以前从未遇到的问题。在毕业设计的开始阶段了解了Java语言及JBuilderX等编译器,因此花费较多时间。
在这次毕业设计中对Java3D有了较好的理解并在一个场景中实现了其中绝大多的功能。但也有很多不足之处只得更进一步学习,比如Vrml97文件的导入,利用Billboard类实现向场景中加入树等。
在一个瞬息万变的变革时代,在一个新技术层出无穷的年代,每一个学科都在新的坐标系中寻找自己新的定位。如何处理传统与现代、科学与技术、理论与实践等诸多矛盾,寻求一个学科发展正确的概念模式,对传统学科尤其显得重要而紧迫。本文对现时由于技术的进步对Web3D所产生的影响进行了远不算成熟的思考。不论是从科学、技术还是社会的角度,Web3D处在一个蓬勃发展的阶段,值得我们不倦地追求并为之努力奋斗。
参考文献
1) 作者,刊物名称,年,卷(期),页。
(宋体,英文均为Times New Roman,小四)
2)作者,“书名”,出版社(出版地),出版年。
5、资源下载
本项目源码及完整论文如下,有需要的朋友可以点击进行下载。如果链接失效可点击下方卡片扫码自助下载。
序号 | 毕业设计全套资源(点击下载) |
---|---|
本项目源码 | 基于java+Java3D的网络三维技术设计与实现(源码+文档)_java_Java3D_网络三维技术.zip |