java3d编程简介(点线面的编程实例)

原文地址:http://blog.csdn.net/gaoyunpeng/article/details/1771473
本文重新整理格式、补充、删改,转载发布


 
  
 
  

一.JAVA3D的作用:

 JAVA3D可用在三维动画、三维游戏、机械CAD等领域。1.可以用来编写三维形体,但和VRML不同,JAVA3D没有基本形体,不过我们可以利用JAVA3D所带的UTILITY生成一些基本形体如立方体、球、圆锥等,我们也可以直接调用一些软件如ALIAS、LIGHTWARE、3DS MAX生成的形体,也可以直接调用VRML2.0生成的形体。2.可以和VRML一样,使形体带有颜色、贴图。3.可以产生形体的运动、变化,动态地改变观测点的位置及视角。4.可以具有交互作用,如点击形体时会使程序发出一个信号从而产生一定的变化。5.可以充分利用JAVA语言的强大功能,编写出复杂的三维应用程序。6.JAVA3D具有VRML所没有的形体碰撞检查功能(这也是本人目前中意JAVA3D的原因)。 
    
  
 
  

二.OPENGL、VRML、DIRECT3D、JAVA3D的比较

由于OPENGL的跨平台特性,许多人利用OPENGL编写三维应用程序,不过对于一个非计算专业的人员来说,利用OPENGL编写出复杂的三维应用程序是比较困难的,且不说C(C++)语言的掌握需要花费大量时间精力,当我们需要处理复杂问题的时候,我们不得不自己完成大量非常繁琐的工作。当然,对于编程高手来说,OPENGL是他们发挥才能的非常好的工具。 VRML2.0(VRML97)自1997年12月正式成为国际标准之后,在网络上得到了广泛的应用,编写VRML程序非常方法(VRML语言可以说比BASIC、VASCRIPT等语言还要简单),同时可以编写三维动画片、三维游戏、用于计算机辅助教学,因而其应用前景非常广阔尤其适合在中国推广应用。不过由于VRML语言功能目前还不是很强(如目前没有形体之间的碰撞检查功能),与JAVA语言等其它高级语言的连接较难掌握,因而失去了一些计算机高手的宠爱。但我们认为,我们可以让大学里的文理科学生利用VRML编写多媒体应用程序,让学生很快地对编写程序感兴趣,从而使国内的计算机水平得到提高。 DIRECT3D是Microsoft公司推出的三维图形编程API,它主要应用于三维游戏的编程,目前相关的学习资料难于获得,由于它一般需要VC等编程工具进行编程,需要编程人员具有较高的C++等高级语言的编程功底,因而难以普及。 JAVA3D是建立在JAVA2(JAVA1.2)基础之上的,JAVA语言的简单性使JAVA3D的推广有了可能。OPENGL和JAVA3D之间的比较可以看成汇编语言与C语言之间的比较,一个是低级的,一个是高级的(也许这样比较不太恰)。JAVA3D给我们编写三维应用程序提供 了一个非常完善的API,它可以帮助我们:
        生成简单或复杂的形体(也可以直接调用现有的三维形体)
        使形体具有颜色、透明效果、贴图。
        可以在三维环境中生成灯光、移动灯光。
        可以具有行为(Behavior)的处理判断能力(键盘、鼠标、定时等)
        可以生成雾、背景、声音等。
        可以使形体变形、移动、生成三维动画。
        可以编写非常复杂的应用程序,用于各种领域如VR。

在编写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

四. 如何编写配置JAVA3D

略  

(环境配置请参考http://blog.csdn.net/olenet/article/details/21334219)

五. 如何运行JAVA3D源程序

六. 一个最简单的JAVA3D源程序。

下面我们介绍一个最简单的JAVA3D源程序,进而介绍JAVA3D为我们提供的各种功能。程序是一个JAVA的APPLET类型的程序,它的作用是显示一个 红色的圆锥,仅此而以
 
  
//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 SimpleConeJAVA3D程序也是JAVA程序,因而我们首先必须对JAVA有所了解,并能编写简单的JAVA程序,了解JAVA编程的基本概念,关于JAVA语言的相关知识,我们在这里就不一一介绍了,国内这方面的书籍非常丰富。
 
  

. SimpleCone 程序分析

1. SimpleCone.java及其对应的VRML程序

 
  

2. 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。介绍了一个简单的JAVA3D程序后,我们开始学习JAVA3D的编程技术。首先我们介绍三维基本形体的生成。和VRML不同,JAVA3D没有基本形体类,因而在程序中无法直接生成大量应用的基本形体,如BOX、CONE、SPHERE等。我们可以通过复杂的编程生成这些基本形体,也可以直接调用JAVA3D为我们提供的geometry classes,利用它生成程序所需要的BOX、COLORCUBE、CONE、SPHERE、CYLINDER。我们开辟一个新的章节介绍这些基本体的生成方法。
 
    

八.基本体的生成方法

八(一): 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的COLORCUBE2. 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、JAVA3D编程过程中,我们经常要编写一些点、线、面,JAVA3D所提供的API中有许多这方面的对象,下面我们开始一一介绍它们的使用方法。
 
    

九.Java3d中点线面的生成

九(一).点

1.点的生成

下面我们改用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中了。
2. 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表示最终应生成的点的个数。
3. 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      
4. 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四个点。 
5. 主程序比较简洁的程序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
6. 能够旋转的点 前面介绍的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米之内的形体均可以旋转运动,而在这范围之外的所有形体均不产生运动。  
我们可以利用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[])
 
  
 
   
 
   
 
   

九(二). 直线

1. 利用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
2. 利用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
 
   
3. 利用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
4. 利用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); 
    }
}

九(三).面

1. 生成平面的对象及其定义
    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[])
 
  
 
   
 
   
2. 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显示的内容从色彩变化及单面显示变为每一个面只有一种颜色及双面显示?在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);
    }
}
3. 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,
         };

4. 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
5. 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

//end of lineShape5.java 

十. 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场景图所引用,如某一个颜色可以被多个形体所引用。
 
 

你可能感兴趣的:(java3d)