程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> 利用Java 3D技術播放動畫之JMF技術

利用Java 3D技術播放動畫之JMF技術

編輯:JAVA編程入門知識
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應用程序中的兩幅屏幕快照,它們是在不同的時刻拍攝的:其中右邊的那幅是屏幕從後面看上去的視圖。


圖 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結點是怎樣被鏈接到一起的)。


圖 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類圖,其中僅顯示了類的公共方法。


圖 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。
把紋理鏈接到四邊形上

把紋理圖像平鋪到一個四邊形上的常用方法是,把紋理的左下角鏈接到四邊形的左下角,並以反時針方向指定其它鏈接。這種方法顯示在圖4中。


圖 4.紋理與四邊形間的標准鏈接


紋理坐標的范圍是0-1,沿著x軸和y軸,且y軸方向向上。例如,紋理左下角使用坐標(0,0),則右上角為(1,1)。

當使用"Y-up"方式時,y軸的紋理坐標是顛倒的,即指向下方。這就是說,坐標(0,0)對應紋理的左上角,而(1,1)對應紋理的右下角。

在使用"Y-up"方式情況下,紋理坐標一定要賦給四邊形的不同點以取得圖像的相同的方向。這種新的配置顯示在圖5中。


圖 5. 當使用"Y-up"方式時的紋理與四邊形的鏈接


在JMFMovieScreen中,實現把四邊形頂點與紋理坐標相鏈接的代碼如下:

TexCoord2f q = new TexCoord2f();

q.set(0.0f, 0.0f);
plane.setTextureCoordinate(0, 3, q);
//紋理坐標(0,0)-->四邊形左上點(p3)
q.set(1.0f, 0.0f);
plane.setTextureCoordinate(0, 2, q);
// (1,0) -->右上(p2)

q.set(1.0f, 1.0f);
plane.setTextureCoordinate(0, 1, q);
// (1,1) -->右下(p1)

q.set(0.0f, 1.0f);
plane.setTextureCoordinate(0, 0, q);
// (0,1) -->左下(p0)

這裡的平面對象代表了四邊形。

更新圖像

前面已經提到,一個TimeBehavior對象被建立以每隔40毫秒調用一次JMFMovieScreen的nextFrame()方法。而ne
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved