利用Java 3D技术播放动画之JMF技术
2008-01-05 08:19:42 来源:WEB开发网核心提示: java 3D场景中动画片段的播放为更丰富更生动的3D内容带来了进一步发展的机会,动画可以显示更逼真的背景,利用Java 3D技术播放动画之JMF技术,例如运动的云彩,繁忙的城市街道,把纹理的左下角链接到四边形的左下角,并以反时针方向指定其它链接,或者窗外的场景等等,动画可以使得帮助信息更生动
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()方法建立起来的:
这里的两个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所使用,其声明如下:
构造器中的最后两个参数指出,它使用的是"by reference"和"Y-up"方式。由于Java 3D会避免把图像从应用程序空间复制到图像内存中去,所以这里指出的方式将减少存储纹理图像的内存需求。
在Windows操作系统环境下,Java 3D用OpenGL作基本的着色引擎,ImageComponent2D格式应该是ImageComponent2D.FORMAT_RGB(如上所述),BufferedImage格式应该是BufferedImage.TYPE_3BYTE_BGR。在JMFSnapper中BufferedImage格式是固定的。
要想对此和其它性能技巧有更多的了解,可以参见j3d.org。 把纹理链接到四边形上
把纹理图像平铺到一个四边形上的常用方法是,把纹理的左下角链接到四边形的左下角,并以反时针方向指定其它链接。这种方法显示在图4中。
本文共分为两部分,描述了我是怎样实现一个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中。
更多精彩
赞助商链接