BBS水木清华站∶精华区

发信人: vrml (3d), 信区: Java        
标  题: JAVA3D学习系列(7)--点的生成 
发信站: BBS 水木清华站 (Wed Apr  7 16:18:25 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 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 202.192.158.112] 

BBS水木清华站∶精华区