天天看點

利用Java 3D技術播放動畫之JMF技術-Java基礎-Java-程式設計開發

<script type="text/javascript"> google_ad_client = "pub-8800625213955058"; google_ad_slot = "0989131976"; google_ad_width = 336; google_ad_height = 280; // </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>  Java 3D場景中卡通片段的播放為更豐富更生動的3D内容帶來了進一步發展的機會。動畫可以顯示更逼真的背景,例如運動的雲彩,繁忙的城市街道,或者窗外的場景等等。動畫可以使得幫助資訊更生動,也可以用于遊戲設計中的場景過渡。

  本文共分為兩部分,描述了我是怎樣實作一個Java 3D動畫螢幕的。本部分将解釋怎樣利用Java媒體架構(JMF)開發本程式的,特别對JMF性能包Windows版本2.1.1e進行了具體的描述。我所用的另外一些工具包括J2SE 5.0和Java 3D 1.3.2。在第二部分中,我将讨論利用Quicktime for Java技術實作該動畫程式的的另外一個版本。

  圖1展示了JMF Movie3D應用程式中的兩幅螢幕快照,它們是在不同的時刻拍攝的:其中右邊的那幅是螢幕從後面看上去的視圖。

利用Java 3D技術播放動畫之JMF技術-Java基礎-Java-程式設計開發

圖 1.Movie3D應用程式中的兩幅視圖

  該應用程式主要包括:

  ·JMF與Java 3D的整合。一個應用程式中可以有多個任意大小的螢幕。既然一個螢幕是Java 3D的Shape3D類的子集,那麼它可以被輕易地整合進不同的場景中。

  ·程式的執行過程采用了"模型-視圖-控制器"設計模式。其中,螢幕是視圖元素,由JMFMovieScreen類描述。動畫是模型部分,由JMFSnapper類所管理。一個Java 3D Behavior類TimeBehavior是控制器,由它來控制動畫的周期性更新。所有的JMF代碼都位于JMFSnapper類中,這使得測試任何變化都更為容易些。在這篇文章的第二部分中,實際上是用了一個稱為QTSnapper的QuickTime for Java版本代替了JMFSnapper。

  ·充分利用了Java 3D性能技巧來加速着色過程;結果,動畫可以以每秒25幀的速度播放而無任何困難。

  ·最後讨論一下我采用JMF開發時遇到的問題,由于這些問題,我更喜歡的解決方案不能正常工作-JMF的确具有成為一個偉大API的潛力,但在這一偉大的背後還有許多低劣的編碼部分有待進一步改進。

  1. 我坐在一座高山上

  實際上,我根本沒有坐在什麼高山上,而是坐在沒有自動調溫器的寒冷的辦公室的一把椅子上。我真正想說的是,這篇文章基于大量的Java 3D和JMF的背景知識。

  在本文中,我将解釋我用來從影片中提取動畫幀的JMF技術,而不去讨論諸如流媒體,捕獲或者代碼轉換等技術。

   2. 程式實作中的兩幅輪廓圖

  動畫由JMFSnapper類負責裝載和播放,且動畫播放循環進行,直到發指令讓其停止。

  動畫螢幕由JMFMovieScreen建立,它負責管理一個放在跳棋盤地闆上的Java 3D四邊形。

  想直覺觀察一下這些類嗎?請看下圖中的應用程式場景圖(該場景圖展示了在一個場景中的Java 3D結點是怎樣被連結到一起的)。

利用Java 3D技術播放動畫之JMF技術-Java基礎-Java-程式設計開發

圖 2. Movie3D場景圖

  圖2的許多細節被忽略掉了,但是這幅圖與KGPJ中第15章的示例Checkers3D有着驚人的相似。隻有動畫相關的結點是新東西。

由于JMFMovieScreen和TimeBehavior對象都是場景圖中的結點,是以它們都以三角形方式顯示。JMFSnapper對象不是圖中的一部分,但是被JMFMovieScreen所調用。

  每隔40毫秒,TimeBehavior對象調用一次JMFMovieScreen的nextFrame()方法,而nextFrame()又依次調用JMFSnapper的getFrame()方法來檢索正播放動畫中的目前幀,該幀然後被放置到由JMFMovieScreen管理的四邊形上。

  TimeBehavior是Java 3D的Behavior類的子類化,是一個定時器的Java 3D實作方式。它與KGPJ中第18章的3D精靈示例中的TimeBehavior類很相似。

  洞察該應用程式實作的另一方法是看一下圖3中描述的UML類圖,其中僅顯示了類的公共方法。

利用Java 3D技術播放動畫之JMF技術-Java基礎-Java-程式設計開發

圖 3. Movie3D類圖

  Movie3D子類化了Jframe,而WrapMovie3D是Jpanel的子類化結果。WrapMovie3D建立了圖2中的場景圖,并在應用程式的JPanel上對其進行着色。它使用CheckerFloor類和ColouredTiles類來構造出跳棋盤地闆效果。

  JMFMovieScreen完成動畫螢幕的建立,并把它添加到場景中去,然後通過建立一個JMFSnapper對象來啟動動畫的播放。TimeBehavior每40毫秒調用JMFMovieScreen中的nextFrame()方法一次,而nextFrame()又調用JMFSnapper中的getFrame()方法來檢索目前幀。

  所有該示例的代碼以及本文的一個早期版本,都能在KGPJ website處找到。

  3.觀看動畫播放

  動畫,動畫螢幕以及用來更新螢幕的TimeBehavior對象都是由WrapMovie3D中的addMovieScreen()方法建立起來的:

//全局變量

private BranchGroup sceneBG;

private JMFMovieScreen ms; //動畫螢幕

private TimeBehavior timer; //更新螢幕

private void addMovieScreen(String fnm)

{

 //把fnm形式的動畫投放到動畫螢幕上

 ms = new JMFMovieScreen(new Point3f(1.5f, 0, -1), 2.0f, fnm);

 sceneBG.addChild(ms);

 //為animating動畫建立計時器對象

 timer = new TimeBehavior(40, ms);

 //更新動畫每40ms一次(25幀/秒)

 timer.setSchedulingBounds(bounds);

 sceneBG.addChild(timer);

}

  這裡的兩個Java 3D方法addChild()調用把JMFMovieScreen結點和TimeBehavior結點連結到場景圖中。setSchedulingBounds()方法用于激活TimeBehavior結點(也就是說,使該結點開始計時)。

  4.生成動畫螢幕

  JMFMovieScreen是Java 3D的Shape3D類的子類化,是以一定要為其指定一個幾何形狀和外觀。

  幾何形狀是一個四邊形,每邊與動畫的圖像尺寸成比例,但是用該四邊形寬度與高度中的較大值用作類JMFMovieScreen的構造器的參數。該四邊形是豎直的,朝向正Z軸方向,可被放于地闆的任意位置。

  該四邊形是兩面的,這樣動畫可以從螢幕的前後兩個方向觀看。紋理是使用雙線性插補算法進行平滑處理,是以當從近處觀看動畫時,像素化現象大大減弱。

  這裡的大部分功能是從KGPJ一書第24章的第一人稱射擊程例中的ImageCsSeries類中複制過來的。ImageCsSeries類用于在一個四邊形上顯示一系列的GIF圖像。為節省篇幅,我僅描述一下JMFMovieScreen差別于ImageCsSeries的幾個特點。

   實作圖像的高效着色

  從動畫中提取的幀被轉換成紋理後放于四邊形之上;其實作方式分為兩步:第一,給定的BufferedImage被傳遞給一個Java 3D ImageComponent2D對象,然後又傳遞給一個Java 3D Texture2D。

  四邊形的紋理更新是很迅速的:每秒可更新25幀,紋理需要變化25次。是以,實作高效地紋理化是十分重要的。這有可能通過把某些特定的格式指定給BufferedImage和ImageComponent2D對象來實作。

  ImageComponent2D對象由JMFMovieScreen所使用,其聲明如下:

ImageComponent2D ic = new ImageComponent2D(

 ImageComponent2D.FORMAT_RGB,

 FORMAT_SIZE, FORMAT_SIZE, true, true);

  構造器中的最後兩個參數指出,它使用的是"by reference"和"Y-up"方式。由于Java 3D會避免把圖像從應用程式空間複制到圖像記憶體中去,是以這裡指出的方式将減少存儲紋理圖像的記憶體需求。

  在Windows作業系統環境下,Java 3D用OpenGL作基本的着色引擎,ImageComponent2D格式應該是ImageComponent2D.FORMAT_RGB(如上所述),BufferedImage格式應該是BufferedImage.TYPE_3BYTE_BGR。在JMFSnapper中BufferedImage格式是固定的。

  要想對此和其它性能技巧有更多的了解,可以參見j3d.org。

[1] [2] [3]