Java 3D API官方教程


第一章、入門

本章目標:

      Java 3D API是一個用於編寫顯示和交互操作三維圖形對象的程序的接口。Java 3D也是在Java2 Java開發包(JDK)上的標准擴展。這個API提供了用於創建和操縱3D圖形的高端構成方法以及渲染該圖形的一些數據結構。Java3D 提供了創建圖片、可視化、動畫以及3D交互圖形應用程序的函數。

1.1 什么是Java 3D API?

       Javae 3D API是作為復雜三維圖形和聲音渲染系統的接口的一系列層次的JAVA類的統稱。

       程序員可以用Java3D開發創建和操縱3D圖形對象的高端應用。這個圖形對象處於一個被渲染了的虛擬世界(Virtual Universe)中。這個API就是用設計來用於靈活方便地創建精確的各種大小的虛擬環境,可以大到大空物體,小到比原子還小。

     除了這些功能之外,API的使用也很直接,API能自動處理渲染的細節,由於利用了Java線程機制的優勢,所以Java3D的渲染器的工作是並行進行的。並且渲染器也能自動地優化並提高渲染性能。   

     一個Java3D程序創建了Java3D對象的實際,並將其置之於場景圖數據結構中。在這個場景圖中,所有3D對象用完全指定了虛擬世界內容和其如何被渲染的樹形結構存儲,

     Java3D程序能寫成能獨立運行的應用程序,或者寫成能嵌入在瀏覽器中運行的Applets,或者二者兼備。

1.2 Java 3D API

每一個Java3D程序至少部分地集成了來自Java類層次中的對象,這些對象的集合稱做虛擬世界(virtual universe),這就是將要被渲染的對象。此API在javax.media.j3d包中定義了超過100多個類,這些類我們平常稱做Java3D核心類。

   在Java3D API中有數以百計的屬性和方法。盡管如此,一個包含動畫功能的簡單的虛擬世界的構建僅僅需要幾個類就行。本章討論了用盡少的對象集合和交互來渲染一個簡單虛擬世界。

    本章包含了一個簡單但是完全的叫HelloJava3D的程序的開發過程,這個程序顯示了一個能旋轉的立方體,這個示例程序是逐步開發完成的,因此這個程序用了很多版本來展示Java 3D編程過程中的每一部分。本教程中的所有程序都可以獲得電子的版本。更多的信息請見前言中的"獲得本教程"[譯者注:http://java.sun.com/products/java-media/3D/collateral/

   除了Java3D核心包之外,Java3D程序設計也會用到其它的包,比如com.sun.j3d.utils,這個包通常稱做Java3D工具類,核心類中僅僅包含了在Java3D編程中必段的最底層的類,而工具類是對核心類方便而強大的補充。

   工具類主要分為四類:內容加載器、場景圖構建輔助類、圖形類和方便的一些工具類。將來還有一些功能,比如nurbs[non-uniform rational B-spline,非均勻有理B樣條],也會加到工具類,而不是Java3D核心包中。而一些工具類在Java 3D API 將來的版本中也可能會移到核心包中去。

   利用工具類大大地減少了Java3D程序中的代碼行數。除Java3D核心類和工具類包之外,每一個Java3D程序還引用了java.awt包和 javax.vecmath包中的類. java.awt包就是Abstract WindowingToolkit (AWT). AWT類用於創建顯示和渲染場景和窗口。而javax.vecmath包則定義了對點、矢量、矩陣以及其他數學對象進行數學運算的類。

     在余下的教程中,詞匯可視對象(visual object)就是場景圖中的對象比如一個立方體或者球體。對象(object)則是指一個類的實例。而內容(content)指的是一個場景圖中全部的可視對象。

1.3 構建場景圖

     一個Java3D的虛擬世界創建自一個場景圖,而場景圖就是由Java3D類的實例構建而成.場景圖集成了定義圖形、聲音、光線、位置、方向以及可視物體和聲音對象的表面屬性等對象。 一個通常的圖形定義是一個由結點和弧邊組成的數據結構。一個結點是一個數據元素,而邊則是數據元素之間的關系。場景圖中的結點就是Java3D類的實例,而邊展示了這些Java 3D實例之間的兩種關系。最為通用的關系是就是父子關系(parent-child relationship),一組結點可以有任意數目的孩子卻只能有一個雙親。一個葉子結果可以有一個雙親但是沒有孩子。

另一個關系是引用(reference)。一個引用與場景圖結點中的結點組件(NodeComponent)對象相關聯。結點組件定義了用於渲染可視對象的圖形和表面屬性。

Java 3D場景圖就是由一堆具有父子關系的結點構建成的樹形結構。在樹形結構里,其中有且僅有一個結點是根結點,共他結點都可以順着從根開始的弧邊可以訪問到,樹形結構中的結點是沒有回路的。一個場景圖就是由植根於本地(Locale)對象的樹而形成的。結點組件和引用弧邊都不是場景圖樹的組成部分。

在樹形結構中,從根結點到葉子結點有且僅有一條路徑,因此,從場景圖的根到其每個葉子結點也僅有一條路徑。從場景圖根結點到到特點葉子結果的路徑我們稱之為該葉子結點的場景圖路徑(scene graph path)。 因此,一條場景圖路徑恰恰只通向了一個葉子結點。而在場景圖中從根到每個葉子結點都有一條這樣的路徑。在Java3D場景圖中的每一條場景圖路徑也完全地 定義了路徑的葉子的狀態信息。狀態信息包括位置、方向、可視對象的大小。由此可見,每一個可視對象的可視屬性僅僅由其場景圖路私決定。Java3D渲染利 用這點,以僅可能有效地按它所定義的順序來渲染葉子對象。Java 3D程序員一般情況下不用控制渲染對象的順序。[原注:Java3D 程序員僅僅可以用來控制渲染對象順序的是OrderedGroup類結點,在本教程中對此部分未加論述,請參見Java3D API規范文檔]

在樹形結構中,從根結點到葉子結點有且僅有一條路徑,因此,從場景圖的根到其每個葉子結點也僅有一條路徑。從場景圖根結點到到特點葉子結果的路徑我們稱之為該葉子結點的場景圖路徑(scene graph path)。 因此,一條場景圖路徑恰恰只通向了一個葉子結點。而在場景圖中從根到每個葉子結點都有一條這樣的路徑。在Java3D場景圖中的每一條場景圖路徑也完全地 定義了路徑的葉子的狀態信息。狀態信息包括位置、方向、可視對象的大小。由此可見,每一個可視對象的可視屬性僅僅由其場景圖路私決定。Java3D渲染利 用這點,以僅可能有效地按它所定義的順序來渲染葉子對象。Java 3D程序員一般情況下不用控制渲染對象的順序。[原注:Java3D 程序員僅僅可以用來控制渲染對象順序的是OrderedGroup類結點,在本教程中對此部分未加論述,請參見Java3D API規范文檔]

場景圖的圖形表示可以當作設計工具或者Java3D程序的文檔。場景圖一般用一些標准的圖形標記來繪制,如圖1-1所示。Java 3D程序可能不止有包含場景圖中的這些對象。

可以用以上標志集合來設計一個Java3D虛擬世界場景圖。等設計上的事情完成后,場景圖的設計就是程序設計的規范。等到程序也設計完成,同一個場景圖就是程序的精解表現(假設程序是依照設計的圖來進行的話)。一個從已有程序繪制成的場景圖可以做創建程序場景圖的文檔。

可以用以上標志集合來設計一個Java3D虛擬世界場景圖。等設計上的事情完成后,場景圖的設計就是程序設計的規范。等到程序也設計完成,同一個場景圖就是程序的精解表現(假設程序是依照設計的圖來進行的話)。一個從已有程序繪制成的場景圖可以做創建程序場景圖的文檔。

       圖1-1左邊所示的每一個標記代表了場景圖中的每一個對象,前兩個標記代表特定的類的對象,即VirtualUniversee和Locale類的對象,下面的三個則常常用於標注特定對象[譯者注:Group子類的對象等]的子類,最后一個標記用於表示其它類的對象。實線箭頭表示兩個所連接的對象之間存在 父子關系。而虛線箭頭則表求一個對象是另一個對象的引用。引用的對象可以供一個場景圖中的不同的分支所共享。一個簡單的場景圖的例子如圖1-2所示。

    在平時,創建一個錯誤的場景圖也是可能的,一個不合理的場景圖的例子如圖1-3所示.

      圖1-3所描繪的場景圖之所以不合理是因為它與有向無環圖(Directed Acyclic Graph Or DAG)的規則相沖突.問題存在於兩個TransformGroup對象都以同樣的ShapE3D葉 子對象作為其孩子。請記住,一個葉子結點只能一個雙親,也就是,從Locale對象到葉子結點只能有一條路徑(或者從葉子結點到Locale對象只能有一 條路徑)。你也許會認為,圖1-3圖所示的場景在虛擬世界中定義了三個可視對象。它看起來好像是這個場景圖通過重用圖形右邊的可視對象(Shape3D) 而定義了兩個對象。從概念上講,每一個TransformGroup 對象都作為共享的那個Shape3D的雙親,這個Shape3D的可視化對象可以允許在不同地方放置一張圖片。盡管如此,由於父子邊之間的關系構不成樹形結構,所以這個場景圖是不合法的。在這個例子中,表現為Shape3D對象有多於一個以上的雙親。

     對樹形結構和有向無環圖的討論是正確的,然而,Java 3D運行時系統會報告這類父子關系之間的錯誤。樹形結構存在的限制是每一個Shape3D 對象只能有一個雙親。

    從圖1-3所示的例子看來,‘多親'異常會在運行時報告出來。圖1-4中,展示了這種不合法場景圖的解決辦法,每一個Shape3D只有一個雙親。 

       一個定義了不合理(法)場景圖的Java3D程序可能通過編譯,但是不會在運行時渲染。當一個定義了不合法場景圖的Java3D程序運行時,Java3D 系統會檢測到這個問題,從而會報告一個異常。程序還會繼續運行,但是結果是,應該被關閉,沒有任何渲染好的圖象生成。每一個場景圖有一個唯一的VirtualUniverse,這個VirtualUniverse有一系列 Locale 對象。

      一個Locale對象,提供了虛擬世界中的一個參考點。可以把Locale對象看作是在虛擬世界中定義可視對象位置的標志。一個Java3D程序有多於一 個的VirtualUniverse對象,技術上是可行的,因此,可以在虛擬世界中定義多個Locale對象,然而,在多個虛擬世界之間沒有內在的溝通方 式,更進一步講,一個場景圖不能存於多個虛擬世界中。同時,我們強烈建議在一個Java 3D程序中只同時擁有有且僅有一個VirtualUniverse。而一個VirtualUniverse 可能在多個Locale對象中引用,但是更多的Java 3D程序只有一個Locale對象,每一個Locale對象,可以作為場景圖中多個子圖的根結點。參考圖1-2作為場景圖的例子,注意到圖中的Locale對象有兩個子圖分支。

     一個BranchGroup對象是子圖的根結點,或者是分支圖的根結點。場景子圖可以分為兩類,視圖分支圖(the view branch graph)和內容分支圖( the content branch graph.)。內容分支圖指定了虛擬世界的內容——圖形,表面,動作,位置,聲音以及光線等。視圖分支子圖指定了視圖參數比如觀看位置和方向。總的來說,兩類子圖指定了很多渲染要完成的工作。

1.3.1高端Java 3D API的類層次

圖1-5顯示了Java 3D API類層次中的前面三個層次。

VirtualUniverse, Locale, Group, 和 Leaf 類處於類層次中的這部分。除了VirtualUniverse 和Locale對象,場景圖中余下的部分由SceneGraphObject 對象構成。SceneGraphObject 幾乎是Java3D類中每一個核心類和工具類的超類[譯者注:超類即上層類,可以是父類或者祖先類]。

SceneGraphObject 有兩個子類: Node 類NodeComponent.類,Node子類提供了場景圖中的絕大部分對象,一個Node對象可以是一個Group,也可是一個Leaf結點對象。

Group 和Leaf是一系列類的超類。這里可以一目了然地看到Node類的子類,它有兩個子類,而 NodeComponent 類,在這些背景知識介紹之后,在Java3D程序的構建中會解釋到。

Node 類

Node是Group和Leaf類的一個抽象超類. Node 為其子類定義了一些公共的重要的方法。某些方法的信息會在更多的背景知識介紹了之后提到。Node 的子類構成了子圖。

Group 類

Group 類是用於在虛擬世界中指定可視對象位置和方向的類的超類。Group類的兩個下層類是 BranchGroup是TransformGroup. 在場景圖的圖形表現中,Group標記 (用圓表示)。而其中BranchGroups注為GB, TransformGroups注為TG,等等。具體例子請見圖1-2。

Leaf 類

Leaf是用於指定虛擬世界中可視對象的形狀,聲音和,動作的類的超類。Leaf的一些子類如Shape3D, Light, behavīor,和 Sound. 這些對象不能有自己的孩子,並且可能引用NodeComponents對象。

NodeComponent 類

NodeComponent 類是用於指定Shape3D (Leaf)結點對象的圖形,表面,紋理和材質屬性的類的超類。NodeComponents 不是場景圖的組成部分,但是為其所引用。一個NodeComponent 對象可能為多個Shape3D對象所引用(譯者注:就是比如,同一個材質對象可以賦予多個shape3D對象)。

java 3D API官方教程:1.4 編寫Java3D程序的一般步驟

SceneGraphObject類的子類就是集成構建場景圖的模塊,一個Java3D程序的開發大略可以分為七步(把它們聚在一起,在Java 3D API 規范中和這里稱之為步驟(recipe)),具體如下列表所示,這些方法可用於裝配許多的Java3D程序。

1. 創建一個Canvas3D對象。

2. 創建一個VirtualUniverse對象。

3. 創建一個Locale 對象,並使之與VirtualUniverse相關聯。

4. 構建一個視圖子圖。

a. 創建一個View 對象。

b. 創建一個ViewPlatform對象。

c. 創建一個PhysicalBody對象。

d. 創建一個PhysicalEnvironment對象。

e. 把 ViewPlatform, PhysicalBody, PhysicalEnvironment, 和Canvas3D對象與View 對象相關聯。

5. 構建一個或多個內容子圖。

6. 編譯所有子圖。

7. 把子圖加到Locale對象中。

表 1-1 編寫Java3D程序的一般步驟


這些步驟忽略了細節但是解釋了Java 3D編程中的基本概念。創建場景圖中的子圖是編程的主要部分。但我們並沒有展開這些步驟詳細討論,本教程的下一部分解釋了一種用更少的代碼更容易的手段來構建一個非常簡單的場景圖的方法。

1.4.1 編寫Java 3D程序的一個簡單方法

用 基本方法編寫具有視圖分支圖的Java 3D programs程序的結構有其唯一性,構建視圖分支子圖結構的規則可以通過SimpleUniverse工具類來實現. SimpleUniverse 的實例承擔了構建場景圖的基本步驟中的第2, 3以及第4步。利用SimpleUniverse類來進行Java3D編程,可以大大減少創建視圖分支圖的時間和精力,從而,程序員可以有更多的時間來構建內容分支子圖,這才是真正與Java3D程序事關重大的。

SimpleUniverse類對於Java 3D編程而言真是一個很好的起點,因為它允許程序員暫時忽略視圖子圖的存在.盡管如此,SimpleUniverse 中也不允許同一個虛擬世界存在多個視圖。

本 教程的所有例子程序都用到了SimpleUniverse類,因此,如果程序員想獲得更多的關於View, ViewPlatform, PhysicalBody, 和PhysicalEnvironment 類的信息請參考其它參考資料,附錄B有詳細的參考資料列表。

SimpleUniverse類

SimpleUniverse 對象的構造函數創建了包含VirtualUniverse 、Locale對象以及一個完整的視圖子圖在內的場景圖,SimpleUniverse創建的視圖子圖是用了ViewingPlatform 和Viewer 便利類的實例來代替了其它核心類來創建視圖子圖。注意到SimpleUniverse僅僅是沒有直接用到 Java3D核心類中的View和ViewPlatform對象的。SimpleUniverse 對象提供了圖1-7中大方框中的所有功能。com.sun.j3d.utils.universe包包括了 SimpleUniverse, ViewingPlatform, 和Viewer convenience工具類。

利 用一個SimpleUniverse 對象可以使構造Java3D程序的基本步驟更加簡單,表1-2展示了簡單的方法。這是用SimpleUniverse 對象之后構建Java3D程序所需的步驟,上文所提到的基本步驟的第2, 3,和4步已經被本方法的第2步所替代。

1. 創建一個Canvas3D對象。

2. 創建一個SimpleUniverse對象,並添加對先前創建的Canvas3D 對象的引用。

a. 定制SimpleUniverse對象。

3. 構建內容子圖。

4. 編譯內容分支子圖。

5. 把內容子圖添加到SimpleUniverse的Locale中。

表1-2 用SimpleUniverse創建Java3D程序的簡單步驟

下 面的灰框中的內容是本教程中參考模塊的第一次出現。參考模塊一般對一個類的構造函數、方法和屬性作了個列表。使用參考模塊的目的在於使讀者能在手頭上沒有其他參考資料的情況下能學到基本的Java 3D API編程知識。本教程中的參考塊並沒有涉及到每一個類的構造函數和方法,由於這個原因,很多的Java 3D API 類都沒有列出參考塊。因此,本教程的文檔本不能替代Java 3D API規范的位置,盡管如此,列出了構造函數、方法和屬性的參考塊的這些類,本教程所提供的信息往往比Java 3D API規范所提供的信息更加詳實。

SimpleUniverse 構造函數

包: com.sun.j3d.utils.universe

這個類構建了一個盡可能小的用戶環境,以使Java3D程序能盡快盡簡單地運轉起來。這個工具類創建了視圖子圖中所必需的所有對象。特別是創建了 Locale, VirtualUniverse, ViewingPlatform, 和Viewer對象, (構建這些對象時統統使用默認值).這些對象以恰當的關系構成了視圖子圖。

SimpleUniverse 提供了許多基本的Java 3D應用程序所必需的全部功能. Viewer和ViewingPlatform都是很方便的工具類.這些類用到了View 和ViewPlatform 核心類。

SimpleUniverse()

構建一個包含視圖子圖的簡單虛擬世界。.

SimpleUniverse(Canvas3D canvas3D)

構建一個簡單虛擬世界並與指定的Canvas3D對象建立關聯。

構建一個簡單虛擬世界並與指定的Canvas3D對象建立關聯。
SimpleUniverse對象創建了虛擬世界中一個完全的視圖分支子圖。這個視圖分支圖包括一個圖板(image plate)。Java 3D把場景內容投影到圖板塊上形成一個渲染圖象。Canvas3D 對象,提供了在計算機的窗口上顯示圖象,就可以看做圖板。
圖1-9,顯示了圖象圖板,觀察者位置和虛擬世界的關系。 觀察者在圖板后面。而可視對象在圖板之前並能在圖板上進行渲染。渲染就可以看作是可視對象到圖板上的投影。這個觀點就如圖中的四個方向上的投影儀(虛線所示)

默認地,圖板位置SimpleUniverse原始位置的中心,默認的方向是從Z軸從上往下看的。從這個位置上看,X軸是一條正向在右邊的水平穿過圖板的直線,而Y軸是垂直穿過圖板中心、正向在上方的直線。因此,點 (0,0,0)就處於圖板的正中央。

一 般的Java3D程序,都把視圖往后退(Z軸正向)(譯者注:物體前移,往Z軸正向移,或往圖外移),以使物體處於或者離原始視圖比較近。 SimpleUniverse類有一個ViewingPlatform的類的實例作為成員對象,ViewingPlatform類也有一個 setNominalViewingTransform的方法來設置觀察者(眼睛)的位置,使之位於 (0, 0, 2.41)(looking in the negative z direction toward the origin?).

ViewingPlatform setNominalViewingTransform() 方法

包: com.sun.j3d.utils.universe

ViewingPlatform 類用於設置SimpleUniverse 對象中Java 3D場景圖的視圖分支圖。這個方法一般用SimpleUniverse 類的getViewingPlatform方法來進行連接。

void setNominalViewingTransform()

把SimpleUniverse對象中的象征性的觀察者設置約2.41米的距離變化。在這個距離上,視圖的默認屬性,2米高和寬的對象大約都會恰好與圖板符合。

創 建了Canvas3D和Simple Universe對象后,下一步就是創建內容子圖。對視圖子圖中的常規結構的應用,從而導致應用SimpleUniverse類的這一套,對內容子圖並不 適合,因為內容子圖在每一個程序中都各有不同,因而也就不可能給出構建一個內容子圖的通用的詳細方法。這也意味着你想集成的任何虛擬世界中並不存在簡單內容類("simple content")。

創建內容子圖是第1.6,1.7和1.9節的主題,在1.8節中討論了內容了圖的編譯。如果你迫不及待地想看代碼以找出個究竟,請參考代碼段1-1,這就是一個應用SimpleUniverse類的例子。

創 建了內容子圖之后,可以用addBranchGraph把內容子圖加到SimpleUniverse對象中. addBranchGraph方法把BranchGroup 的實例作為唯一的傳入參數。BranchGroup作為SimpleUniverse 對象所創建的Locale對象的孩子加到場景圖中。

SimpleUniverse 的方法 (只列出了部分)

包: com.sun.j3d.utils.universe

void addBranchGraph(BranchGroup bg)

用於往SimpleUniverse對象所創建的Locale對象的場景圖中。用這個方法把內容子圖添加到虛擬世界中。

ViewingPlatform getViewingPlatform()

用於獲取SimpleUniverse 實例化后的ViewingPlatform 對象。這個方法再附加調用setNominalViewingTransform()方法來調整視圖的位置



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM