发信人: vrml() 
整理人: funboy(1999-11-24 09:19:15), 站内信件
 | 
 
 
    		JAVA3D学习系列之7---点的生成
 
     汕头大学机电系  张杰([email protected])
 
 
 (     在前面(第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
  -- ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.192.159.19]
  | 
 
 
 |