利用Java 3D技术播放动画之JMF技术(2)

http://www.sina.com.cn 2005年07月22日 10:59 天极yesky
 

  文/朱先忠编译

    把纹理链接到四边形上

  把纹理图像平铺到一个四边形上的常用方法是,把纹理的左下角链接到四边形的左下角,并以反时针方向指定其它链接。这种方法显示在图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()方法。而nextFrame()又调用JMFSnapper对象的getFrame()方法来以一个BufferedImage对象方式检索当前动画帧。该BufferedImage对象被指派给ImageComponent2D对象,然后用于四边形的材质。nextFrame()的代码如下所示:

//全局变量
private Texture2D texture; //由四边形使用
private ImageComponent2D ic;

private JMFSnapper snapper;
//快照该动画
private boolean isStopped = false;
//动画停止了吗?

public void nextFrame()
{
 if (isStopped) //动画已经停止
  return;

 BufferedImage im = snapper.getFrame();
 //获取当前帧
 if (im != null) {
  ic.set(im); //把该帧指派给ImageComponent2D
  texture.setImage(0,ic);
  //使成为该形状的材质
 }
 else
  System.out.println("Null BufferedImage");
}

    JMFSnapper对象snapper是在JMFMovieScreen的构造器中创建的:

//装载并播放动画
snapper = new JMFSnapper(movieFnm);

    JMFSnapper中的简单接口隐藏了用于播放动画和从动画中提取帧的JMF代码的复杂性。在本文的第二部分里,JMFSnapper类为一个使用QuickTime for Java的版本所取代,且JMFMovieScreen类也作了最少的修改。

  5.管理动画

  JMF为存取特定的动画帧提供了一种高级存取方式。下面的代码片断显示了该高级方式的主要组成,我略去了其中有关错误检测及异常处理的部分。

//在realized状态下,创建一个动画播放器
URL url = new URL("file:" + movieFnm);
Player p = Manager.createRealizedPlayer(url);

//生成一个帧放置器
FramePositioningControl fpc = (FramePositioningControl) p.getControl("javax.media.control. FramePositioningControl");

//创建一个帧抓取器
FrameGrabbingControl fg = (FrameGrabbingControl) p.getControl("javax.media.control.FrameGrabbingControl");

//要求改变到一个prefetched 态
p.prefetch();

//一直等待,直到播放器处于那种状态...

//移动到具体的某帧,例如第100帧
fpc.seek(100);

//取得当前帧的一个快照
Buffer buf = fg.grabFrame();

//取得它的视频格式细节
VideoFormat vf = (VideoFormat) buf.getFormat();

//用视频格式初始化BufferToImage
BufferToImage bufferToImage =new BufferToImage(vf);

//把缓冲区数据转化成一幅图像
Image im = bufferToImage.createImage(buf);

//指定想得到的BufferedImage的格式
BufferedImage formatImg =
new BufferedImage(
FORMAT_SIZE, FORMAT_SIZE,
BufferedImage.TYPE_3BYTE_BGR);

//把该图像转化成一个BufferedImage
Graphics g = formatImg.getGraphics();
g.drawImage(im, 0, 0,
FORMAT_SIZE, FORMAT_SIZE, null);
g.dispose();

    一个媒体播放器从创建到开始播放共经历6种状态。处于realized态的播放器知道如何对其数据进行着色,所以在要求时可以提供可视化组件和控件。我用了两个控件:FramePositioningControl 和FrameGrabbingControl

    FramePositioningControl提供seek()和skip()等方法,用于在一个动画中 移动以查找一个特别的帧。FrameGrabbingControl提供了方法grabFrame(),它可以从动画的视频轨道中抓取当前帧。

    为使这些控件工作,播放器必须实现从realized 态转入prefetched 态。这可以使播放器为进行媒体播放作好准备,并使媒体数据装入。

  对于prefetch()的调用是异步的,这意味着我的代码必须包含一个等待周期,直到完成一个变换状态为止。标准的JMF编码方案是实现一个waitForState()方法,它可以停止代码的执行,直到一个状态改变事件唤醒它。

  要抓取的帧可以用seek()方法在轨道中定位,然后调用grabFrame()方法实现帧的抓取。编码中必须经历多个转换步骤来把抓取的缓冲对象转换成JMFMovieScreen要求的BufferedImage对象。注意,BufferedImage对象使用了TYPE_3BYTE_BGR格式,这种格式对于该程序中的Java 3D部分通过引用方式使用纹理是必需的。

  Sun的JMF站点 包括了一些有用的小例子,其中Seek.java一例说明了如何使用FramePositioningControl来遍历一个动画。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值