随笔 - 5  文章 - 3  trackbacks - 0
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(3)

随笔档案

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

转帖链接:http://bbs.zju.edu.cn/cgi-bin/bbs0an?path=/groups/GROUP_1/Graphics_Image/CAD_ImageProcess/dev/DevLib/java3d 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习资料(一)(转载) 发信站: 飘渺水云间 (Wed Mar 31 15:58:48 1999), 转信 PIII、K6-III出来了,在3D编程语言中,JAVA3D也应占有重要的位置。 为此,本人拿出半年多学习及应用JAVA3D的经验,借国内主要BBS站点,推出JAVA3D编程 指导,并给出大量的例子。 一。如何运行JAVA3D? 只要在WIN95/98上安装了JDK1.2(JAVA2),再安装JAVA3D运行环境,就可以运行 JAVA3D,注意,别忘了在autoexec.bat中插入一行: SET PATH=C:\JDK1.2\BIN 目前我们可以从SUN公司的站点获得最新的JAVA3D,本人拥有的为: java3d1_1-win32-opengl-jdk.exe,大小为3197K。 JAVA3D运行环境中附有许多例子,可用来学习JAVA3D,同时网络上还有大量的 JAVA3D学习资料,可以用来学习JAVA3D编程。 二。网络上的JAVA3D学习资料 1.http://www.sun.com/desktop/java3d/collateral/ 这里有SUN公司为我们提供的学习资料。 2.http://www.sdsc.edu/~nadeau/Courses/VR99/java3d.zip 这是一个非常好的JAVA3D学习资料。(12,058K),里面有许多例子。 大家可以从http://www.sdsc.edu/~nadeau/中得到VRML和JAVA3D的许多资料。 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(二)(转载) 发信站: 飘渺水云间 (Wed Mar 31 16:01:09 1999), 转信 一。JAVA3D的作用: JAVA3D可用在三维动画、三维游戏、机械CAD等领域。 1.可以用来编写三维形体,但和VRML不同,JAVA3D没有基本形体,不过我们可以利用 JAVA3D所带的UTILITY生成一些基本形体如立方体、球、圆锥等,我们也可以直接调用 一些软件如ALIAS、LIGHTWARE、3DS MAX生成的形体,也可以直接调用VRML2.0生成的 形体。 2.可以和VRML一样,使形体带有颜色、贴图。 3.可以产生形体的运动、变化,动态地改变观测点的位置及视角。 4.可以具有交互作用,如点击形体时会使程序发出一个信号从而产生一定的变化。 5.可以充分利用JAVA语言的强大功能,编写出复杂的三维应用程序。 6.JAVA3D具有VRML所没有的形体碰撞检查功能(这也是本人目前中意JAVA3D的原因)。 (作为一个高级的三维图形编程API,JAVA3D给我们带来了极大的方便,它的作用 可以说,几乎包含了VRML2.0所提供的所有功能。) 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(三)(转载) 发信站: 飘渺水云间 (Wed Mar 31 16:02:21 1999), 转信 二。OPENGL、VRML、DIRECT3D、JAVA3D的比较 由于OPENGL的跨平台特性,许多人利用OPENGL编写三维应用程序,不过对于一个非 计算专业的人员来说,利用OPENGL编写出复杂的三维应用程序是比较困难的,且不说C (C++)语言的掌握需要花费大量时间精力,当我们需要处理复杂问题的时候,我们不得 不自己完成大量非常繁琐的工作。当然,对于编程高手来说,OPENGL是他们发挥才能的 非常好的工具。 VRML2.0(VRML97)自1997年12月正式成为国际标准之后,在网络上得到了广泛的应 用,编写VRML程序非常方法(VRML语言可以说比BASIC、JAVASCRIPT等语言还要简 单),同时可以编写三维动画片、三维游戏、用于计算机辅助教学,因而其应用前景非 常广阔尤其适合在中国推广应用。不过由于VRML语言功能目前还不是很强(如目前没有 形体之间的碰撞检查功能),与JAVA语言等其它高级语言的连接较难掌握,因而失去了 一些计算机高手的宠爱。但我们认为,我们可以让大学里的文理科学生利用VRML编写多媒 体应用程序,让学生很快地对编写程序感兴趣,从而使国内的计算机水平得到提高。 DIRECT3D是Microsoft公司推出的三维图形编程API,它主要应用于三维游戏的编程, 目前相关的学习资料难于获得,由于它一般需要VC等编程工具进行编程,需要编程人员 具有较高的C++等高级语言的编程功底,因而难以普及。 JAVA3D是建立在JAVA2(JAVA1.2)基础之上的,JAVA语言的简单性使JAVA3D的推广 有了可能。OPENGL和JAVA3D之间的比较可以看成汇编语言与C语言之间的比较,一个是低 级的,一个是高级的(也许这样比较不太恰当)。JAVA3D给我们编写三维应用程序提供 了一个非常完善的API,它可以帮助我们: 生成简单或复杂的形体(也可以直接调用现有的三维形体) 使形体具有颜色、透明效果、贴图。 可以在三维环境中生成灯光、移动灯光。 可以具有行为(Behavior)的处理判断能力(键盘、鼠标、定时等) 可以生成雾、背景、声音等。 可以使形体变形、移动、生成三维动画。 可以编写非常复杂的应用程序,用于各种领域如VR。 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(四)(转载) 发信站: 飘渺水云间 (Thu Apr 1 21:45:23 1999), 转信 在编写JAVA3D程序之前,我们需要了解一些概念,完成一些准备工作。 一. JAVA3D的数据结构 JAVA3D实际上是JAVA语言在三维图形领域的扩展,JAVA3D的编程和JAVA一样, 是面向对象的编程。 JAVA3D的数据结构采用的是Scene Graphs Structure(场景图),这一灵活 的树状结构与显示列表多少有些相似之处,但运用起来更耐用(More Robust)。 JAVA3D的场景图是DAG(Directed-acyclic Graph),即具有方向性的不对称图形。 场景图中有许多线和线的交汇点,交汇点称为节点(Node),不管什么节点, 它都是JAVA3D类的实例(Instance of Class),线(Arc)表示实例之间的关系。 在JAVA3D的场景图中,最底层(根部)的节点是Virtual Universe,每一个 场景图只能有一个Virtual Universe。 在Virtual Universe上面,就是Locale节点,每个程序可以有一个或多个 Locale,但同时只能有一个Locale处于显示状态,就好象一个三维世界非常大, 有很多个景点,但我们同时只能在一个景点进行观察。当然我们可以从一个景点 跳到另一个景点,不过绝大多数程序只有一个Locale。 每一个Locale上面拥有一个到多个BranchGroup节点。我们知道,要想建立 我们的三维应用环境,我们必须建立所需要的形体(Shape),给出形体的外观 (Appearance)及几何信息(Geometry),再把它们摆放在合适的位置, 这些形体及其摆放位置都建立在BranchGroup节点之上,摆放位置通过另一个节点 TransformGroup来设定。另外,我们在安放好三维形体之后,还需要设定具体的 观察位置,我们暂时用View Platform代替,它也是建立在TransformGroup节点 之上的。 下面我们用一个示意图来说明上面我们介绍的JAVA3D的场景图概念。 Virtual Universe | |----------------------------------| | | Locale Locale | | ----------------+----------------- | | | | | | | | BG BG BG BG (BG--BranchGroup) | | | | | | | | (S---Shape) S TG TG TG (TG--TransformGroup) ----+--- | | | | | | | | A G S S View Platform | | | | (A---Appearance) ----+---- ----+---- (G---Geometry) | | | | | | | | A G A G 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(五)(转载) 发信站: 飘渺水云间 (Sun Apr 4 14:15:43 1999), 转信 一. 如何安装JAVA3D 下载JDK1.2及JAVA3D (目前最新的为1.1.1版本)。 在WIN95/98上安装,先安装JDK1.2,再安装JAVA3D, 将JDK安装到JDK1.2目录下。 建立一个自己的目录,在自己的目录中编写并运行程序。 注意,安装JDK1.2时别忘了在autoexec.bat中插入一行: SET PATH=C:\JDK1.2\BIN JDK1.2的大小为20,041KB(jdk12_win32.exe)。 JAVA3D的大小为3,197KB(java3d1_1-win32-opengl-jdk.exe) 安装时可以选择所有缺省参数以减收麻烦。 二. 如何编写JAVA3D源程序 用自己喜爱的文本编辑工具编辑源程序,和其它JAVA程序 一样,程序后缀为JAVA。 三. 如何运行JAVA3D源程序 用JAVAC编译源程序,生成class文件。根据文件的类型, 选择用JAVA或APPLETVIEWER运行程序。 JAVA3D程序可以为APPLICATION程序,也可以为APPLET程序, 因而JAVA3D程序也可以摆放在网页上,当然这时候我们必须在浏 览器上做一些设置工作(以后再介绍)。 四. 一个最简单的JAVA3D源程序。 下面我们介绍一个最简单的JAVA3D源程序,进而介绍JAVA3D 为我们提供的各种功能。 程序是一个JAVA的APPLET类型的程序,它的作用是显示一个 红色的圆锥,仅此而已。 名为SimpleCone.java。 //SimpleCone.java import java.applet.Applet; import java.awt.BorderLayout; //import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class SimpleCone extends Applet{ public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objTrans = new TransformGroup(); objRoot.addChild(objTrans); Appearance app = new Appearance(); Material material = new Material(); material.setEmissiveColor(new Color3f(1.0f,0.0f,0.0f)); app.setMaterial(material); Cone cone=new Cone(.5f,1.0f,1,app); objTrans.addChild(cone); objRoot.compile(); return objRoot; } public SimpleCone() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } // public static void main(String[] args) { // new MainFrame(new SimpleCone(), 256, 256); // } } //end of Simple.java 在运行applet程序时,我们需要编写一个HTML文件: 先用javac将JAVA3D源程序编译成class文件,再用 appletviewer运行HTML文件。 虽然程序是applet程序,但我们也可以将其变成 application程序,这时我们只需将程序头尾的四个注释行 的注释符号去掉即可,这时我们可以用java来运行它: java SimpleCone 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(六)(转载) 发信站: 飘渺水云间 (Tue Apr 13 19:08:04 1999), 转信 JAVA3D程序也是JAVA程序,因而我们首先必须对JAVA有所了解,并能 编写简单的JAVA程序,了解JAVA编程的基本概念,关于JAVA语言的相关知 识,我们在这里就不一一介绍了,国内这方面的书籍非常丰富。 一. SimpleCone 程序分析 1. SimpleCone.java及其对应的VRML程序 上一节中,我们给出了SimpleCone这个非常简单的JAVA3D程序,下面 我们来解读这个程序,进而介绍JAVA3D所提供的API的内容。 第三节中,我们对JAVA3D的场景图结构作了一个简单的介绍,从场景图 我们可以看出,JAVA3D的场景图和VRML的场景图非常相似,因而我们可以编 写类似的VRML程序出来,与JAVA3D程序进行比较。 SimpleCone程序只是显示一个红色的圆锥,相类似的VRML程序为: //SimpleCone.wrl #VRML V2.0 utf8 Shape{ geometry Cone{ bottomRadius .5 height 1.0} appearance Appearance{material Material{emissiveColor 1 0 0}} } //end of SimpleCone.wrl 可以看到,与JAVA3D程序相比,VRML程序要简单的多,并且可以直接在 IE和Netscape浏览器上运行,而JAVA3D则要复杂的多。不过几乎所有的VRML 程序都可以用JAVA3D编写出来,而稍微复杂一点的JAVA3D的程序则基本上无 法用VRML语言完成。因为VRML几乎可以看成是一个三维计算机图形格式,而 JAVA3D则是一个高级计算机语言。 在上面的VRML程序中,只定义了一个三维形体及其材质,背景、灯光、 位置等均为缺省值。 同样地,SimpleCone.java程序中,我们也只定义了三维形体及其材质, 没有背景、灯光等,处在缺省的位置上(坐标系原点)。 JAVA3D和VRML一样,采用的是一个符合右手螺旋法则的三维坐标系。正 X轴向右,正Y轴向上,正Z轴朝外(从计算机屏幕指向我们)。 2. JAVA3D(API)中的类 JAVA3D是SUN公司为我们提供的一个API,里面包含了几乎所有我们所需 要的编写JAVA三维多媒体应用程序的基本的类及方法。我们在编程时,只 需调用所需要的类及方法,就可以快速地编写出复杂的三维多媒体应用程 序。可以说,我们所做的工作只是学会应用JAVA3D的各种类(Objects)及方 法。 JAVA3D为我们提供了100多个存放于javax.media.j3d程序包中的类,它 们被称为JAVA3D的核心类,除了核心包中的类以外,JAVA3D还提供了一些其 它程序包,其中一个重要的包是com.sun.j3d.utils包(Utility)。 JAVA3D所提供的Utility并不是JAVA3D编译环境的核心组成部分,我们可以 不用它,不过使用它们会大大提高我们的程序编写效率。JAVA3D为我们提供的 Utility会不断增加,例如有可能增加处理NURBS曲线的Utility。目前,JAVA3D 为我们提供了四组Utility,它们是: 用于调用其它三维图形格式如ALIAS图形格式的content loader 用于构造场景图的scene graph construction aids 用于建立一些基本体如圆锥、球的geometry classes 一些其它方便我们编程的convenience utilities 除了JAVA3D的核心包及Utility包之外,每个JAVA3D程序还必需用到下面 两个包:java.awt和javax.vecmath。java.awt包用来定义一个显示用的窗口, 而javax.vecmath包则是用来处理调用程序所需要的定义矢量计算所用的类, 处理定义三维形体及其位置时,我们需要用到点、矢量、矩阵及其它一些数学 对象,它也是JAVA3D所提供的一个包,目前它在JAVA3D的编译环境中,今后则 可能会成为JAVA1.2的核心组成部分。 根据其作用,JAVA3D所提供的类主要有两种类型:Node、NodeComponent Node类,它含有Group及Leaf两个子类: Group类 (用于将形体等按一定的组合方式组合在一起), 类似于VRML的组节点。 Leaf 类 (如Light、Sound、Background、shape3d、 Appearance、Texture及其属性等,还有 ViewPlatform、Sensor、Behavior、Morph、 Link等),类似与VRML的相应节点,是JAVA3D 场景图的重要组成部分。 NodeComponent类,用于表示Node的属性,它并不是JAVA3D场景图 的组成部分,而是被JAVA3D场景图所引用,如某 一个颜色可以被多个形体所引用。 3. SimpleCone.java程序import语句部分的介绍 根据JAVA3D所提供的类,按照面向对象的编程方式,我们可以编写出三维 环境中所需要的各个对象。编写JAVA3D程序的关键是学会应用JAVA3D所提供的 各个类,生成自己所需要的对象。 下面我们来看一下SimpleCone.java里的每一个import语句。 我们知道,java程序中。凡是利用到的外部的类均用import语句调用,我 们首先介绍一下程序中的import语句。 第一个import语句表示本程序是Applet程序。 第二个import语句表示窗口环境采用BorderLayout管理方式。 第三个import语句语句在去掉//后就可以使程序既为applet 也为application,为此,使用了JAVA3D所附带的一个Utility,这是一个名 叫Jef Poskanzer的人所编写的类。 第四个import语句表示调用生成Cone的一个Utility,这是因为,JAVA3D 和VRML不同,VRML有几个基本几何体的节点语句,但JAVA3D的核心部分一个 基本体也没有定义,但JAVA3D所附带的Utility为我们提供了一些事先编好的 基本体,我们可以调用这些基本体。 第五个import语句表示我们调用一些设置基本的观测位置所用的类,如 SimpleUniverse、Viewer、ViewingPlatform等,利用它们,我们可以很方便 地构造JAVA3D场景图底部的VirtualUniverse、Locale及其上的View分支,进 而使精力主要用在建模及复杂问题的处理上面,当然它们也都是JAVA3D所附带 的Utility。 第六个import语句表示调用程序所需要的JAVA3D核心类,因而所有JAVA3D 程序都必须带有这一语句,只有这样才能在JDK1.2环境中编译执行JAVA3D程序。 第七个import语句表示调用程序所需要的定义矢量计算所用的类。 3. SimpleCone.java程序的组成 SimpleCone.java程序主要由三个部分组成: createSceneGraph方法的定义 SimpleCone的构造函数 用于生成application应用程序的main函数 4. createSceneGraph方法的定义 我们首先来看一下createSceneGraph方法的定义部分。通过第三讲的 JAVA3D场景图的简单示意图,我们知道,为了编写出一个JAVA3D应用程序, 我们必须编写出一个拥有三维形体的内容分支,即一个分支组,一个 BranchGroup。我们将我们所需要的形体及其材质定义在里面,由于一般 形体会摆放在三维空间的某一个位置,因而我们还需要先在BranchGroup 分支之上建立一个可用于几何变换用的TransformGroup,即几何变换分支 组,再将形体及其材质作为TransformGroup的一个分支给出,当然程序中 如果将形体摆放在坐标原点,也可以不给出一个TransformGroup,如下面 的SimpleCone1程序运行起来和SimpleCone结果完全一样,它没有一个 TransformGroup对象: //SimpleCone1.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class SimpleCone1 extends Applet{ public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Appearance app = new Appearance(); Material material = new Material(); material.setEmissiveColor(new Color3f(1.0f,0.0f,0.0f)); app.setMaterial(material); Cone cone=new Cone(.5f,1.0f,1,app); objRoot.addChild(cone); objRoot.compile(); return objRoot; } public SimpleCone1() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new SimpleCone1(), 256, 256); } } //end of SimpleCone1.java JAVA3D有三种运行方式,一种是Immediate Mode,一种是 Retained Mode,一种是Compiled-Retained Mode。 SimpleCone程序中的 objRoot.compile(); 表示程序为Compiled-Retained Mode,在这种模式下,JAVA3D对程序 进行了优化,程序的运行运行速度最快。不过在一些场合,如形体在 程序运行过程中才生成,则不能Compile形体,这说明优化是有条件的。 注意,JAVA3D程序没有“开始渲染”这一步骤,当一个View被有 效地放入一个Virtual Universe,JAVA3D运行环境就开始不停地渲染 JAVA3D场景图中的三维形体,从而使屏幕上显示出三维图形。 5. SimpleCone的构造函数 SimpleCone的构造函数的作用为 首先设置一个BorderLayout。 生成一个名为c的Canvas--Canvas3D继承了JDK1.2中的Canvas类, 从而构造了一个图形环境。 将c放入BorderLayout的中心位置。 生成一个场景图分支scene,里面定义了形体及其材质(红色)。 借用JAVA3D的一个Utility,生成了场景图的Virtual Universe及 Locale、Viewer,和VRML程序有些不同,在缺省情况下, JAVA3D的观察点为位于(0 , 0 , 2.41),而VRML的观察点 位于(0 , 0 , 10),因而形体在VRML中看起来比较小, 而在JAVA3D中看起来比较大。我们利用这个Utility生成的 这个u使我们不必考虑生成场景图中的观测分支,不过它也 有缺点,即我们不能在Virtual Universe中拥有多个View, 因而也就不能从一个View跳到另一个View。 6. 用于生成application应用程序的main方法 为了使我们的程序既可以为applet程序,又可以为application 程序,我们可以通过编写一个main方法,利用import语句提供的 MainFrame类,生成一个MainFrame对象,从而使程序变成为 application程序。MainFrame是JAVA3D为我们提供的一个非常有用 的Utility。 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(七)(转载) 发信站: 飘渺水云间 (Tue Apr 13 19:10:48 1999), 转信 介绍了一个简单的JAVA3D程序后,我们开始学习JAVA3D的编程 技术。首席我们介绍三维基本形体的生成。 和VRML不同,JAVA3D没有基本形体类,因而在程序中无法直接 生成大量应用的基本形体,如BOX、CONE、SPHERE等。我们可以通过 复杂的编程生成这些基本形体,也可以直接调用JAVA3D为我们提供的 geometry classes,利用它生成程序所需要的BOX、COLORCUBE、CONE、 SPHERE、CYLINDER。下面介绍这些基本体的生成方法。 一. BOX UTILITY里BOX的构造函数有: 1. Box() 生成一个各边尺寸均为2的BOX,要说明的是,BOX、COLORCUBE、 SPHERE的坐标原点均在其中心点,CONE、CYLINDER的则在其轴 线的中点上。 2. Box(float xdim, float ydim, Appearance ap) 生成一个给定尺寸、给定外观属性的BOX 例:Box(.5f, .6f, .4f, myApp) 3. Box(float xdim, float ydim, float zdim, int primflags, Appearance ap) 生成一个有特定说明的BOX,例如: Box(.4f,.6f,.3f,Primitive.ENABLE_APPEARANCE_MODIFY, ap) 表示程序在运行时可以改变其外观属性。 我们可以在程序中使用的primflags种类可以在JAVA3D所附带提 供的UTILITY里的Primitive.java中获得。 二. COLORCUBE UTILITY里COLORCUBE的构造函数有: 1. ColorCube() 生成一个边长均为2的COLORCUBE 2. ColorCube(double scale) 将边长均为2的COLORCUBE按比例放大缩小。 三. CONE UTILITY里CONE的构造函数有: 1. public Cone() 生成一个底半径为1,高为2的CONE。 2. Cone (float radius, float height) 3. Cone (float radius, float height, int primflags, Appearance ap) 4. Cone(float radius, float height, int primflags, int xdivision, int ydivision, Appearance ap) 这里,xdivision、ydivision可用来表示圆锥的显示是高精度 的显示,或是底精度的显示,缺省时的中等精度时 xdivision = 15; ydivision = 1; 我们可利用这两个参数来 改变显示的效果,使显示圆锥的三角片更多或更少些。 四. SPHERE UTILITY里SPHERE的构造函数有: 1. Sphere() 生成一个半径为1的SPHERE。 2. Sphere (float radius) 3. Sphere (float radius, Appearance ap) 4. Sphere(float radius, int primflags, Appearance ap) 5. Sphere(float radius, int primflags, int divisions) 6. Sphere(float radius, int primflags, int divisions, Appearance ap) 这里,divisions的作用和圆锥的xdivision、ydivision相似。 五. CYLINDER UTILITY里CYLINDER的构造函数有: 1. Cylinder() 生成一个底半径为1,高为2的CYLINDER。 2. Cylinder (float radius, float height) 3. Cylinder (float radius, float height, Appearance ap) 4. Cylinder (float radius, float height, int primflags, Appearance ap) 5. Cylinder(float radius, float height, int primflags, int xdivision, int ydivision, Appearance ap) 有了这些基本体的构造函数,我们就可以按SimpleCone.java 程序同样的方法,编写出生成BOX、COLORCUBE、CONE、SPHERE、 CYLINDER的JAVA3D程序来。 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(八)(转载) 发信站: 飘渺水云间 (Tue Apr 13 19:40:39 1999), 转信 JAVA3D学习系列之7---点的生成 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) ( 在前面(第6部分)我们介绍了如何编写JAVA3D三维基本形体的) ( 程序,需要指出的是,我们将前面的SimpleCone.java程序修改为) ( 其它形体时,我们需要同时修改import语句的类型,或者干脆将 ) ( 相应的那个import语句修改成: ) ( import com.sun.j3d.utils.geometry.*; )   JAVA3D编程过程中,我们经常要编写一些点、线、面,JAVA3D所提供 的API中有许多这方面的对象,下面我们开始一一介绍它们的使用方法。 一. 点的生成 我们先用VRML编写一个带有不同颜色的六个点的程序。 //Point.wrl ----观测点在 (0 0 10) #VRML V2.0 utf8 Shape { geometry PointSet { coord Coordinate { point [.8 .8 .0, -.8, .8 0, .5 0 0, -.5 0 0, -.8 -.8 0, .8 -.8 0]} color Color{ color [ .0 .5 1., .5 .0 1, 0 .8 .2, 1 0 .3, 0 1 .3, .3 .8 0 ]} }} #end of Point.wrl 由程序可知,VRML程序中的点非常小,且无法变大。 下面我们改用JAVA3D编写同样的程序,不过由于观测 点不同,观测效果有差异,VRML程序中的点比较集中,JAVA3D 程序中的点比较分散,程序如下: //Point1.java -----观测点在( 0 0 2.41 ) import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Point1 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,0.2f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; Shape3D shape = new Shape3D(); PointArray point = new PointArray(6, PointArray.COORDINATES |PointArray.COLOR_3); point.setCoordinates(0,vert); point.setColors(0,color); shape.setGeometry(point); objRoot.addChild(shape); objRoot.compile(); return objRoot; } public Point1() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Point1(), 400,400); } } //end of Point1.java 我们来分析一下上面的Point1.java。 我们知道,编写JAVA3D程序实际上是编写一个特定的场景图, 给出了场景图中带有形体及其属性的一个分支(BranchGrou)和 表示观察位置等数据的另一个分支(View Platform)。一般来说, 表示观测位置的分支可以用JAVA3D的UTILITY来完成,因而我们可 以看到,在Point1.java中,构造函数Point1和前面介绍的 SimpleCone.java的构造函数SimpleCone内容完全一样。两个程序 的不同之处在于形体构造及处理分支,即createSceneGraph方法的 定义。 我们来看一下Point1.java的createScendGraph方法的定义。 在这个方法里,程序先定义了一个分支objRoot,然后用数组 的形式定义了六个顶点坐标vert和六种颜色color,再用PointArray 定义了一组点point,并将顶点坐标及颜色赋值给point,由于JAVA3D 中的PointArray点是Shape3D的子类,它不能直接放入一个BranchGroup, 因而我们还要先定义一个Shape3D对象shape,再将point赋予shape, 这样point就可以放入BranchGroup类型的对象objRoot中了。 二. PointArray、IndexedPointArray介绍 JAVA3D提供的API中,可用于生成Point的对象有: PointArray IndexedPointArray 1. PointArray PointArray的构造函数为: PointArray( int vertexCount, int vertexFormat ); 这里,vertexCount表示应生成的点的数目, vertexFormat表示所需要的顶点的格式。 点、线、面几何体所需要的顶点的格式有: COORDINATES 顶点坐标数组 NORMALS 顶点法向数组 COLOR_3 不带alpha值的颜色数组 COLOR_4 带alpha值的颜色数组 TEXTURE_COORDINATE_2 二维纹理坐标数组 TEXTURE_COORDINATE_3 三维纹理坐标数组 Point1.java程序用到了COORDINATES和COLOR_3。 2. IndexedPointArray IndexedPointArray的构造函数为: IndexedPointArray( int vertexCount, int vertexFormat, int indexCount ); 利用本函数,我们可以从众多的点中,选择特定的点来显示。 这里,vertexCount表示顶点坐标数组所提供的点的总个数, indexCount表示最终应生成的点的个数。 三. 20像素大小的点的生成 JAVA3D可以生成任意大小的点,并且可以使点为方点或圆点。 下面的程序生成了一个20像素大小的程序。 //Point2.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Point2 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; Shape3D shape = new Shape3D(); PointArray point = new PointArray(6, PointArray.COORDINATES |PointArray.COLOR_3); point.setCoordinates(0,vert); point.setColors(0,color); PointAttributes pa = new PointAttributes(); pa.setPointSize(20.0f); pa.setPointAntialiasingEnable(true); //不加这一行,点的显示效果为正方形 //加了这一行,点的显示效果为圆形 Appearance ap = new Appearance(); ap.setPointAttributes(pa); shape.setGeometry(point); shape.setAppearance(ap); objRoot.addChild(shape); objRoot.compile(); return objRoot; } public Point2() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Point2(), 400,400); } } //end of Point2.java 四. IndexedPointArray编写的点 下面的程序中,我们用IndexedPointArray生成了四个点。 //Point3.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Point3 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; Shape3D shape = new Shape3D(); int[] index={ 0 , 2 , 3 , 4 }; int VertexCount=4; IndexedPointArray point = new IndexedPointArray(6, IndexedPointArray.COORDINATES| IndexedPointArray.COLOR_3, VertexCount); point.setCoordinates(0,vert); point.setColors(0,color); point.setCoordinateIndices(0,index); point.setColorIndices(0,index); PointAttributes pa = new PointAttributes(); pa.setPointSize(20.0f); pa.setPointAntialiasingEnable(true); Appearance ap = new Appearance(); ap.setPointAttributes(pa); shape.setGeometry(point); shape.setAppearance(ap); objRoot.addChild(shape); objRoot.compile(); return objRoot; } public Point3() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Point3(), 400,400); } } //end of Point3.java 通过上面的程序,我们来看一下IndexedPointArray 的应用方法。 在定义一个point实例后,我们要给出顶点坐标数组及 对应各个顶点的颜色数组,按下标给出我们的顶点及颜色 的具体选择方案。从而得以从众多的点中,选择特定的点来 显示并给定颜色。通过setPointSize、setPointAntialiasingEnable 的设定,使显示的点拥有一定的大小及良好的显示效果。 ---1--- ---0--- ---3--- ---2--- ---4--- ---5---   程序Point3.java中,我们只选用了六个点中的0、2、3、4 四个点。 五. 主程序比较简洁的程序Point4.java 前面几个程序,所有的内容均放置在一个程序中,这对于 阅读程序来说,增添了一些困难。一般来说,一个具体的例子通常 由几个JAVA3D程序来完成,一般是将形体生成部分划为单独的一个 子程序,下面我们将上面的Point3.java分成两个程序:子程序 myShape.java用来生成点,主程序Point4.java完成其它设置任务 并调用myShape.java,我们设定两个程序均位于同一个子目录下。 //pointShape.java import javax.media.j3d.*; public class pointShape extends Shape3D { private float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; public pointShape() { int[] index={ 0 , 2 , 3 , 4 }; int VertexCount=4; IndexedPointArray point = new IndexedPointArray(6, IndexedPointArray.COORDINATES| IndexedPointArray.COLOR_3, VertexCount); point.setCoordinates(0,vert); point.setColors(0,color); point.setCoordinateIndices(0,index); point.setColorIndices(0,index); PointAttributes pa = new PointAttributes(); pa.setPointSize(20.0f); pa.setPointAntialiasingEnable(true); Appearance ap = new Appearance(); ap.setPointAttributes(pa); this.setGeometry(point); this.setAppearance(ap); } } //end of pointShape.java -------------------------------------------- //Point4.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Point4 extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Shape3D shape = new pointShape(); objRoot.addChild(shape); objRoot.compile(); return objRoot; } public Point4() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Point4(), 400,400); } } //end of Point4.java 六. 能够旋转的点 前面介绍的JAVA3D程序,显示的内容是静止的,且看不出立体的 效果,为此,我们使程序中的点绕着Y轴旋转,这样就可以看到具有 立体效果的点了,当然,其它形体也可以按同样的方法编程,程序调 用了上面给出的pointShape.java。 //Point5.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Point5 extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); objRoot.addChild(createObject()); objRoot.compile(); return objRoot; } private Group createObject() { Transform3D t = new Transform3D(); TransformGroup objTrans = new TransformGroup(t); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Shape3D shape = new pointShape(); objTrans.addChild(shape); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 50.0); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); return objTrans; } public Point5() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Point5(), 400,400); } } //end of Point5.java 在Point4.java的objRoot里,放置的是一个Shape3D对象, 而在Point5.java的objRoot里,放置的是一个Group对象。在 生成对象的createObject() 方法里,为了使得形体能够产生 旋转运动,我们首先建立了一个TransformGroup对象和一个 Transform3D对象,通过Capability参数的设置,表示在程序 运行时,objTrans能够进行几何变换,并将形体放入objTrans。 JAVA3D之所以能够使形体运动,是因为JAVA3D拥有类似于 VRML的时间传感器节点的Alpha对象,和类似于VRML的内插器节 点的各种Interpolator对象,它们在由BoundingSphere等对象 所设定的范围内在特定的时间内进行几何坐标变化,因而使形 体产生运动变化的效果。 本程序中,Alpha给出了一个4秒钟的循环变化时间周期; RotationInterpolator规定了形体每4秒钟绕着Y轴旋转 一周。BoundingSphere表示所有距离坐标原点50米之内的形体 均可以旋转运动,而在这范围之外的所有形体均不产生运动。 和Point5.java相类似的VRML程序如下,VRML里的点不能够 改变大小: //Point5.wrl #VRML V2.0 utf8 DEF T Transform{ children Shape { geometry PointSet { coord Coordinate { point [.8 .8 .0, -.8, .8 0, .5 0 0, -.5 0 0, -.8 -.8 0, .8 -.8 0]} color Color{ color [ .0 .5 1., .5 .0 1, 0 .8 .2, 1 0 .3, 0 1 .3, .3 .8 0 ]} }}} DEF TS TimeSensor{ cycleInterval 4 loop TRUE} DEF OI OrientationInterpolator{ key [0 .25 .5 .75 1] keyValue [0 1 0 1, 0 1 0 1.57, 0 1 0 3.14 0 1 0 4.71 0 1 0 6.28]} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation # end of Point5.wrl 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(九)(转载) 发信站: 飘渺水云间 (Tue Apr 13 19:47:27 1999), 转信 JAVA3D学习系列(8)-----直线的生成 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 我们可以利用JAVA3D的一些对象,生成各种直线。 可以生成直线的对象有: 1. LineArray LineArray(int vertexCount, int vertexFormat) 2. LineStripArray LineStripArray(int vertexCount ,int vertexFormat, int[] stripVertexCounts ) 3. IndexedLineArray IndexedLineArray(int vertexCount, int vertexFormat, int indexCount ) 4. IndexedLineStripArray IndexedLineStripArray( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 一. 利用LineArray生成直线 LineArray对象的定义如下: LineArray(int vertexCount, int vertexFormat) 这里: vertexCount表示顶点的个数(必须为偶数) vertexFormat表示顶点的格式(第七讲有介绍) 由下面的程序我们得知,Line1.java和前面介绍的 Point4.java几乎完全一样,lineShape1.java和 pointShape.java也相差不多。运行Line1.java我们获得 了三条直线,由此得知,LineArray的作用是生成多条直线, 顶点坐标数组的每一对数据构成一条直线。 在编写LineArray生成的直线时,要注意,顶点及颜色 的个数必须相等且为偶数,此数目必须赋值于vertexCount,也即 程序中的vertexCount必须为偶数且不能少于顶点的个数。 -------------------------- 第一条 ---------------- 第二条 -------------------------- 第三条 我们可以根据各种不同的情况,生成不同的直线,如 给定宽度的直线、虚线等。相应的的方法有: setLineWidth(float lineWidth) setLinePattern(int linePattern) setLineAntialiasingEnable(boolean state) 对于线型linePattern有以下数据可选: int PATTERN_SOLID int PATTERN_DASH int PATTERN_DOT int PATTERN_DASH_DOT 这些内容对所有种类的直线都有效。 前面我们利用PointArray生成了六个点,这里,我们 将前面的pointShape.java稍微变化一下,则同样的六个点生 成了三条直线,所用的两个程序为: //lineShape1.java import javax.media.j3d.*; public class lineShape1 extends Shape3D { private float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; public lineShape1() { LineArray line = new LineArray(6, LineArray.COORDINATES|LineArray.COLOR_3); line.setCoordinates(0,vert); line.setColors(0,color); LineAttributes la = new LineAttributes(); la.setLineWidth(5.0f); la.setLineAntialiasingEnable(true); Appearance ap = new Appearance(); ap.setLineAttributes(la); this.setGeometry(line); this.setAppearance(ap); } } //end of lineShape1.java ------------------------------------ //Line1.java ---using LineArray object import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Line1 extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Shape3D shape = new lineShape1(); objRoot.addChild(shape); objRoot.compile(); return objRoot; } public Line1() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Line1(), 400,400); } } //end of Line1.java 二. 利用LineStripArray生成直线 LineStripArray可用来生成多条折线段 LineStripArray对象的定义如下: LineStripArray(int vertexCount ,int vertexFormat, int[] stripVertexCounts ) 这里: vertexCount表示顶点的个数(必须为偶数) vertexFormat表示顶点的格式(第七讲有介绍) stripVertexCounts为一数组,数组里的每一个数值表示 每条折线段所拥有的顶点数目。 下面我们利用lineShape1.java同样的顶点坐标数组及 颜色数组,用LineStripArray对象生成直线。程序也是两个: lineShape2.java、Line2.java,并使生成的直线绕着Y轴旋转, 直线线型为虚线,线宽为30个像素。 //lineShape2.java import javax.media.j3d.*; public class lineShape2 extends Shape3D { int StripCount[] = new int[1]; private float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; public lineShape2() { StripCount[0] = 6; LineStripArray line = new LineStripArray(6, LineStripArray.COORDINATES| LineStripArray.COLOR_3,StripCount); line.setCoordinates(0,vert); line.setColors(0,color); LineAttributes la = new LineAttributes(); la.setLineWidth(30.0f); la.setLineAntialiasingEnable(true); la.setLinePattern(LineAttributes.PATTERN_DASH); Appearance ap = new Appearance(); ap.setLineAttributes(la); this.setGeometry(line); this.setAppearance(ap); } } //end of lineShape2.java ----------------------------------------- //Line2.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Line2 extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); objRoot.addChild(createObject()); objRoot.compile(); return objRoot; } private Group createObject() { Transform3D t = new Transform3D(); TransformGroup objTrans = new TransformGroup(t); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Shape3D shape = new lineShape2(); objTrans.addChild(shape); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 50.0); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); return objTrans; } public Line2() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Line2(), 400,400); } } //end of Line2.java 由上可知,Line2.java这个程序和Point5.java几乎没有 什么差别,除了类的名字于调用的外部程序名不同之外,其余 完全相同。 lineShape1.java和lineShape2.java相差不大, lineShape2.java多了一个StripCount数组,它可以用来生成 多个折线段,下面的lineShape3.java程序就将Line2.java生成 的一条折线段分成了两条折线段:0、1、2三个点构成了一个折 线段,3、4、5构成了另一条折线段,每个折线段的顶点数目就 构成了数组StripCount,StripCount数组的大小等于折线段的 数目。 //lineShape3.java import javax.media.j3d.*; public class lineShape3 extends Shape3D { int StripCount[] = new int[2]; private float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; public lineShape3() { StripCount[0] = 3; StripCount[1] = 3; LineStripArray line = new LineStripArray(6, LineStripArray.COORDINATES| LineStripArray.COLOR_3,StripCount); line.setCoordinates(0,vert); line.setColors(0,color); LineAttributes la = new LineAttributes(); la.setLineWidth(30.0f); la.setLineAntialiasingEnable(true); la.setLinePattern(LineAttributes.PATTERN_DASH); Appearance ap = new Appearance(); ap.setLineAttributes(la); this.setGeometry(line); this.setAppearance(ap); } } //end of lineShape3.java 将lineShape3.java生成的绕Y轴旋转的形体用VRML 程序表示的结果为: #VRML V2.0 utf8 DEF T Transform{ children Shape { geometry IndexedLineSet { coord Coordinate { point [.8 .8 .0, -.8, .8 0, .5 0 0, -.5 0 0, -.8 -.8 0, .8 -.8 0]} coordIndex [0 1 2 -1, 3 4 5 ] # 两个折线段 color Color{ color [ .0 .5 1., .5 .0 1, 0 .8 .2, 1 0 .3, 0 1 .3, .3 .8 0 ]} }}} DEF TS TimeSensor{ cycleInterval 4 loop TRUE} DEF OI OrientationInterpolator{ key [0 .25 .5 .75 1] keyValue [0 1 0 1, 0 1 0 1.57, 0 1 0 3.14 0 1 0 4.71 0 1 0 6.28]} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation #end of lineShape3.wrl 三. 利用IndexedLineArray生成直线 IndexedLineArray对象的定义为: IndexedLineArray(int vertexCount, int vertexFormat, int indexCount ) 这里: vertexCount表示顶点数组里顶点的个数 vertexFormat表示顶点的格式(第七讲有介绍) indexCount表示选用的顶点个数,如果一个点用了 几次,则要把几次加进去 在上一节里我们介绍了利用IndexedPoint生成点 的程序,和IndexedPoint相类似,我们可以利用 IndexedLineArray生成直线段。 下面的lineShape4.java利用了IndexedLineArray 从六个点中挑选了3个点,生成了2条直线。 从程序中我们可以看到,下标为0的点使用了两次, 但生成的是两条线,因而参数VertexCount应为4,即 此处的VertexCount的数值应为直线条数的两倍。 //lineShape4.java import javax.media.j3d.*; public class lineShape4 extends Shape3D { int[] index={ 1, 0, 0 , 3, }; int VertexCount=4; private float vert[] = { .8f, 0.8f,0.0f, -0.8f, 0.8f,0.0f, 0.5f, 0.0f,0.0f, -0.5f, 0.0f,0.0f, -0.8f,-0.8f,0.0f, 0.8f,-0.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, }; public lineShape4() { IndexedLineArray line = new IndexedLineArray(6, IndexedLineArray.COORDINATES| IndexedLineArray.COLOR_3,VertexCount); line.setCoordinates(0,vert); line.setColors(0,color); line.setCoordinateIndices(0,index); line.setColorIndices(0,index); LineAttributes la = new LineAttributes(); la.setLineWidth(30.0f); la.setLineAntialiasingEnable(true); la.setLinePattern(LineAttributes.PATTERN_DASH); Appearance ap = new Appearance(); ap.setLineAttributes(la); this.setGeometry(line); this.setAppearance(ap); } } //end of lineShape4.java 将lineShape4.java翻译成VRML的相应程序为: #VRML V2.0 utf8 DEF T Transform{ children Shape { geometry IndexedLineSet { coord Coordinate { point [.8 .8 .0, -.8, .8 0, .5 0 0, -.5 0 0, -.8 -.8 0, .8 -.8 0]} coordIndex [1 0 -1 0 3] color Color{ color [ .0 .5 1., .5 .0 1, 0 .8 .2, 1 0 .3, 0 1 .3, .3 .8 0 ]} }}} DEF TS TimeSensor{ cycleInterval 4 loop TRUE} DEF OI OrientationInterpolator{ key [0 .25 .5 .75 1] keyValue [0 1 0 1, 0 1 0 1.57, 0 1 0 3.14 0 1 0 4.71 0 1 0 6.28]} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation 四. 利用IndexedLineStripArray生成直线 IndexedLineStripArray对象的定义如下: IndexedLineStripArray( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 这里: vertexCount表示顶点数组里顶点的个数 vertexFormat表示顶点的格式(第七讲有介绍) indexCount表示选用的顶点的个数 stripIndexCounts为一数组,数组里的每一个数值表示 每条折线段所拥有的顶点数目。 下面的程序里,我们给出10个顶点, --0-- --1-- --2-- --3-- --4-- --5-- --6-- --7-- --8-- --9-- 然后我们用IndexedLineStripArray生成三个折线段,第一个 折线段为:0 1 3 2,第二个折线段为3、5、4,第三个折线段为 6、7、8、6,最后一个点没有用到。所有的直线宽度为30像数。 这时我们只用了10个点中的9个点,但有2个点用了两次,因而程序 中的vertexCount为11, 程序如下: //lineShape5.java import javax.media.j3d.*; public class lineShape5 extends Shape3D { int StripCount[] = new int[3]; int[] index={ 0 , 1 , 3 , 2 , 3 , 5 , 4 , 6 , 7 , 8 , 6 } ; int vertexCount = 11; private float vert[] = { -.3f , .8f , .0f, .3f , .8f , .0f, -.3f , .4f , .0f, .3f , .4f , .0f, -.3f , .0f , .0f, .3f , .0f , .0f, -.3f , -.4f , .0f, .3f , -.4f , .0f, -.3f , -.8f , .0f, .3f , -.8f , .0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f }; public lineShape5() { StripCount[0] = 4; StripCount[1] = 3; StripCount[2] = 4; IndexedLineStripArray line = new IndexedLineStripArray(10 , IndexedLineStripArray.COORDINATES| IndexedLineStripArray.COLOR_3, vertexCount , StripCount); line.setCoordinates(0,vert); line.setColors(0,color); line.setCoordinateIndices(0,index); line.setColorIndices(0,index); LineAttributes la = new LineAttributes(); la.setLineWidth(30.0f); la.setLineAntialiasingEnable(true); la.setLinePattern(LineAttributes.PATTERN_DASH); Appearance ap = new Appearance(); ap.setLineAttributes(la); this.setGeometry(line); this.setAppearance(ap); } } //end of lineShape5.java 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(十)(转载) 发信站: 飘渺水云间 (Tue Apr 13 20:00:11 1999), 转信 JAVA3D学习系列(9)----- 面的生成(上) 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 一. 生成平面的对象及其定义 JAVA3D可通过编程显示出面来,面有两种:三角形和四边形, 相应的对象为Triangle和Quad。 JAVA3D用于生成平面的对象有: 1. TriangleArray TriangleArray (int vertexCount, int vertexFormat ) 2. QuadArray QuadArray (int vertexCount, int vertexFormat ) 3. TriangleStripArray TriangleStripArray ( int vertexCount , int vertexFormat, int[] stripVertexCounts ) 4. TriangleFanArray TriangleFanArray ( int vertexCount ,int vetexFormat, int[] stripVertexCounts ) 5. IndexedTriangleArray IndexedTriangleArray (int vertexCount , int vertexFormat, int indexCount) 6. IndexedQuadArray IndexedQuadArray (int vertexCount , int vertexFormat, int indexCount ) 7. IndexedTriangleStripArray IndexedTriangleStripArray( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 8. IndexedTriangleFanArray IndexedTriangleFanArray ( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 二. TriangleArray生成的面 和前面介绍的PointArray、LineArray一样,面也可以用 TriangleArray来生成,利用它可以生成三角片面我们先看一下TriangleArray的定义: TriangleArray (int vertexCount, int vertexFormat ) 这里: vertexCount表示顶点的个数(必须为三的倍数) vertexFormat表示顶点的格式(第七讲有介绍) 下面我们看一个利用TriangleArray的例子,例子里有九个点。 --1-- --4-- --7-- --0-- --3-- --6-- --2-- --5-- --8-- //triShape1.java import javax.media.j3d.*; public class triShape1 extends Shape3D { private float vert[] = { -.8f , .0f ,0.0f, -.4f , .8f ,0.0f, -.4f , -.8f,0.0f, -.2f , .0f ,0.0f, 0.2f , .8f ,0.0f, 0.2f , -.8f,0.0f, 0.4f , .0f ,0.0f, 0.8f , .8f ,0.0f, 0.8f , -.8f,0.0f, }; private float color[] = { 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, 1.0f,0.0f,0.3f, 0.0f,1.0f,0.3f, 0.3f,0.8f,0.0f, 0.0f,0.5f,1.0f, 0.5f,0.0f,1.0f, 0.0f,0.8f,2.0f, }; public triShape1() { TriangleArray tri = new TriangleArray(9, TriangleArray.COORDINATES|TriangleArray.COLOR_3); tri.setCoordinates(0,vert); tri.setColors(0,color); this.setGeometry(tri); } } //end of triShape1.java 从程序运行结果可以得知,TriangleArray将一个顶点数组的 每三个数组合在一个,生成一个面,因而vertexCount的点数必须 为三的倍数。triShape1.java显示的结果是三个三角形构成的面。 由于对每一个顶点都定义了颜色,因而程序显示的是色彩变化的 三角形,且只能从正面看到,反面看不到,这和VRML程序生成面 的效果完全一样。在VRML程序中,为了使一个面的正反方向都可见, 可以在IndexedFaceSet节点中将solid字段设为FALSE。 下面是和triShape1.java相对应的VRML程序,为了使面的正反 都可见,我们将IndexedFaceSet的solid字段设为FALSE。 #VRML V2.0 utf8 DEF T Transform{ children Shape { geometry IndexedFaceSet { solid FALSE coord Coordinate { point [ -.8 , .0 ,0.0, -.4 , .8 ,0.0, -.4 , -.8,0.0, -.2 , .0 ,0.0, 0.2 , .8 ,0.0, 0.2 , -.8,0.0, 0.4 , .0 ,0.0, 0.8 , .8 ,0.0, 0.8 , -.8,0.0,]} coordIndex [0 1 2 -1 3 4 5 -1 6 7 8] color Color{ color [ 0.0,0.5,1.0, 0.5,0.0,1.0, 0.0,0.8,2.0, 1.0,0.0,0.3, 0.0,1.0,0.3, 0.3,0.8,0.0 0.0,0.5,1.0, 0.5,0.0,1.0, 0.0,0.8,2.0,]} }}} DEF TS TimeSensor{ cycleInterval 4 loop TRUE} DEF OI OrientationInterpolator{ key [0 .25 .5 .75 1] keyValue [0 1 0 1, 0 1 0 1.57, 0 1 0 3.14 0 1 0 4.71 0 1 0 6.28]} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation 如何将triShape1.java显示的内容从色彩变化及单面显示 变为每一个面只有一种颜色及双面显示? VRML程序中我们可以将IndexedFaceSet节点的 colorPerVertex设为FALSE,并提供一个 colorIndex字段以挑选颜色数组中的颜色。 在JAVA3D程序中我们有一个笨办法处理颜色问题,即将 每一个面的三个点的颜色均设定为相同的数值,因为 TriangleArray对象没有 setColorIndices(0,index) 这一方法,故不能从颜色组中选用颜色。 至于双面显示问题,我们可以通过设定PolygonAttributes 对象的setCullFace(int cullFace)方法来获得,cullFace可以为: CULL_NONE CULL_FRONT CULL_BACK 通过选择其中之一,来获得前面、后面及双面的显示效果,缺省 值为只显示前面。 另外,我们还可以通过设定PolygonAttributes对象的 setPolygonMode(int polygonMode)方法使面用顶点或端线来代替。 polygonMode有下列三种选择: POLYGON_POINT POLYGON_LINE POLYGON_FILL 缺省值为POLYGON_FILL。 triShape2.java显示的是前后都可以看得见的面,每一个面 都有唯一的颜色。 //triShape2.java import javax.media.j3d.*; public class triShape2 extends Shape3D { private float vert[] = { -.8f , .0f ,0.0f, -.4f , .8f ,0.0f, -.4f , -.8f,0.0f, -.2f , .0f ,0.0f, 0.2f , .8f ,0.0f, 0.2f , -.8f,0.0f, 0.4f , .0f ,0.0f, 0.8f , .8f ,0.0f, 0.8f , -.8f,0.0f, }; private float color[] = { 1.0f,0.0f,0.0f, 1.0f,0.0f,0.0f, 1.0f,0.0f,0.0f, 0.0f,1.0f,0.0f, 0.0f,1.0f,0.0f, 0.0f,1.0f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,1.0f, }; public triShape2() { TriangleArray tri = new TriangleArray(9, TriangleArray.COORDINATES|TriangleArray.COLOR_3); tri.setCoordinates(0,vert); tri.setColors(0,color); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); //pa.setPolygonMode(PolygonAttributes.POLYGON_LINE); // 增加这一行会使面由线代替 Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); } } 三. QuadArray生成的面 QuadArray对象的定义如下: QuadArray (int vertexCount, int vertexFormat ) 这里,每一个参数的含义都和TriangleArray里的一样。 QuadArray可用来生成平面,构成平面的顶点的数目必须为 4的倍数。 下面我们来看一个利用QuadArray的例子,例子里有8个点, 程序运行后生成了两个长方形面。 //quadShape1.java import javax.media.j3d.*; public class quadShape1 extends Shape3D { private float vert[] = { -.6f , .8f ,0.0f, -.6f , -.8f,0.0f, -0.2f , -.6f,0.0f, -0.2f , .6f ,0.0f, 0.2f , .8f ,0.0f, 0.6f , .8f, 0.0f, 0.6f , -.8f, 0.0f, 0.2f , -.8f,0.5f, }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, }; public quadShape1() { QuadArray tri = new QuadArray(8, QuadArray.COORDINATES|QuadArray.COLOR_3); tri.setCoordinates(0,vert); tri.setColors(0,color); this.setGeometry(tri); } } //end of quadShape1.java 程序的双面显示问题及单一颜色问题的处理同上面的 triShape2.java。 编写QuadArray应用程序时,我们要注意几个问题。 首先是四点应当共面,如果不共面,程序仍然可以编译 运行,但显示的内容为两个三角面。 其次是四个点组成的面不应有凹点,这有点象VRML程序中 的Extrusion、IndexedFaceSet里的情况,当然,在VRML程序中 四个点构成的面可以有凹点,这时只需要在相应的节点内加上 一个参数: convex TRUE 而在JAVA3D程序中,如果QuadArray生成的面有凹点时, 程序的显示结果会不正确,例如,当我们将quadShape里的顶点 坐标换为: private float vert[] = { -.6f , .8f , 0.0f, -.6f , -.8f , 0.0f, -0.2f, -.6f , 0.0f, -0.5f, .0f , 0.0f, 0.2f , .8f , 0.0f, 0.6f , .8f , 0.0f, 0.6f , -.8f , 0.0f, 0.2f , -.8f , 0.5f, }; 时,显示的结果不确定,正面时是一个形状,转到反面时是 另一个形状。 最后一个问题是QuadArray所利用的每四个点,其坐标 位置除了要共面、凸点,四个点的旋转方向也要注意,如果 点的旋转方向是逆时针的话,其正面朝外,反之则朝内。当 我们将顶点的坐标换成下面的数据时,我们可以清楚地得出 这一结论。 private float vert[] = { -.6f , .8f ,0.0f, -.6f , -.8f ,0.0f, -0.2f , -.4f ,0.0f, -0.2f , .4f ,0.0f, 0.2f , .8f ,0.0f, 0.6f , .8f ,0.0f, 0.6f , -.8f ,0.0f, 0.2f , -.8f ,0.5f, }; 四. TriangleStripArray生成的面 TriangleStripArray对象的定义为: TriangleStripArray ( int vertexCount , int vertexFormat, int[] stripVertexCounts ) 利用TriangleStripArray对象,我们可以生成多组三角片面, 对于每一组三角片面来说,它的头三个点生成一个面,从第四个点 开始,每一个点都和前两个点生成一个新的面。 下面的程序中,我们利用一组点,生成了两组三角片面。程序 中,顶点数组的个数为11,头一组用了7个顶点,生成了5个相连的 三角片面,后一组用了5个顶点,生成了三个相连的三角片面。 //triShape3.java import javax.media.j3d.*; public class triShape3 extends Shape3D { int StripCount[] = new int[2]; private float vert[] = { -.6f , .8f , 0.0f, -.6f , -.8f, 0.2f, -0.2f , .5f, -.2f, -0.2f , -.5f , 0.2f, 0.0f , -.5f, -.2f, 0.0f , .5f , .2f, 0.2f , .0f, .0f, 0.2f , .8f , 0.3f, 0.2f , -.8f, -0.3f, 0.6f , .8f, 0.0f, 0.6f , -.8f, 0.5f, 0.8f , 0.0f , .3f }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, }; public triShape3() { StripCount[0] = 7; StripCount[1] = 5; TriangleStripArray tri = new TriangleStripArray(12, TriangleStripArray.COORDINATES| TriangleStripArray.COLOR_3 , StripCount); tri.setCoordinates(0,vert); tri.setColors(0,color); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); this.setGeometry(tri); } } //end of triShape3.java 五. TriangleFanArray生成的面 TriangleFanArray对象的定义为: TriangleFanArray ( int vertexCount ,int vetexFormat, int[] stripVertexCounts ) 利用TriangleFanArray对象,我们可以生成多组三角片面,每组 三角片面占用一定数量的顶点,每个组在生成三角片面时,头三个顶 点构成一个三角片面,其余的顶点和前面的顶点及每组第一个顶点生成 一个三角片面。下面的triShape4.java程序中,我们生成了两组三角 片面,头5个点生成了三个相连的三角片面,后6个点生成了四个相连的 三角片面。形状就像两把扇子,一大一小。 //triShape4.java import javax.media.j3d.*; public class triShape4 extends Shape3D { int FanCount[] = new int[2]; private float vert[] = { 0.0f , 0.0f , 0.0f, -0.3f , 0.3f , 0.02f, -0.1f , 0.4f , -0.02f, 0.1f , 0.4f , 0.02f, 0.3f, 0.3f , -0.02f, 0.0f, -0.8f , 0.0f, -0.6f, -0.2f, 0.02f, -0.3f, -0.1f , -0.02f, .0f, -0.05f, 0.02f, .3f, -0.1f, -0.02f, .6f, -0.2f, 0.02f }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, }; public triShape4() { FanCount[0] = 5; FanCount[1] = 6; TriangleFanArray tri = new TriangleFanArray(11, TriangleFanArray.COORDINATES| TriangleFanArray.COLOR_3 , FanCount); tri.setCoordinates(0,vert); tri.setColors(0,color); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); this.setGeometry(tri); } } //end of triShape4.java 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(十一)(转载) 发信站: 飘渺水云间 (Tue Apr 13 20:13:18 1999), 转信 JAVA3D学习系列(10)----- 面的生成(下) 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 一. IndexedTriangleArray生成的面 IndexedTriangleArray对象的定义为: IndexedTriangleArray (int vertexCount , int vertexFormat, int indexCount) 利用这个对象,我们可以从一个顶点数组中挑选一些顶点生成自己 所需要的三角片面。程序triShape5.java中,有一个10个点的数组,我们 从这个数组中选择了8个点,生成了三个面,其中有一个点用了两次,如果 所挑选的点都只用一次,则选择的点的数目必须为3的倍数。 另外,在编程时,我们要注意点的旋转顺序,逆时针旋转和顺时针 旋转有时会产生不同的效果。 程序中,vertexCount表示顶点数组顶点的总数,indexCount表示生成 的面的顶点个数,数值为面的个数的三倍,本例中,生成的面为三个,故 vertexCount为9。 //triShape5.java import javax.media.j3d.*; public class triShape5 extends Shape3D { private float vert[] = { -.6f , .6f ,.0f , -.6f , -.6f, .0f , -.3f , .6f ,.0f , -.3f , -.6f, .0f , -.0f , .6f ,.0f , -.0f , -.6f, .0f , .3f , .6f ,.0f , .3f , -.6f, .0f , .6f , .6f ,.0f , .6f , -.6f, .0f , }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, }; public triShape5() { int[] index={ 0 , 1 , 2 , 4 , 5 , 6 , 6 , 7 , 8 }; int VertexCount=9; IndexedTriangleArray tri = new IndexedTriangleArray(10, IndexedTriangleArray.COORDINATES| IndexedTriangleArray.COLOR_3 , VertexCount); tri.setCoordinates(0,vert); tri.setColors(0,color); tri.setCoordinateIndices(0,index); tri.setColorIndices(0,index); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); this.setGeometry(tri); } } //end of triShape5.java 二. IndexedQuadArray生成的面 IndexedQuadArray对象的定义为: IndexedQuadArray (int vertexCount , int vertexFormat, int indexCount ) 利用这个对象,我们可以从一个顶点数组中挑选一些顶点生成自己 所需要的四个点所构成的平面。程序quadShape2.java中,有一个10个点 的数组,我们从这个数组中选择了7个点,生成了两个面,其中有一个点 用了两次,如果所挑选的点都只用一次,则选择的点的数目必须为4的倍数。 这些选中的点构成了数组index。在输入每一个顶点的坐标及颜色时,我们 用到了下面两种方法: setCoordinateIndices(0,index); setColorIndices(0,index); 程序中,vertexCount表示顶点数组顶点的总数,indexCount表示生成 的面的顶点个数,数值为面的个数的4倍,本例中,生成的面为两个,故 vertexCount为8。 编写IndexedQuadArray应用程序时,我们仍然要注意下面几个问题。 首先是四点应当共面,如果不共面,程序仍然可以编译 运行,但显示的内容为两个三角面。 其次是四个点组成的面不应有凹点,这有点象VRML程序中 的Extrusion、IndexedFaceSet里的情况,当然,在VRML程序中 四个点构成的面可以有凹点,这时只需要在相应的节点内加上 一个参数: convex TRUE 而在JAVA3D程序中,如果QuadArray生成的面有凹点时, 程序的显示结果会不正确。 //quadShape2.java import javax.media.j3d.*; public class quadShape2 extends Shape3D { private float vert[] = { -.6f , .6f , .0f , -.6f , -.6f, .0f , -.3f , .6f , .0f , -.3f , -.6f, .0f , -.0f , .6f , .0f , -.0f , -.6f, .0f , .3f , .6f , .0f , .3f , -.6f, .0f , .6f , .6f , .0f , .6f , -.6f, .0f , }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, }; public quadShape2() { int[] index={ 2 , 1 , 3 , 4 , 4 , 7 , 9 , 6}; int VertexCount=8; IndexedQuadArray quad = new IndexedQuadArray(10, IndexedQuadArray.COORDINATES| IndexedQuadArray.COLOR_3 , VertexCount); quad.setCoordinates(0,vert); quad.setColors(0,color); quad.setCoordinateIndices(0,index); quad.setColorIndices(0,index); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(quad); this.setAppearance(ap); this.setGeometry(quad); } } //end of quadShape2.java 三. IndexedTriangleStripArray生成的面 IndexedTriangleStripArray对象的定义为: IndexedTriangleStripArray( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 利用IndexedTriangleStripArray对象,我们可以生成多组三角片面, 对于每一组三角片面来说,它的头三个点生成一个面,从第四个点 开始,每一个点都和前两个点生成一个新的面。这些点可以通过一个数组index 从一个顶点数组中任意选取,它和TriangleStripArray的差别在于 TriangleStripArray对顶点没有选择权,而IndexedTriangleStripArray 对顶点具有选择权,其它的都一样。 程序triShape6.java给出了一个16个数构成的顶点数组,从中挑选了 两组数,每一组都有6个顶点构成并生成了相连的四个三角片面。 //triShape6.java import javax.media.j3d.*; public class triShape6 extends Shape3D { int StripCount[] = new int[2]; private float vert[] = { -.6f , .6f , .1f , -.6f , .2f , .2f , -.6f , -.2f , .1f , -.6f , -.6f , .2f , -.0f , .6f , -.1f , -.0f , .2f , -.2f , -.0f , -.2f , -.1f , -.0f , -.6f , -.2f , .6f , .6f , .1f , .6f , .2f , .2f , .6f , -.2f , .1f , .6f , -.6f , .2f , }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 5.0f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, }; public triShape6() { int[] index={ 0 , 1 , 4 , 5 , 8 , 9 , 2 , 3 , 6 , 7 , 10 }; StripCount[0] = 6; StripCount[1] = 5; int indexCount=11; IndexedTriangleStripArray tri = new IndexedTriangleStripArray(12, IndexedTriangleStripArray.COORDINATES| IndexedTriangleStripArray.COLOR_3 , indexCount , StripCou nt); tri.setCoordinates(0,vert); tri.setColors(0,color); tri.setCoordinateIndices(0,index); tri.setColorIndices(0,index); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); this.setGeometry(tri); } } //end of Shape6.java 四. IndexedTriangleFanArray生成的面 IndexedTriangleFanArray对象的定义为: IndexedTriangleFanArray ( int vertexCount, int vertexFormat, int indexCount, int stripIndexCounts[]) 利用这一对象,我们可以从一组顶点数组中挑选我们所需要的 顶点,生成多组三角片面,每组三角片面占用一定数量的顶点,每个组 在生成三角片面时,头三个顶点构成一个三角片面,其余的顶点和前面 的顶点及每组第一个顶点生成一个三角片面。下面的triShape7.java程 序中,我们生成了两组三角片面,头5个点生成了三个相连的三角片面, 后6个点生成了四个相连的三角片面。形状就像两把扇子,一大一小。 程序中所用的数组为20个点的顶点数组。 IndexedTriangleFanArray对象和TriangleFanArray的应用方法很相似, 它们之间的不同在于IndexedTriangleFanArray对象可以从顶点数组中挑选 自己所需要的顶点,而TriangleFanArray对象没有挑选权,只能被动地使用 顶点数组中的数据。 //triShape7.java import javax.media.j3d.*; public class triShape7 extends Shape3D { int StripCount[] = new int[2]; private float vert[] = { -.6f , .8f , -.1f , -.6f , .4f , -.0f , -.6f , .0f , .1f , -.6f , -.8f , -.1f , -.4f , .8f , .1f , -.4f , .4f , .1f , -.4f , .0f , -.1f , -.4f , -.8f , .1f , -.0f , .8f , -.1f , -.0f , .4f , -.0f , -.0f , .0f , .1f , -.0f , -.8f , -.1f , .4f , .8f , .1f , .4f , .4f , -.05f , .4f , .0f , -.1f , .4f , -.8f , .1f , .6f , .8f , -.1f , .6f , .4f , -.0f , .6f , .0f , .1f , .6f , -.8f , -.1f , }; private float color[] = { 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 1.0f,0.8f,0.0f, 0.5f,1.0f,0.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,1.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, 0.0f,0.5f,1.0f, 1.0f,0.5f,0.0f, 1.0f,0.0f,0.5f, 0.9f,1.0f,0.0f, 0.5f,0.0f,1.0f, }; public triShape7() { int[] index={ 9 , 4 , 8 , 12 , 16 , 11 , 2 , 6 , 10 , 14 , 18}; StripCount[0] = 5; StripCount[1] = 6; int indexCount=11; IndexedTriangleFanArray tri = new IndexedTriangleFanArray(20, IndexedTriangleFanArray.COORDINATES| IndexedTriangleFanArray.COLOR_3 , indexCount , StripCount ); tri.setCoordinates(0,vert); tri.setColors(0,color); tri.setCoordinateIndices(0,index); tri.setColorIndices(0,index); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); Appearance ap = new Appearance(); ap.setPolygonAttributes(pa); this.setGeometry(tri); this.setAppearance(ap); this.setGeometry(tri); } } /end of triShape7.java 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(十二)(转载) 发信站: 飘渺水云间 (Fri Apr 16 13:32:38 1999), 转信 JAVA3D学习系列(11)---外部复杂形体的调用 (Wavefront的OBJ,Lightwave的LWS和LWO,WRL,DWG,3DS) 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 我们可以利用前面介绍的方法生成我们所需要的基本形体, 生成点、线、平面。但有的时候,我们需要用到其它格式的三 维形体,如VRML2.0格式的图形文件,AUTOCAD绘出的DWG格式的 三维形体,3DS MAX绘制出的复杂形体。对于这些形体,我们可 以非常方便地将其用到JAVA3D程序中去。下面我们介绍一些图形 格式在JAVA3D中的应用方法。 一. Wavefront的OBJ格式的图形文件的调用 1. OBJ格式图形的简单调用 JAVA3D编译环境所带的UTILITY有两个LOADER,一个可用来 调用Wavefront软件的OBJ格式的三维图形格式文件,一个可用来 调用Lightwave软件的LWS及LWO格式的三维图形格式文件。 假设我们有一个OBJ格式的文件(JAVA3D附带有两个OBJ,文 件名分别为galleon.obj和p51_mustang.obj,以及调用它们的一 个程序ObjLoad.java)。 我们编写的第一个程序Obj1.java介绍了OBJ图形的调用方法。 程序的便宜方法: javac Obj1.java 程序的运行方法(假设图形在同一目录): java Obj1 galleon.obj //Obj1.java 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.*; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Obj1 extends Applet { private String filename = null; public BranchGroup createSceneGraph(String args[]) { BranchGroup objRoot = new BranchGroup(); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objRoot.addChild(objTrans); ObjectFile f = new ObjectFile( ); Scene s = null; try { s = f.load(filename); } catch (FileNotFoundException e) { System.err.println(e); System.exit(1); } catch (ParsingErrorException e) { System.err.println(e); System.exit(1); } catch (IncorrectFormatException e) { System.err.println(e); System.exit(1); } objTrans.addChild(s.getSceneGroup()); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objRoot.compile(); return objRoot; } public Obj1(String args[]) { filename = args[0]; setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(args); //与通常的有不同 SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Obj1(args), 400,400); } } //end of Obj1.java 程序运行后我们发现,显示的效果不太正确,形体只显示了 一部分,我们将在Obj2.java将其效果修正一下。 我们来看程序,为了使JAVA3D能够调用Wavefront的OBJ格式 的图形文件,我们需要用到JAVA3D所附带的UTILITY。程序的头 四行import语句就是用来处nsform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objRoot.compile(); return objRoot; } public Obj3(String args[]) { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Obj3(args), 400,400); } } //end of Obj3.java -------------------------- //objFile.java 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.*; import javax.media.j3d.*; public class objFile extends BranchGroup{ private double creaseAngle = 60.0; public objFile(String filename) { BranchGroup obj = new BranchGroup( ); int flags = ObjectFile.RESIZE; ObjectFile f = new ObjectFile(flags, (float)(creaseAngle * Math.PI / 180.0)); Scene s = null; try { s = f.load(filename); } catch (FileNotFoundException e) { System.err.println(e); System.exit(1); } catch (ParsingErrorException e) { System.err.println(e); System.exit(1); } catch (IncorrectFormatException e) { System.err.println(e); System.exit(1); } obj.addChild(s.getSceneGroup( ) ); this.addChild(obj); } } //end of objFile.java 4.同时调用两个形体,两者单独旋转。 前面的程序中,形体只有一个,为此,我们编了一个 程序,利用它可以调用两个OBJ形体,一左一右,它们分别绕 自身的轴旋转,当然,形体的生成仍然使用上面的 objFile.java程序。另外,我们还在程序中加了红色的背景。 //Obj4.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; public class Obj4 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objScale = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.3); objScale.setTransform(t3d); objRoot.addChild(objScale); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); Color3f bgColor = new Color3f(1.05f, 0.00f, 0.0f); Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); objRoot.addChild(bg); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); BranchGroup b1 = new objFile("1.obj"); BranchGroup b2 = new objFile("2.obj"); objScale.addChild(createObject (b1, -1.2f , 0.0f )); objScale.addChild(createObject (b2, 1.2f , 0.0f )); objRoot.compile(); return objRoot; } private Group createObject (BranchGroup b, float xpos, float ypos ) { Transform3D t = new Transform3D ( ); t.setTranslation ( new Vector3f ( xpos, ypos, 0.0f ) ); TransformGroup objTrans = new TransformGroup(t); TransformGroup spin = new TransformGroup(); spin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); spin.addChild(b); Transform3D yAxis = new Transform3D ( ); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, spin, yAxis, 0.0f, (float) Math.PI*2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objTrans.addChild ( spin ); return objTrans ; } public Obj4(String args[]) { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Obj4(args), 400,400); } } //end of Obj4.java 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(十三)(转载) 发信站: 飘渺水云间 (Fri Apr 16 13:38:41 1999), 转信 JAVA3D学习系列(12)---AUTOCAD的DWG、VRML的WRL及3DS MAX图形的调用 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 一. VRML2.0(VRML97)图形文件在JAVA3D中的应用简介 SUN公司为我们提供了一个VRML97的LOADER,利用它我们可以 在JAVA3D程序中方便地调用VRML图形。不过由于这个LOADER目前 还不是很完善,因而没有放入JAVA3D之中,不过随着它的完善, 最终它会成为JAVA3D的一个组成部分,调用VRML97程序就象调用 Wavefront的OBJ一样简单。 我们可以从以下的网址下载(VRML97.ZIP)并安装,下载的网址为: http://www.vrml.org/WorkingGroups/vrml-java3d/ 从这个网页上我们需要下载目前大小为283KB的一个ZIP文件, VRML97.ZIP,利用解压程序将其解成VRML97.JAR,大小目前为310KB, 版本为0.90.2版,利用它可以让我们在JAVA3D程序中调用 VRML97(VRML2.0)图形。 *********好消息****************** 为了使国内的JAVA3D爱好者能够节省时间及开支,本人愿意 向国内的JAVA3D爱好者提供最新的VRML97.JAR,咨询请发EMAIL。 收到EMAIL后一分钟内就可将VRML97.JAR发出。 *********好消息****************** 二. VRML97.JAR的安装 获得VRML97.JAR后,假设我们的JDK1.2摆放的位置为目录JDK1.2, 我们应将其放在下面的子目录中: C:\jdk1.2\lib 并在WINDOWS的AUTOEXEC.BAT文件中写入下面一行: SET CLASSPATH=%CLASSPATH%;C:\JDK1.2\LIB\vrml97.jar 重新启动计算机,这样我们就可以利用它了。 当然,我们可以将VRML97.JAR放在一个目录中,利用下面的方法 将其解开,不过所获得的全为CLASS文件。 三. VRML97.JAR的应用 1. 利用VRML971.JAR调用一个VRML文件,使VRML文件中的形体不停地 旋转,程序如下。 程序的编译方法: javac Vrml1.java 程序的运行方法(假设图形在同一目录): java Vrml1 myShape.wrl 当然,如果所调用的形体非常大或非常小时,需要修改: t3d.setScale(0.3); 中的数值。 //Vrml.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.loaders.vrml97.VrmlLoader; import com.sun.j3d.loaders.Scene; public class Vrml1 extends Applet { private String filename = null; public BranchGroup createSceneGraph(String args[]) { BranchGroup objRoot = new BranchGroup(); TransformGroup objScale = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.3); objScale.setTransform(t3d); objRoot.addChild(objScale); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objScale.addChild(objTrans); VrmlLoader loader = new VrmlLoader(); Scene s = null; try { s = loader.load(filename); } catch (Exception e) { System.err.println(e); System.exit(1); } objTrans.addChild(s.getSceneGroup()); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objRoot.compile(); return objRoot; } public Vrml1(String args[]) { filename = args[0]; setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(args); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Vrml1(args), 400,400); } } //end of Vrml.java 可以看出,Vrml1.java和前面介绍的Obj2.java非常相似。 2. 将Vrml.java分解成两个程序 上面的程序中,用于处理调用问题的部分我们可以提取出来,这样 我们就可以多次重复使用。 从下面的程序我们可以得知,Vrml2.java和前面介绍的Obj3.java 除了Obj3改为Vrml2,objFile改为vrmlLoad之外,其余什么也没有改变。 vrmlLoad.java和objFile.java也非常相似。 //Vrml2.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; public class Vrml2 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objScale = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.3); objScale.setTransform(t3d); objRoot.addChild(objScale); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); Color3f bgColor = new Color3f(0.05f, 0.05f, 0.2f); Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); objRoot.addChild(bg); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objScale.addChild(objTrans); BranchGroup b1 = new vrmlLoad("7.wrl"); objTrans.addChild(b1); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objRoot.compile(); return objRoot; } public Vrml2(String args[]) { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Vrml2(args), 400,400); } } //end of Vrml2.java ----------------------------- //vrmlLoad.java import javax.media.j3d.*; import java.io.*; import com.sun.j3d.loaders.vrml97.VrmlLoader; import com.sun.j3d.loaders.Scene; public class vrmlLoad extends BranchGroup{ public vrmlLoad(String filename) { BranchGroup obj = new BranchGroup( ); VrmlLoader loader = new VrmlLoader(); Scene s = null; try { s = loader.load(filename); } catch (Exception e) { System.err.println(e); System.exit(1); } obj.addChild(s.getSceneGroup( ) ); this.addChild(obj); } } //end of vrmlLoad.java 3. 调用两个VRML文件并使其放在不同的位置处旋转 编写这个程序非常简单,只需将前面介绍的Obj4.java 稍作修改即可,程序如下: //Vrml3.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Vrml3 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objScale = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.1); objScale.setTransform(t3d); objRoot.addChild(objScale); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); Color3f bgColor = new Color3f(1.05f, 0.00f, 0.0f); Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); objRoot.addChild(bg); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); BranchGroup b1 = new vrmlLoad("7.wrl"); BranchGroup b2 = new vrmlLoad("8.wrl"); objScale.addChild(createObject (b1, -1.2f , 0.0f )); objScale.addChild(createObject (b2, 1.2f , 0.0f )); objRoot.compile(); return objRoot; } private Group createObject (BranchGroup b, float xpos, float ypos ) { Transform3D t = new Transform3D ( ); t.setTranslation ( new Vector3f ( xpos, ypos, 0.0f ) ); TransformGroup objTrans = new TransformGroup(t); TransformGroup spin = new TransformGroup(); spin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); spin.addChild(b); Transform3D yAxis = new Transform3D ( ); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, spin, yAxis, 0.0f, (float) Math.PI*2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); objTrans.addChild ( spin ); return objTrans ; } public Vrml3(String args[]) { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Vrml3(args), 400,400); } } //end of Vrml3.java 四. AUTOCAD R14的DWG图形及3DS MAX图形在JAVA3D中的应用。 在三维图形生成过程中,国内目前大量使用AUTOCAD及3DS MAX等 软件。如何将这些软件生成的三维图形应用到JAVA3D上去呢? 对于3DS MAX软件,处理起来非常方便,因为3DS MAX可以将其图形 直接输出成VRML97格式,因而可以按本讲介绍的方法处理。 对于AUTOCAD R14来说,目前还不太方便,不知AUTOCAD 2000是否 能直接输出VRML97图形格式。本人从欧洲捷克一个站点拷得一个文件, 可用来直接将AUTOCAD R14所绘制的三维图形转换成VRML97(VRML2.0) 格式,因而AUTOCAD软件生成的图形也可以非常方便地应用到JAVA3D上面, 为我们编写JAVA3D的复杂应用程序打下了良好的基础。此软件非常好用 (采用ARX技术编写)。 **************好消息************** 需要将AUTOCAD R14所生成的图形转换成VRML2.0的朋友,可 发一个EMAIL给我,在收到EMAIL一分钟之内,我将把 AUTOCAD ----> VRML的转换文件发出,大小为206KB。 **************好消息************** 发信人: cypress (Cypress), 信区: Cad 标 题: Java3D学习系列(十四)(转载) 发信站: 飘渺水云间 (Sun Apr 18 14:17:51 1999), 转信 JAVA3D学习系列(13)---形体的组合及几何坐标变换 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) VRML2.0(VRML97)中,有两个用来组合各形体的组节点: Transform、Group,其中的Group节点完全可以用Transform 节点来代替。如何在JAVA3D中实现Transform所提供的几何变换 功能,是我们掌握JAVA3D应用编程的基础。下面我们对此给以 详细的介绍。 我们首先来看一下VRML97的Transform节点的定义: Transform节点的定义是: Transform { eventIn MFNode addChildren eventIn MFNode removeChildren exposedField SFVec3f center 0 0 0 exposedField MFNode children [] exposedField SFRotation rotation 0 0 1 0 exposedField SFVec3f scale 1 1 1 exposedField SFRotation scaleOrientation 0 0 1 0 exposedField SFVec3f translation 0 0 0 field SFVec3f bboxCenter 0 0 0 field SFVec3f bboxSize -1 -1 -1 } 由定义我们可以看出,VRML程序中,我们可以通过设定 translation、rotation、scale来使形体产生平移、旋转、 比例变换。如VRML2.0交互式三维图形编程一书所给出的一个 生成一个小丑的程序Ex4_03.wrl,里面就对形体进行了平移、 旋转、比例变换。我们先给出Ex4_03.wrl程序(我们对 书中的程序进行了修改,使生成的小丑能够旋转),再给出 用JAVA3D编写出来的Ex4_03.java。 //Ex4_03.wrl #VRML V2.0 utf8 DEF T Transform{ children[ Transform { scale 1 1.2 1 children Shape { appearance Appearance{material Material {diffuseColor 1 1 0 }} geometry Sphere{}}} Transform{ translation .5 .4 .6 scale 1 1 2 children Shape{ appearance Appearance{material Material {diffuseColor 0 0 1}} geometry Sphere{radius .2}}} Transform { translation -.5 .4 .6 scale 1 1 2 children Shape{ appearance Appearance{material Material {diffuseColor 0 0 1}} geometry Sphere {radius .2}}} Transform{ translation 0 1 0 scale 1.1 .4 1.1 children Shape{ appearance Appearance{material Material {diffuseColor 1 0 0}} geometry Cone{}}} Transform{ translation 1 0 0 scale .2 .4 .2 children Shape{ appearance Appearance{material Material {diffuseColor 0 1 1}} geometry Sphere{}}} Transform{ translation -1 0 0 scale .2 .4 .2 children Shape{ appearance Appearance{material Material {diffuseColor 0 1 1}} geometry Sphere{}}} Transform{ translation 0 0 1 scale .2 .4 .2 rotation 1 0 0 -.5 children Shape{ appearance Appearance{material Material {diffuseColor 1 0 0}} geometry Sphere{}}} Transform{ translation 0 -.5 .9 scale .4 .1 .3 children Shape{ appearance Appearance{material Material {diffuseColor 1 1 1}} geometry Sphere{}}} ]} DEF TS TimeSensor{ cycleInterval 8 loop TRUE} DEF OI OrientationInterpolator{ key [0 .25 .5 .75 1] keyValue [0 1 0 0, 0 1 0 1.57, 0 1 0 3.14 0 1 0 4.71 0 1 0 6.28]} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation Background {skyColor 1 1 1} //end of Ex4_03.wrl ------------------------------ //Ex4_03.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Ex4_03 extends Applet{ public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.3); TransformGroup objScale = new TransformGroup(); objScale.setTransform(t3d); Transform3D temp = new Transform3D(); TransformGroup obj = new TransformGroup(); obj.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); obj.setTransform(temp); objScale.addChild(obj); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, obj, temp, 0.0f, (float) Math.PI*2.0f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); rotator.setSchedulingBounds(bounds); obj.addChild(rotator); objRoot.addChild(objScale); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); Appearance app_red = new Appearance(); Material material1 = new Material(); material1.setDiffuseColor(new Color3f(1.0f,0.0f,0.0f)); app_red.setMaterial(material1); Appearance app_yellow = new Appearance(); Material material2 = new Material(); material2.setDiffuseColor(new Color3f(1.0f,1.0f,0.0f)); app_yellow.setMaterial(material2); Appearance app_blue = new Appearance(); Material material3 = new Material(); material3.setDiffuseColor(new Color3f(0.0f,0.0f,1.0f)); app_blue.setMaterial(material3); Appearance app_cyan = new Appearance(); Material material4 = new Material(); material4.setDiffuseColor(new Color3f(0.0f,1.0f,1.0f)); app_cyan.setMaterial(material4); Appearance app_white = new Appearance(); Material material5 = new Material(); material5.setDiffuseColor(new Color3f(1.0f,1.0f,1.0f)); app_white.setMaterial(material5); Cone c = new Cone(1.0f,2.0f,1,app_red); Primitive s_1 = (Primitive) new Sphere(1.0f,app_yellow); Primitive s_2 = (Primitive) new Sphere(.2f ,app_blue); Primitive s_2b = (Primitive) new Sphere(.2f ,app_blue); Primitive s_3 = (Primitive) new Sphere(1.0f,app_cyan); Primitive s_3b = (Primitive) new Sphere(1.0f,app_cyan); Primitive s_4 = (Primitive) new Sphere(1.0f,app_red); Primitive s_5 = (Primitive) new Sphere(1.0f,app_white); Transform3D t1 = new Transform3D(); t1.setScale(new Vector3d(1,1.2,1)); TransformGroup objTrans1 = new TransformGroup(t1); objTrans1.addChild(s_1); Transform3D t2 = new Transform3D(); t2.setScale(new Vector3d(1,1,2)); t2.setTranslation(new Vector3f(0.5f, 0.4f, 0.6f)); TransformGroup objTrans2 = new TransformGroup(t2); objTrans2.addChild(s_2); Transform3D t3 = new Transform3D(); t3.setScale(new Vector3d(1,1,2)); t3.setTranslation(new Vector3f(-0.5f, 0.4f, 0.6f)); TransformGroup objTrans3 = new TransformGroup(t3); objTrans3.addChild(s_2b); Transform3D t4 = new Transform3D(); t4.setScale(new Vector3d(1.1,0.4,1.1)); t4.setTranslation(new Vector3f(0.0f, 1.0f, 0.0f)); TransformGroup objTrans4 = new TransformGroup(t4); objTrans4.addChild(c); Transform3D t5 = new Transform3D(); t5.setScale(new Vector3d(0.2, 0.4, 0.2)); t5.setTranslation(new Vector3f(1.0f, 0.0f, 0.0f)); TransformGroup objTrans5 = new TransformGroup(t5); objTrans5.addChild(s_3); Transform3D t6 = new Transform3D(); t6.setScale(new Vector3d(0.2, 0.4, 0.2)); t6.setTranslation(new Vector3f(-1.0f, 0.0f, 0.0f)); TransformGroup objTrans6 = new TransformGroup(t6); objTrans6.addChild(s_3b); Transform3D t7 = new Transform3D(); t7.setScale(new Vector3d(0.2, 0.4, 0.2)); t7.setTranslation(new Vector3f(0.0f, 0.0f, 1.0f)); TransformGroup objTrans7 = new TransformGroup(t7); objTrans7.addChild(s_4); Transform3D t8 = new Transform3D(); t8.setScale(new Vector3d(0.4, 0.1, 0.3)); t8.setTranslation(new Vector3f(0.0f, -0.5f, 0.9f)); TransformGroup objTrans8 = new TransformGroup(t8); objTrans8.addChild(s_5); Color3f bgColor = new Color3f(1.0f, 1.0f, 1.0f); Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); objRoot.addChild(bg); obj.addChild(objTrans1); obj.addChild(objTrans2); obj.addChild(objTrans3); obj.addChild(objTrans4); obj.addChild(objTrans5); obj.addChild(objTrans6); obj.addChild(objTrans7); obj.addChild(objTrans8); objRoot.compile(); return objRoot; } public Ex4_03() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Ex4_03(), 640, 480); } } //end of Ex4_03.java 我们来仔细研究JAVA3D所提供的形体几何变换功能。 前面我们主要介绍形体生成的方法,其中,编写自己的形体 用到的是Shape3D对象,VRML97与之对应的是Shape节点。 同样,JAVA3D对应于VRML97的Transform节点的对象是Transform3D。 VRML97编程中,形体的平移可以通过Transform节点的 translation字段来设置;JAVA3D编程时,形体的平移可以通过 Transform3D的setTranslation方法完成。 VRML97编程中,形体的旋转可以通过Transform节点的 rotation字段来设置;JAVA3D编程时,形体的旋转可以通过 Transform3D的setRotation方法完成。 VRML97编程中,形体的比例变化可以通过Transform节点的 scale字段来设置;JAVA3D编程时,形体的比例变化可以通过 Transform3D的setScale方法完成,其中,当扩弧里只有一个双 精度数时,setScale对所有的方向均采用同一个比例,而当里面 有三个双精度数时,setScale对不同的方向可以采用不同的比例, 双精度数后面不加符号,而单精度浮点数后面要加一个f。 我们来看一下程序的主要内容: 程序一开始就定义了一个BranchGroup,后面所有的生成的内容 如形体、形体的变换、背景、灯光都放入其中。 为了使我们生成的图形有合适的大小,我们定义了一个 TransformGroup对象objScale,通过一个t3d使其按比例缩小,这 相当于我们将视野往后移动。 为了使我们生成的小丑能够旋转,我们定义一个TransformGroup 类型的obj,这相当于定义了一个小丑所在的局部坐标系,设定此 坐标系可以旋转,选转方式由一个Transform3D类型的temp来确定, 定义obj为objScale的一个子节点。 通过定义rotationAlpha、rotator地定义使得obj能够产生旋转。 它们的作用类似于VRML的时间传感器及方向内插器。 接下来我们在空间中定义了一个定向光、各种材质、形体,并 将灯光、具有一定材质的形体放入objRoot、obj之中,最后我们 还定义了一个背景光。 通过这个程序的编写,我们掌握了JAVA3D生成复杂形体的最基本 概念,即如何进行形体的几何坐标变换。掌握了形体几何坐标变换 方法,我们就具有了编写JAVA3D复杂应用程序的能力。 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(十五)(转载) 发信站: 飘渺水云间 (Sun Apr 25 22:16:51 1999), 转信 JAVA3D学习系列(14)---初始观察位置的设定 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 一. 初始观察位置的给定 前面我们介绍的JAVA3D程序,在没有进行比例变换前,观察点位于 (0 , 0 , 2.41 ),这是由 setLayout(new BorderLayout()); Canvas3D c = new MyCanvas3D(null); add("Center",c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNorminalViewingTransform(); 多个语句确定的,在前面的第5讲已经对其作了简单介绍,大多数程序 都利用这些语句定义场景图中的一个观察分支。 我们可以将JAVA3D所提供的java3d-utils-src.jar按照下面 的方式解开: jar xvf java3d-utils-src.jar 就可以获得JAVA3D所有UTILITY的源程序,我们可以从其中的 SimpleUniverse.java、ViewingPlatform.java 程序了解JAVA3D是如何进行观察点初始位置的设置的。 语句中的u定义了一个SimpleUniverse类型的对象实例。 getViewingPlatform()方法定义在ViewingPlatform.java中, 利用它可以获得程序所需要的观察位置,而此方法又通过 ViewingPlatform.java中的setNorminalViewingTransform() 来做进一步的设置。 在没有用到setNorminalViewingTransform()之前, ViewingPlatform() 给出的缺省观察位置为坐标原点(0,0,0), 而当我们用到setNorminalViewingTransform()时,由 viewDistance我们得知这时的观察点的Z坐标移到了 1/tan(math.PI/8),也即2.41。 **************这时的观察视角为90°**************** 如果要使程序的观察点为一个可以很方便改动的点,我们就 需要将程序改动,下面是我们将前面介绍的第4讲的程序 SimpleCone.java,修改获得的新程序NewCone.java,两者的差别 在于,SimpleCone.java的观察点位于(0,0,2.41), NewCone.java的观察点坐标位于(0, 0, 10)。我们可以根据需要 设定初始的观察点的位置,这时只需要方便地将(0,0, 10)改为 我们所需要的任何数值。初始观察位置改动同样用到了 SimpleUniverse对象,只是将对象的观察点坐标变量作了修改。 //NewCone.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class NewCone extends Applet{ public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objTrans = new TransformGroup(); objRoot.addChild(objTrans); Appearance app = new Appearance(); Material material = new Material(); material.setEmissiveColor(new Color3f(1.0f,0.0f,0.0f)); app.setMaterial(material); Cone cone=new Cone(.5f,1.0f,1,app); objTrans.addChild(cone); objRoot.compile(); return objRoot; } public NewCone() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); ViewPlatform viewPlatform; Viewer viewer = new Viewer(c); Vector3d viewpoint = new Vector3d(0.0, 0.0, 10.0); //初始观察点位置 Transform3D t = new Transform3D(); t.set(viewpoint); ViewingPlatform v = new ViewingPlatform( ); v.getViewPlatformTransform().setTransform(t); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse( v, viewer); u.getViewingPlatform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new NewCone(), 256, 256); } } //end of NewCone.java 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(十六)(转载) 发信站: 飘渺水云间 (Mon Apr 26 11:57:22 1999), 转信 【 以下文字转载自 screamer 的信箱 】 【 原文由 screamer 所发表 】 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 1997年底正式成为国际标准的VRML2.0是我们编写简单 三维应用程序的一个非常合适的计算机语言,利用它,我们可以 非常方便地编写三维动画、交互式的三维游戏,当然,只能 是一些较为简单的三维动画及交互式三维游戏。而利用JAVA3D 则可以编写出较为复杂的三维动画及交互式三维游戏。 前面我们介绍了JAVA3D的形体生成等方面的知识,JAVA3D 三维应用程序最吸引人之处是它可以用来制作三维动画、三维 游戏等。为了掌握JAVA3D三维动画、三维游戏的编程,我们首先 要掌握三维形体在空间的运动控制。 VRML语言有6个内插器节点和7个传感器节点,同样地,在 JAVA3D中,也有和VRML内插器节点类似的Interpolator对象,它 们和另一个Alpha类结合在一起,可以编写出各种类型的三维动画 程序。 下面我们就介绍这些对象及其应用方法。 一. Alpha类 从VRML的各个内插器节点的定义来看,我们可以看到,每一个 内插器节点都有一个key字段和一个keyValue字段。key字段定义 一个数组,数值从0到1。 所有的内插器节点在使用时都需要与TimeSensor(时间传感器) 配合使用。TimeSensor把给定的时间周期归一化,虽然时间的周期 cycleInterval 有给定的秒数,但计算机内部将其处理成从0.0到 1.0,即起始时间为0.0,终止时间为1.0,假如一个时间周期为 20(单位均为秒),则第6秒的归一化结果是0.3,第10秒的归一化 结果是0.5,第20秒的归一化结果是1.0。 JAVA3D里的Alpha类和VRML的key字段的功能类似,它也是用于 输出归一化的时间,不过它能够处理更加复杂的时间安排问题。 Alpha可以输出从0到1之间的数值给特定的内插对象,当Alpha 输出的数值为0时,对应的特定内插对象的值为最小;当Alpha输出 的数值为1时,对应的特定内插对象的值为最大;当Alpha输出的数 值为0到1之间的数值时,对应的特定内插对象生成和Alpha成相同 比例的数值。假设某一时刻Alpha输出的数值为0.2,则对应的特定 内插对象的当前值为最小值加上最大最小值之差乘以0.2。 (当前值-最小值)/(最大值-最小值)=0.2 JAVA3D里的各种Interpolator对象和VRML的内插节点的作用 比较类似,可用来旋转形体、移动形体的坐标、变化形体的颜色等。 假设我们要让一个形体在规定的时间内按照指定的方式运动, 我们首先要给出时间段的大小,还要指出时间是否要循环。这些内容 都是由Alpha类来完成的。 Alpha类的构造函数定义如下: public Alpha(int loopCount, int mode, long triggerTime, long phaseDelayDuration, long increasingAlphaDuration, long increasingAlphaRampDuration, long alphaAtOneDuration, long decreasingAlphaDuration, long decreasingAlphaRampDuration, long alphaAtZeroDuration) 我们在前面已多次用到Alpha类,基本上我们用它及一个旋转内 插器RotationInterpolator来使形体绕着其所在的局部坐标系不停 地旋转。下面是我们眼熟的语句,语句的作用是让形体以4秒为一周 期,不停地绕着某一个轴旋转(Y轴): Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, obj, temp, 0.0f, (float) Math.PI*2.0f); 从中我们可以看到,Alpha构造函数中: loopCount表示循环的次数,例如如果我们将前面介绍的Ex4_03.java 的loopCount设为10,则小丑会旋转10周,然后停止。不过在一些运行速度 慢的计算机上会出现少几次的情况,如作者本人使用的一台机器是 Pentium 586/100的计算机,当loopCount为10时,只看到小丑旋转了7次, 因为程序从开始运行到出现画面,需要一段时间。loopCount为-1时表示 无限循环。我们可以利用下面两个方法设置或获得loopCount: public void setLoopCount(int loopCount) public int getLoopCount() mode表示Alpha每一周期的运行方式,一共有三种:INCREASING_ENABLE、 DECREASING_ENABLE、INCREASING_ENABLE|DECREASING_ENABLE。第一种 方式表示Alpha的数值从0到1,相对应的内插对象的数值从最小到 最大;第二种方式表示Alpah的数值从1到0,相对应的内插对象的数值 从最大到最小;第三种方式表示Alpah的数值从0到1,然后从1到0, 相对应的内插对象的数值从最小到最大,然后又从最大到最小。 我们前面用到的Alpha,它每一个周期的数值,都是从0到1,对应的内插 对象的数值,在每一个循环周期里,都是从最小到最大。我们可以 利用下面两个方法,设置或获得mode: public void setMode(int Mode) public int getMode() triggerTime表示Alpha起作用的时间,它可由外部来触发,它和后面 的7个参数的单位均为毫秒。 triggerTime参数后面还有7个类型为long的数,我们可以设置 这些数值,来达到我们的各种编程目的。 前面我们介绍了VRML中各内插器节点key字段的作用,在VRML中, key的值只能从0到1。而在JAVA3D中,Alpha输出的值不仅可以从0到1, 还可以从1到0,甚至可以先从0到1,再从1到0。 VRML程序中各内插器节点的keyValue字段则根据key给定的数值, 输出相应的数值,计算机在keyValue各个数之间进行线性插值。而 JAVA3D的Alpha则不仅可以对各内插对象的数值进行线性插值,而且 可以利用increasingAlphaRampDuration、decreasingAlphaRampDuration 这两个参数进行非线性插值,插值曲线可以从SUN公司所提供的JAVA3D的 API中看出,这时又分两种情况:Ramp大于1/2、Ramp小于1/2。 接下来我们将通过多个JAVA3D动画程序的编制,介绍Alpha的各个参数。 JAVA3D动画编程时经常使用的10个内插器对象,它们分别是: PositionInterpolator RotationInterpolator ColorInterpolator ScaleInterpolator SwitchValueInterpolator TransparencyInterpolator PositionPathInterpolator RotPosPathInterpolator RotPosScalePathInterpolator RotationPathInterpolator 二. PositionInterpolator对象 为了编写一个彩色立方体在空间的运动,我们用到了JAVA3D所提供 的PositionInterpolator对象。 PositionInterpolator对象的定义如下: public PositionInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfTranslation, float startPosition, float endPosition) 利用这个对象,我们可以在给定的时间内,使某一个局部坐标系 在两个点之间按照Alpha提供的方式移动位置,它的作用类似于VRML 的PositionInterpolator节点,两者的名字完全一样。 PositionInterpolator对象也有多个方法,用于参数的设定,如: public void setStartPosition(float position) public float getStartPosition() public void setEndPosition(float position) public float getEndPosition() public void setTarget(TransformGroup target) public TransformGroup getTarget() public void setAxisOfTranslation(Transform3D axis) public Transform3D getAxisOfTranslation() public void processStimulus(Enumeration criteria) 我们先编写一个VRML程序,使一个形体沿着X轴线左右移动,其实, 形体并没有移动,移动的只是形体所在的局部坐标系,源程序Pos.wrl 如下,注意,它的观察点坐标位于(0 ,0 , 10),左右移动一周的时间 为20秒,左右移动的范围是(-4 , 0 , 0 )到( 4 , 0 , 0): #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{material Material{diffuseColor 1 0 0}} geometry Box{} } } Background{skyColor 1 1 1} DEF TS TimeSensor{ loop TRUE cycleInterval 20} DEF PI PositionInterpolator{ key [ 0 .5 1] keyValue[-4 0 0, 4 0 0 ,-4 0 0] } ROUTE TS.fraction TO PI.fraction ROUTE PI.value TO T.translation #end of Pos.wrl -------------------------------------------------------- 我们再利用PositionInterpolator对象编写类似的JAVA3D应用程序, 同样,Pos.java的观察点坐标也位于(0 , 0 , 10 ): //Pos.java import com.sun.j3d.utils.geometry.ColorCube; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Pos extends Applet { private BranchGroup createSceneGraph( ) { BranchGroup objRoot = new BranchGroup(); BoundingSphere bound=new BoundingSphere( new Point3d(0.0,0.0,0.0),50.); Transform3D tr=new Transform3D(); TransformGroup group=new TransformGroup(tr); group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); group.addChild(new ColorCube()); Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0,10000, 0, 0,10000, 0, 0); PositionInterpolator tran = new PositionInterpolator(xtranAlpha, group, tr, -4.f,4.f); tran.setSchedulingBounds(bound); group.addChild(tran); Color3f bgColor = new Color3f(1.0f, 1.0f, 1.0f); Background bg = new Background(bgColor); bg.setApplicationBounds(bound); objRoot.addChild(bg); objRoot.addChild(group); return objRoot; } public Pos() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); ViewPlatform viewPlatform; Viewer viewer = new Viewer(c); Vector3d viewpoint = new Vector3d(0.0, 0.0, 10.0); //初始观察点位置 Transform3D t = new Transform3D(); t.set(viewpoint); ViewingPlatform v = new ViewingPlatform( ); v.getViewPlatformTransform().setTransform(t); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse( v, viewer); u.getViewingPlatform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Pos(), 400,400); } } //end of Pos.java 运行Pos.java后我们发现,JAVA3D、VRML程序运行效果基本一致。 1. PositionInterpolator对象里的参数 我们来看一下Pos.java里定义的PositionInterpolator对象实例 tran里的各个参数。 xtranAlpha表示局部坐标系的变化方式是由xtranAlpha这个Alpha 定义的。 group给出了受影响的局部坐标系的名称。 tr给出了PositionInterpolator运动变化的方向,缺省时为沿X轴。 -4.f,4.f给出了局部坐标系移动的范围,表示坐标系的原点在 (-4 , 0 , 0 ) 和 ( 4 , 0 , 0 )之间移动。 2. xtranAlpha里各参数的含义 -1表示无限循环 Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE表示在一个 周期里面,局部坐标系统的位置从(-4, 0 , 0)移到(4 , 0 , 0),再从 (4 , 0 , 0)回到(-4 , 0 , 0),即从最小值到最大值,再从最大值到 最小值。 头一个10000表示局部坐标系从最小值移到最大值所用的时间,为 10秒。 第二个10000表示局部坐标系从最大值移到最小值所用的时间,也 为10秒,因而一个周期的时间为20秒。 3. 坐标轴的改变。 当然,我们可以改变局部坐标系移动的坐标轴,例如,当我们想 让局部坐标系沿着Y轴移动时,我们就可以在 Transform3D tr=new Transform3D(); 后面加上一句: tr.rotZ(Math.PI/2) ; 如果我们加的是: tr.rotY(Math.PI/2) ; 则形体沿着Z轴移动。 后面我们在详细介绍Transform3D时还将详细介绍坐标系的变换 方法。 三. Alpha构造函数后7个参数的含义 我们再次给出Alpha类的构造函数: public Alpha(int loopCount, int mode, long triggerTime, long phaseDelayDuration, long increasingAlphaDuration, long increasingAlphaRampDuration, long alphaAtOneDuration, long decreasingAlphaDuration, long decreasingAlphaRampDuration, long alphaAtZeroDuration) Alpha构造函数里的头三个参数我们已经介绍过了,我们在这里介绍 它的后7个参数,它们用于定义各内插对象的周期变化方式。 Alpha将每一个周期分外5个时段: 起始延迟时段 上升时段 高位时段 下降时段 低位时段 ------ / \ / \ / \ ------- ------- 每个周期的时间长度为这5个时段时间长度之和。 每一个Alpha都必须给出这5个时段,当然,其中的任何数都可以为0, 因而我们可以获得各种各样的Alpha类型。下面我们给出部分类型: 1. 只有上升时段的类型 / / / / / / / / / / / / 这种类型的Alpha输出的数值从最小升到最大,然后又从最小升到最大。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,20000, 0, 0,0, 0, 0); 它使形体从左移到右,再将形体跳回到左边。 2. 只有下降时段的类型 \ \ \ \ \ \ \ \ \ \ \ \ 这种类型的Alpha输出的数值从最大降到最小,然后又从最大降到最小。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE, 0, 0,0, 0, 0,20000, 0, 0); 它使形体从右移到左,再将形体跳回到右边。 3. 上升加高位时段的类型 --- --- / / / / / / / / 这种类型的Alpha输出的数值从最小升到最大,暂停一段时间, 然后又从最小升到最大。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,10000, 0, 10000, 0,0, 0); 它使形体从左移到右,暂停一段时间,再将形体跳回到左边。 4. 下降加低位时段 \ \ \ \ \ \ ---- ---- 这种类型的Alpha输出的数值从最大降到最小,暂停一段时间, 然后又从最大降到最小。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE, 0, 0,0, 0, 0, 10000,0, 10000); 它使形体从右移到左,再将形体跳回到右边。 5. 暂停、上升加高位时段的类型 ---- / / / / ---- 这种类型的Alpha输出的数值一开始先暂停,然后从最小升到最 大,再暂停一段时间。不过要注意的是,这种类型不能用于 循环方式。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(1, Alpha.INCREASING_ENABLE, 0, 5000,10000, 0, 5000, 0,0, 0); 它使形体暂停一段时间,从左移到右,再暂停一段时间。 6. 暂停、下降加暂停时段的类型 ---- \ \ \ ------ 这种类型的Alpha输出的数值一开始先暂停,然后从最大升到最 小,再暂停一段时间。不过要注意的是,这种类型也不能用于 循环方式。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(1, Alpha.DECREASING_ENABLE, 0, 0,0, 0, 5000, 10000,0, 5000); 它使形体暂停一段时间,从右移到左,再暂停一段时间。 7. 5种时段均有的类型 ----- / \ / \ / \ ----- ----- 此种类型的Alpha输出的数值一开始先暂停,然后从最小升到 最大,再暂停一段时间,然后下降到最小,最后再暂停一段时间。 不过要注意的是,这种类型也不能用于循环方式。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(1, Alpha.DECREASING_ENABLE|Alpha.INCREASING_ENABLE, 0, 3000,5000, 0, 3000, 5000,0, 3000); 8. 上升、暂停、下降、暂停类型 ---- ---- / \ / \ / \ / \ / \------/ \----- 本类型和第7种很相似,但没有上升前的暂停阶段,因而可以 用于循环方式。 我们将前面的Pos.java改成这种类型时,生成的Alpha应为: Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE|Alpha.INCREASING_ENABLE, 0, 0,5000, 0, 5000, 5000,0, 5000); 9. Alpha的加速 前面介绍的8种类型,可以用于各种场合,如开关门等。但它们 均有一个问题,即形体从静止到运动的变化是跳跃性的,变化时的 加速度为无穷大。为此,JAVA3D还提供了两个参数,解决这个问题, 这就是Alpha里的increasingAlphaRampDuration和 decreasingAlphaRampDuration,它们有两种应用方式:一是设置为 大于或等于0.5,一是设置为小于0.5。 当它们的值为第一种情况时,计算机自动将其转成0.5,使Alpha 产生的加速度在头一半时间是均匀加速的,在后一半时间里是均匀 减速的,因而在头一半时间里,加速度是正数,在后一半时间里, 加速度是相同的负数(请参考JAVA3D的API说明)。 第一种情况在某一时段的速度图: /\ / \ / \ / \ 下面我们给出这样一个Alpha的例子: Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE|Alpha.INCREASING_ENABLE, 0, 0,5000, (long)0.5, 5000, 5000,(long)0.5, 5000); 当这两个数小于0.5时,Alpha只在时间段的两头产生加速度, 中间的加速度为0,因而中间的速度保持不变。 下面我们给出这样一个Alpha的例子: Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE|Alpha.INCREASING_ENABLE, 0, 0,5000, (long)0.2, 5000, 5000,(long)0.5, 5000); 第二种情况在某一时段的速度图: -------- / \ / \ / \ m 发信人: screamer (Screamer), 信区: Cad 标 题: Java3D学习系列(十七)(转载) 发信站: 飘渺水云间 (Sun May 2 18:33:40 1999), 转信 JAVA3D学习系列(16)--动画的生成(中) 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 上一讲我们已经介绍了一个JAVA3D的内插对象: PositionInterpolator。本讲我们将继续介绍其它的 内插对象。 一. RotationInterpolator对象 RotationInterpolator的构造函数有两个: public RotationInterpolator(Alpha alpha, TransformGroup target) public RotationInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfRotation, float minimumAngle, float maximumAngle) RotationInterpolator的方法有: public void setMinimumAngle(float angle) public float getMinimumAngle() public void setMaximumAngle(float angle) public float getMaximumAngle() public void setAxisOfRotation(Transform3D axis) public Transform3D getAxisOfRotation() public void setTarget(TransformGroup target) public TransformGroup getTarget() public void processStimulus(Enumeration criteria) 利用这个对象,我们可以在给定的时间内,使某一个局部坐标系 在按照Alpha提供的方式绕着某一个轴旋转,它的作用类似于VRML 的OrientationInterpolator节点。 RotationInterpolator的前三个参数和我们上一讲介绍的 PositionInterpolator对象的前三个参数概念一样: Alpha为我们提供了旋转方式。 target为我们提供了需要旋转的局部坐标系。 axisOfRotation确定了旋转轴的方位。 1. 第一个构造函数的运行结果 假如我们利用的是第一个构造函数,我们所获得的最大角度为 2*PI,最小角度为0,坐标系绕着Y轴,按照Alpha给出的旋转方式 旋转。 2. 第二个构造函数的运行结果 我们来看一下OrientationInterpolator第二个构造函数的后两 个参数,它们给出了旋转的最大最小的角度。 下面的程序Rot.java利用了RotationInterpolator对象,使一个 立方体绕着自己的Y轴不停地旋转:先正转180度。停顿几秒后,又反 转180度,再停顿几秒钟。 //Rot.java import com.sun.j3d.utils.geometry.ColorCube; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Rot extends Applet { private BranchGroup createSceneGraph( ) { float min = 0.0f; float max = (float) Math.PI; BranchGroup objRoot = new BranchGroup(); BoundingSphere bound=new BoundingSphere( new Point3d(0.0,0.0,0.0),50.); Transform3D tr=new Transform3D(); TransformGroup group=new TransformGroup(tr); group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); group.addChild(new ColorCube()); Alpha xtranAlpha = new Alpha(-1, Alpha.DECREASING_ENABLE|Alpha.INCREASING_ENABLE, 0, 0,5000, (long)0.5, 5000, 5000,(long)0.5, 5000); RotationInterpolator tran = new RotationInterpolator(xtranAlpha, group, tr, min,max); tran.setSchedulingBounds(bound); group.addChild(tran); Color3f bgColor = new Color3f(1.0f, 1.0f, 1.0f); Background bg = new Background(bgColor); bg.setApplicationBounds(bound); objRoot.addChild(bg); objRoot.addChild(group); return objRoot; } public Rot() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); ViewPlatform viewPlatform; Viewer viewer = new Viewer(c); Vector3d viewpoint = new Vector3d(0.0, 0.0, 10.0); //初始观察点位置 Transform3D t = new Transform3D(); t.set(viewpoint); ViewingPlatform v = new ViewingPlatform( ); v.getViewPlatformTransform().setTransform(t); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse( v, viewer); u.getViewingPlatform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Rot(), 400,400); } } //end of Rot.java 我们给出相应的VRML语言编写出的程序,由VRML程序的 运行结果可以看出,VRML程序无法使形体的速度渐变,而只 能突变,因而JAVA3D在这一方面功能较强。 #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{material Material{diffuseColor 1 0 .5}} geometry Box{}} } DEF TS TimeSensor{ loop TRUE cycleInterval 20} DEF OI OrientationInterpolator{ key [ 0 .25 .5 .75 1] keyValue[0 1 0 0 ,0 1 0 3.14,0 1 0 3.14, 0 1 0 0, 0 1 0 0] } ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation #end of Rot.wrl 如果我们在JAVA3D程序的 Transform3D tr=new Transform3D(); 后面加上一句: tr.rotZ(Math.PI/2) ; 则形体从绕着Y轴旋转改为绕着X轴旋转。 二. ColorInterpolator对象 ColorInterpolator的构造函数也有两个: public ColorInterpolator(Alpha alpha, Material target) public ColorInterpolator(Alpha alpha, Material target, Color3f startColor, color3f endColor) ColorInterpolator的方法有: public void setStartColor(Color3f color) public void getStartColor(Color3f color) public void setEndColor(Color3f color) public void getEndColor(Color3f color) public void setTarget(Material target) public Material getTarget() public void processStimulus(Enumeration criteria) 利用这个对象,我们可以在给定的时间内,使某一个Material 对象的漫反射光DiffuseColor发生变化。按照Alpha提供的方式变化, 它的作用类似于VRML的ColorInterpolator节点,两者的名字完全一样。 1. 第一个构造函数的运行结果 如果我们采用的是第一个构造函数,则startColor为黑色, endColor为白色。本人利用此方法编写了几个程序,发现形体的 颜色难以控制,因而建议大家少使用这个方法。 2. 第二个构造函数的运行结果 采用第二个构造函数时,我们需要设定startColor和endColor 这两个颜色。不过要注意,为了使Material对象的DiffuseColor 产生变化的效果,我们应在空间增加一个对着形体照射的光线, 否则形体显示的依旧是辐射光EmissiveColor。 但我们经过多次实验,发现ColorInterpolator对象产生的 效果不是我们所预期的效果,例如,如果我们想使形体的 diffuseColor从颜色a变到颜色b,显示的结果却是形体的 emissiveColor到diffuseColor的变化。程序如下: //Color.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.*; import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; public class Color extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); objRoot.addChild(createObject()); Color3f bgColor = new Color3f(1.0f, 1.0f, 1.0f); BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0); Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); objRoot.addChild(bg); Color3f light1Color = new Color3f(1.0f, 1.0f, 1.0f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); objRoot.compile(); return objRoot; } private Group createObject() { Transform3D t = new Transform3D(); TransformGroup objTrans = new TransformGroup(t); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Appearance ap=new Appearance(); ap.setCapability(Appearance.ALLOW_MATERIAL_WRITE); ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); Material mat = new Material( ); mat.setCapability(Material.ALLOW_COMPONENT_WRITE); Color3f emissive = new Color3f(0.0f, 1.0f, 0.0f); Color3f diffuse = new Color3f(0.0f, 0.0f, 1.0f); mat.setEmissiveColor(emissive); mat.setDiffuseColor(diffuse); ap.setMaterial(mat); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); ap.setPolygonAttributes(pa); ColoringAttributes ca = new ColoringAttributes( ); ca.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE); ap.setColoringAttributes( ca); Alpha alpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0, 8000, 0, 0, 8000, 0, 0); ColorInterpolator ci = new ColorInterpolator(alpha, mat, new Color3f(1.0f,0.0f, 1.0f), new Color3f(0.0f, 0.0f, 1.0 f)); BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0); ci.setSchedulingBounds(bounds); Shape3D shape = new myShape(); shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); shape.setAppearance(ap); objTrans.addChild(shape); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); return objTrans; } public Color() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Color(), 540,361); } } //end of Color.java ---------------------- //myShape.java import javax.media.j3d.*; import javax.vecmath.*; public class myShape extends Shape3D { private float vert[] = { -.3f,-.3f,0.0f, -.3f,.3f,0.0f, -.1f,-.3f,0.0f, -.1f,.3f,0.0f, .1f,-.3f,0.0f, .1f,.3f,0.0f, .3f,-.3f,0.0f, .3f,.3f,0.0f, .4f,.4f,0.0f, }; public myShape() { int i, face; TriangleArray shape = new TriangleArray(9, TriangleArray.COORDINATES|TriangleArray.NORMALS); shape.setCoordinates(0,vert); Vector3f normal = new Vector3f(); Vector3f v1 = new Vector3f(); Vector3f v2 = new Vector3f(); Point3f [] pts = new Point3f[3]; for (i=0;i<3;i++) pts[i] = new Point3f(); for(face =0; face<3; face++) { shape.getCoordinates(face*3,pts); v1.sub(pts[1],pts[0]); v2.sub(pts[2],pts[0]); normal.cross(v1,v2); normal.normalize(); for (i=0;i<3;i++) { shape.setNormal((face*3+i), normal); } } this.setGeometry(shape); } } //end of myShape.java 我们给出程序对应的VRML程序color.wrl #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{ material DEF M Material{diffuseColor 0 1 0}} geometry IndexedFaceSet{ coord Coordinate{point [-0.3 -0.3 0,-0.3 0.3 0, -0.1 -0.3 0,-0.1 0.3 0, 0.1 -0.3 0, 0.1 0.3 0, 0.3 -0.3 0, 0.3 0.3 0, 0.4 0.4 0]} coordIndex[0 3 1 -1, 2 5 4 -1, 6 8 7] solid FALSE } } } DEF TS TimeSensor{ loop TRUE cycleInterval 8} DEF CI ColorInterpolator{ key[0 .5 1] keyValue[ 0 1 0, 0 0 1 , 0 1 0] } DEF OI OrientationInterpolator{ key[0 .5 1] keyValue[ 0 1 0 0 , 0 1 0 3.14, 0 1 0 6.28] } Viewpoint { position 0 .3 1 orientation 1 0 0 -.3} Background{skyColor 1 1 1} ROUTE TS.fraction TO CI.fraction ROUTE TS.fraction TO OI.fraction ROUTE CI.value TO M.diffuseColor ROUTE OI.value TO T.rotation #end of color.wrl 三. ScaleInterpolator对象 ScaleInterpolator对象的构造函数有两个: public ScaleInterpolator(Alpha alpha, TransformGroup target) public ScaleInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfScale, float minimumScale, float maximumScale) ScaleInterpolator的方法有: public void setMinimumScale(float scale) public float getMinimumScale() public void setMaximumScale(float scale) public float getMaximumScale() public void setAxisOfScale(Transform3D axis) public Transform3D getAxisOfScale() public void setTarget(TransformGroup target) public TransformGroup getTarget() public void processStimulus(Enumeration criteria) public void updateNodeReferences(NodeReferenceTable referenceTable) 利用这个对象,我们可以在给定的时间内,使某一个局部坐标系 的各个方向按照Alpha提供的方式进行比例变化,它的作用在VRML 程序中可以用PositionInterpolator来代替。 ScaleInterpolator的第一个构造函数为我们提供了缺省的比例数 值,最大为1.0f,最小为0.1f。下面的程序利用第一个构造函数使一 个立方体在一定的时间内按照Alpha给出的变化方式在各个方向上产生 了相同的比例变化,为了比较,我们还给出了相应的VRML语言编写的程序。 //Scale1.java import java.applet.Applet; import java.awt.BorderLayout; import java.awt.event.*; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Scale1 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Transform3D tran3d=new Transform3D(); tran3d.rotX(0.4); TransformGroup objTrans = new TransformGroup(tran3d); objRoot.addChild(objTrans); Transform3D t =new Transform3D(); t.rotX(0.4); TransformGroup obj = new TransformGroup(t); objTrans.addChild(obj); obj.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); obj.addChild(new ColorCube(0.4)); Alpha scaleAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0, 4000, 0, 0, 4000, 0, 0); ScaleInterpolator scale = new ScaleInterpolator(scaleAlpha, obj); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); scale.setSchedulingBounds(bounds); obj.addChild(scale); objRoot.compile(); return objRoot; } public Scale1() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Scale1(),400,400); } } //end of Scale1.java ----------------------Scale1.wrl---------- #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{material Material{diffuseColor 1 0 .5}} geometry Box{}} } DEF TS TimeSensor{ loop TRUE cycleInterval 8} EF PI PositionInterpolator{ key [ 0 .5 1] keyValue[1 1 1, 0.1 0.1 0.1 1 1 1] } ROUTE TS.fraction TO PI.fraction ROUTE PI.value TO T.scale #end of Scale1.wrl ScaleInterpolator的第二个构造函数允许我们设置最大及最小 的比例数值。我们利用它编写了下面的这个程序,利用它,可以设 置我们所需要的比例数值。 //Scale2.java import java.applet.Applet; import java.awt.BorderLayout; import java.awt.event.*; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Scale2 extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Transform3D tran3d=new Transform3D(); tran3d.rotX(0.4); TransformGroup objTrans = new TransformGroup(tran3d); objRoot.addChild(objTrans); Transform3D t =new Transform3D(); t.rotX(0.4); TransformGroup obj = new TransformGroup(t); objTrans.addChild(obj); obj.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); obj.addChild(new ColorCube(0.4)); Alpha scaleAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0, 4000, 0, 0, 4000, 0, 0); ScaleInterpolator scale = new ScaleInterpolator(scaleAlpha, obj,t,1.0f,0.4f); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); scale.setSchedulingBounds(bounds); obj.addChild(scale); objRoot.compile(); return objRoot; } public Scale2() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Scale2(),400,400); } } //end of Scale2.java 四. SwitchValueInterpolator SwitchValueInterpolator对象的构造函数有两个: public SwitchValueInterpolator(Alpha alpha, Switch target) public SwitchValueInterpolator(Alpha alpha, Switch target, int firstChildIndex, int lastChildIndex) SwitchValueInterpolator的方法有: public void setFirstChildIndex(int firstIndex) public int getFirstChildIndex() public void setLastChildIndex(int lastIndex) public int getLastChildIndex() public void setTarget(Switch target) public Switch getTarget() public void processStimulus(Enumeration criteria) 利用这个对象,我们可以在屏幕上在不同的时间分别显示 不同的形体。例如下面程序里,计算机按循环显示形体,每一个 周期显示的内容为:大立方体--球--圆锥--小立方体--圆锥--球。 当然,当我们采用第一个构造函数时,结果和本程序一样。 当我们将程序中的: SwitchValueInterpolator sv = new SwitchValueInterpolator(scaleAlpha, s,0,4); 改为: SwitchValueInterpolator sv = new SwitchValueInterpolator(scaleAlpha, s,0,3); 时,每一个周期显示的内容为:大立方体--球--圆锥--球,由此看 来,第四个形体没有显示出来。 //mySwitch.java import java.applet.Applet; import java.awt.BorderLayout; import java.awt.event.*; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class mySwitch extends Applet { public BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); Transform3D tran3d=new Transform3D(); tran3d.rotX(0.4); TransformGroup objTrans = new TransformGroup(tran3d); objRoot.addChild(objTrans); Transform3D t =new Transform3D(); t.rotX(0.4); TransformGroup obj = new TransformGroup(t); Switch s = new Switch( ); s.addChild(new ColorCube(0.4)); s.addChild(new Sphere( )); s.addChild(new Cone( )); s.addChild(new ColorCube(0.2)); s.setCapability(Switch.ALLOW_SWITCH_WRITE); objTrans.addChild(obj); obj.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); obj.addChild(s); Alpha scaleAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0, 4000, 0, 4000, 4000, 0, 4000); SwitchValueInterpolator sv = new SwitchValueInterpolator(scaleAlpha, s,0,4); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); sv.setSchedulingBounds(bounds); obj.addChild(sv); Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); objRoot.addChild(light1); objRoot.compile(); return objRoot; } public mySwitch() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new mySwitch(),400,400); } } //end of mySwitch.java 发信人: screamer (Screamer), 信区: Cad 标 题: Java学习系列(十八)(转载) 发信站: 飘渺水云间 (Thu May 6 21:06:31 1999), 转信 JAVA3D学习系列(17)--动画的生成(下) 汕头大学机电系 张杰(jzhang@mailserv.stu.edu.cn) 一. TransparnecyInterpolator对象 TransparencyInterpolator对象的构造函数有两个: public TransparencyInterpolator(Alpha alpha, TransparencyAttributes target) public TransparencyInterpolator(Alpha alpha, TransparencyAttributes target, float minimumTransparency, float maximumTransparency) 它的方法有: public void setMinimumTransparency(float transparency) public float getMinimumTransparency() public void setMaximumTransparency(float transparency) public float getMaximumTransparency() public void setTarget(TransparencyAttributes target) public TransparencyAttributes getTarget() public void processStimulus(Enumeration criteria) 利用这个对象,我们可以在给定的时间内,使某一个形体的透明度 按照Alpha提供的方式在两个数值之间变化,VRML语言中我们可以用 ScalarInterpolator节点来实现同样的效果。 如果我们使用的是第一个构造函数,则透明度的最大值为1.0f, 最小值为0.0f。 下面是一个应用此方法的JAVA3D程序和一个相对应的VRML程序。 为了看出透明的效果,我们设定背景为白色。 //Tra.java import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.*; import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; public class Tra extends Applet { private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); objRoot.addChild(createObject()); BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0 ); Background bg=new Background(new Color3f(1.0f,1.0f,1.0f)); bg.setApplicationBounds(bounds); objRoot.addChild(bg); objRoot.compile(); return objRoot; } private Group createObject() { Transform3D t = new Transform3D(); TransformGroup objTrans = new TransformGroup(t); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Appearance ap=new Appearance(); Color3f ambient=new Color3f(1.0f,0.0f,0.0f); Color3f emissive = new Color3f(0.8f,0.2f,0.2f); Color3f diffuse=new Color3f(1.f,1.f,0.f); Color3f specular = new Color3f(1.0f,1.0f,1.0f); ap.setMaterial(new Material(ambient,emissive,diffuse,specular,100.0f)); PolygonAttributes pa = new PolygonAttributes(); pa.setCullFace(PolygonAttributes.CULL_NONE); ap.setPolygonAttributes(pa); TransparencyAttributes ta=new TransparencyAttributes(); ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); ta.setTransparencyMode(ta.BLENDED); ta.setTransparency(.0f); ap.setTransparencyAttributes(ta); Alpha alpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0, 8000, 0, 0, 8000, 0, 0); TransparencyInterpolator transparency= new TransparencyInterpolator(alpha,ta,.0f,1.f); BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0 ); transparency.setSchedulingBounds(bounds); Shape3D shape = new myShape(); shape.setAppearance(ap); objTrans.addChild(shape); objTrans.addChild(transparency); Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); return objTrans; } public Tra() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Tra(), 540,361); } } //end of Tra.java --------- #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{material DEF M Material{diffuseColor 0 1 0}} geometry IndexedFaceSet{ coord Coordinate{point [-0.3 -0.3 0,-0.3 0.3 0, -0.1 -0.3 0,-0.1 0.3 0, 0.1 -0.3 0, 0.1 0.3 0, 0.3 -0.3 0, 0.3 0.3 0, 0.4 0.4 0]} coordIndex[0 3 1 -1, 2 5 4 -1, 6 8 7] solid FALSE } } } DEF TS TimeSensor{ loop TRUE cycleInterval 8} DEF SI ScalarInterpolator{ key[0 .5 1] keyValue[ 1, 0, 1] } DEF OI OrientationInterpolator{ key[0 .5 1] keyValue[ 0 1 0 0 , 0 1 0 3.14, 0 1 0 6.28] } Viewpoint { position 0 .3 1 orientation 1 0 0 -.3} Background{skyColor 1 1 1} ROUTE TS.fraction TO SI.fraction ROUTE TS.fraction TO OI.fraction ROUTE SI.value TO M.transparency ROUTE OI.value TO T.rotation #end of tra.wrl 二. PathInterpolator对象 我们在后面将要介绍下面这些对象: PositionPathInterpolator RotPosPathInterpolator RotPosScalePathInterpolator RotationPathInterpolator 它们都是PathInterpolator的子类。为此,我们先介绍一下 PathInterpolator对象的作用。 PathInterpolator是Interpolator类的子类,就好象我们 上面介绍的所有的内插对象是Interpolator类的子类一样。 PathInterpolator的子类能够借助于父类的下面的这个方法: computePathInterpolation() 来完成所需要的计算。 PathInterpolator还有以下几个方法: getArrayLengths() public void setKnot(int index, float knot) public float getKnot(int index) 三. PositionPathInterpolator对象 PositionPathInterpolator对象的构造函数为: public PositionPathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfTranslation, float knots[], Point3f positions[]) 它的方法有: public void setPosition(int index, Point3f position) public void getPosition(int index, Point3f position) public void setAxisOfTranslation(Transform3D axis) public Transform3D getAxisOfTranslation() public void setTarget(TransformGroup target) public TransformGroup getTarget() public void processStimulus(Enumeration criteria) 利用这个对象,我们可以对某一个局部坐标系按照指定的路径、 指定的运动方式进行坐标系的移动。 positions[]给出了指定的路径。 knots[]、alpha给出了指定的运动方式。 下面我们利用这个对象编写一个使某个立方体按指定路径,按 指定运动方式的位移运动。 由程序我们得知,立方体围绕着由pos[]定义的一个长方形平移。 轨迹的第一个点和最后一个点重合。在从第一个点到最后一个点运动 过程中,每一个点都对应一个knot值,第一个knot值为0.0f,最后一 个knot值为1.0f,knot值必须从小到大排列,它用来给各个点分配由 Alpha对象定义的上升时间段和下降时间段。每一个点的时间可以由 对应的knot的数值算出。 运行JAVA3D程序,我们会看到立方体绕着一个长方形的四个 顶点旋转。如果我们将程序中的xtranAlpha改写成下面的内容: Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0,10000, 0, 2000, 10000, 0, 2000); 则每一个循环的运行结果为:立方体先顺时针转一圈(10秒), 暂停2秒,再逆时针旋转一圈(10秒),再暂停2秒。 我们可以用VRML语言编写同样的处理程序,这时我们应用的节点 是PositionInterpolator。由此可以得知,JAVA3D程序中的knot对应 于VRML程序中PositionInterpolator节点的key字段,而pos对应于 VRML程序中PositionInterpolator节点的keyValue字段。因而我们同时 编写了一个VRML程序。 //Pos.java import com.sun.j3d.utils.geometry.ColorCube; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Pos extends Applet { float knot[] = {0.0f,0.25f,0.5f,0.75f,1.0f}; Point3f pos[] = { new Point3f(-.8f,-.6f,0.0f), new Point3f(-.8f,.6f, 0.0f), new Point3f(.8f, .6f, 0.0f), new Point3f(.8f, -.6f,0.0f), new Point3f(-.8f,-.6f,0.0f), }; private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objTran=new TransformGroup(); objTran.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Transform3D t3d=new Transform3D(); t3d.setScale(.3); objTran.setTransform(t3d); objRoot.addChild(objTran); BoundingSphere bound=new BoundingSphere( new Point3d(0.0,0.0,0.0),50.); Transform3D tr=new Transform3D(); TransformGroup translation=new TransformGroup(tr); translation.addChild(new ColorCube(.2)); objTran.addChild(translation); translation.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,10000, 0, 0, 0, 0, 0); PositionPathInterpolator tran = new PositionPathInterpolator(xtranAlpha, translation, tr, knot,pos); tran.setSchedulingBounds(bound); translation.addChild(tran); return objRoot; } public Pos() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Pos(), 640,480); } } //end of Pos.java ------------------------------ #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{ material Material{diffuseColor 1 0 0}} geometry Box{}}} DEF TS TimeSensor{ loop TRUE cycleInterval 10} DEF PI PositionInterpolator{ key[0 .25 .5 .75 1] keyValue[-.8 -.6 0 , -.8 .6 0, .8 .6 0, .8 -.6 0, -.8 -.6 0]} ROUTE TS.fraction TO PI.fraction ROUTE PI.value TO T.translation Background{skyColor 1 1 1} Viewpoint{ position 0 2 8 orientation 1 0 0 -.3} #end of Pos.wrl 四. RotPosPathInterpolator对象 RotPosPathInterpolator对象的构造函数为: public RotPosPathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfRotPos, float knots[], Quat4f quats[], Point3f positions[]) 它的方法有: public void setQuat(int index, Quat4f quat) public void getQuat(int index, Quat4f quat) public void setPosition(int index, Point3f position) public void getPosition(int index, Point3f position) public void setAxisOfRotPos(Transform3D axisOfRotPos) public Transform3D getAxisOfRotPos() public void setTarget(TransformGroup target) public TransformGroup getTarget() public void processStimulus(Enumeration criteria) 我们上面介绍的PositionPathInterpolator对象可以 使形体按指定的路径平移,而利用RotPosPathInterpolator 对象则可以在实现平移运动的同时使形体按指定的方式绕特 定的轴旋转。例如下面的程序就是在Pos.java程序的基础之 上加了一个Quat4f数组,用来定义形体的旋转方式。使形体 在每一个knots数值之下都有一个旋转角度相对应。程序的其 它地方没有变化。 立方体在顺时针或反时针移动时,都要绕着自身先正转 90度,再反转90度。 RotPosPathInterpolator对象可以由下面两个对象代替: PositionPathInterpolator RotationInterpolator //Rot.java import com.sun.j3d.utils.geometry.ColorCube; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Rot extends Applet { float knot[] = {0.0f,0.25f,0.5f,0.75f,1.0f}; Point3f pos[] = { new Point3f(-.8f,-.6f,0.0f), new Point3f(-.8f,.6f, 0.0f), new Point3f(.8f, .6f, 0.0f), new Point3f(.8f, -.6f,0.0f), new Point3f(-.8f,-.6f,0.0f), }; Quat4f quat[ ] = { new Quat4f( 0.0f ,1.0f ,0.0f ,0.0f), new Quat4f(0.0f ,1.0f ,0.0f ,0.78f ), new Quat4f(0.0f ,1.0f, 0.0f , 1.57f ), new Quat4f(0.0f, 1.0f ,0.0f, 0.78f ), new Quat4f( 0.0f ,1.0f, 0.0f, 0.0f ) }; private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objTran=new TransformGroup(); objTran.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Transform3D t3d=new Transform3D(); t3d.setScale(.3); objTran.setTransform(t3d); objRoot.addChild(objTran); BoundingSphere bound=new BoundingSphere( new Point3d(0.0,0.0,0.0),50.); Transform3D tr=new Transform3D(); TransformGroup translation=new TransformGroup(tr); translation.addChild(new ColorCube(.2)); objTran.addChild(translation); translation.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0,10000, 0, 2000, 10000, 0, 2000); RotPosPathInterpolator tran = new RotPosPathInterpolator(xtranAlpha, translation, tr, knot,quat , pos); tran.setSchedulingBounds(bound); translation.addChild(tran); return objRoot; } public Rot() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Rot(), 640,480); } } //end of Rot.java 我们将Rot.java变成VRML程序Rot.wrl #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{ material Material{diffuseColor 1 0 0}} geometry Box{size .5 .5 .5}} } DEF TS TimeSensor{ loop TRUE cycleInterval 10} DEF PI PositionInterpolator{ key[0 .125 .25 .375 .5 .625 .75 .875 1] keyValue[-.8 -.6 0 , -.8 .6 0, .8 .6 0, .8 -.6 0, -.8 -.6 0 .8 -.6 0, .8 .6 0, -.8 .6 0 -.8 -.6 0]} DEF OI OrientationInterpolator{ key[0 .125 .25 .375 .5 .625 .75 .875 1] keyValue[0 1 0 0,0 1 0 .78,0 1 0 1.57, 0 1 0 0.78, 0 1 0 0, 0 1 0 0.78, 0 1 0 1.57, 0 1 0 0.78 0 1 0 0]} ROUTE TS.fraction TO PI.fraction ROUTE PI.value TO T.translation ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation Background{skyColor 1 1 1} Viewpoint{ position 0 2 8 orientation 1 0 0 -.3} # end of Rot.wrl 五. RotPosScalePathInterpolator对象 RotPosScalePathInterpolator对象的构造函数为: public RotPosScalePathInterpolator(Alpha alpha, TransformGroup target, Transform3D axisOfRotPosScale, float knots[], Quat4f quats[], Point3f positions[], float scales[]) 它的方法有: public void setScale(int index, float scale) public float getScale(int index) public void setQuat(int index, Quat4f quat) 前面我们已经介绍了一个RotationInterpolator对象,利用 它可以使形体按Alpha指定的方式绕着特定的轴旋转,旋转的速度 可以由Alpha的一些参数控制,但具体时间的角度无法控制。这时 我们就可以利用RotationPathInterpolator对象,利用quats数组, 控制具体时间的形体旋转角度。 下面的程序是由上面介绍的Sca.java程序经过一定的处理得来 的,没有增加什么,只是将用于位移及比例变化的部分去掉了。 //Rot2.java import com.sun.j3d.utils.geometry.ColorCube; import java.applet.Applet; import java.awt.BorderLayout; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; public class Rot2 extends Applet { float knot[] = {0.0f,0.25f,0.5f,0.75f,1.0f}; Quat4f quat[ ] = { new Quat4f( 0.0f ,1.0f ,0.0f ,0.0f), new Quat4f(0.0f ,1.0f ,0.0f ,0.78f ), new Quat4f(0.0f ,1.0f, 0.0f , 1.57f ), new Quat4f(0.0f, 1.0f ,0.0f, 0.78f ), new Quat4f( 0.0f ,1.0f, 0.0f, 0.0f )}; private BranchGroup createSceneGraph() { BranchGroup objRoot = new BranchGroup(); TransformGroup objTran=new TransformGroup(); objTran.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Transform3D t3d=new Transform3D(); t3d.setScale(.3); objTran.setTransform(t3d); objRoot.addChild(objTran); BoundingSphere bound=new BoundingSphere( new Point3d(0.0,0.0,0.0),50.); Transform3D tr=new Transform3D(); TransformGroup translation=new TransformGroup(tr); translation.addChild(new ColorCube(.2)); objTran.addChild(translation); translation.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Alpha xtranAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE, 0, 0,10000, 0, 2000, 10000, 0, 2000); RotationPathInterpolator tran = new RotationPathInterpolator(xtranAlpha, translation, tr, knot,quat); tran.setSchedulingBounds(bound); translation.addChild(tran); return objRoot; } public Rot2() { setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c); BranchGroup scene = createSceneGraph(); SimpleUniverse u = new SimpleUniverse(c); u.getViewingPlatform().setNominalViewingTransform(); u.addBranchGraph(scene); } public static void main(String[] args) { new MainFrame(new Rot2(), 640,480); } } //end of Rot2.java -------------------- 相应的VRML程序如下: #VRML V2.0 utf8 DEF T Transform{ children Shape{ appearance Appearance{ material Material{diffuseColor 1 0 0}} geometry Box{ }} } DEF TS TimeSensor{ loop TRUE cycleInterval 10} DEF OI OrientationInterpolator{ key[0 .125 .25 .375 .5 .625 .75 .875 1] keyValue[0 1 0 0,0 1 0 .78,0 1 0 1.57, 0 1 0 0.78, 0 1 0 0, 0 1 0 0.78, 0 1 0 1.57, 0 1 0 0.78 0 1 0 0]} Background{skyColor 1 1 1} Viewpoint{ position 0 2 8 orientation 1 0 0 -.3} ROUTE TS.fraction TO OI.fraction ROUTE OI.value TO T.rotation # end of Rot2.wrl
posted on 2007-06-19 13:37 托托姆 阅读(4571) 评论(2)  编辑  收藏

FeedBack:
# re: Java3D学习系列(转) 2008-08-01 15:00 mocake
希望你工作认真点!!
不要发这样的帖子!
ok  回复  更多评论
  
# re: Java3D学习系列(转) 2009-06-09 09:28 HAKLF
发那么多有用没有呀!能否有点主要点!!!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: