Graphics 版 (精华区)

发信人: seaman (翩翩少年), 信区: Graphics
标  题: JAVA3D学习系列(7)--点的生成
发信站: 哈工大紫丁香 (Mon Sep 20 19:15:30 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.hit.edu.cn.[FROM: sunsoft.bbs@bbs.net.]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.336毫秒