天天看點

java3d程式設計簡介(點線面的程式設計執行個體)一.JAVA3D的作用:二.OPENGL、VRML、DIRECT3D、JAVA3D的比較三. JAVA3D的資料結構四. 如何編寫配置JAVA3D五. 如何運作JAVA3D源程式六. 一個最簡單的JAVA3D源程式。七. SimpleCone 程式分析八.基本體的生成方法九.Java3d中點線面的生成十. JAVA3D(API)中的類

原文位址: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檔案:<HTML><BODY><APPLET code=SimpleCone.class width=200 height=150></APPLET></BODY></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場景圖所引用,如某一個顔色可以被多個形體所引用。