在这里我首先感谢大家对上一篇文章的支持,也正是有了大家的支持,我决定把我的Mobile3D学习过程拿出来和大家共享,希望大家能一起来讨论Mobile3D
在上一次的教程中我为您详细的介绍了,在Moble3D中通过及时运算建立3D图形,并且对从*.m3g文件中导入模型做了一个简单的介绍,这次我想在这里通过*.m3g文件的使用简单的介绍一下Mobile3D对动画的控制,以及对模型的一些操作。
首先我来简单的说一下m3g文件的建立,这个其实很简单,你只需要选择一种你所熟悉的3D图形制作软件,并安装对应的插件即可,在这里我使用的软件是MAYA和3DS MAX,插件使用的是H3T Export Plugin,该插件有maya和3ds max的,同时还需要下载一个软件M3G Tools kit。这些都可以从Sony Ericsson的网站上找到连接。插件的安装应该都没问题吧。插件安装完成后,就可以建立模型、设置材质帖图、设置摄影机、设置关键帧等等了,最后只要输出成H3T文件即可。然后再打开M3G Tools kit将h3t文件输出成m3g文件就可以了。在使用m3g文件之前最好用M3G Tools kit浏览一下该文件,为的是记录对应的信息,例如userid和该场景的树状结构等信息,这些都是非常重要的哦~如果你这样做了,你会发现这样导出的m3g文件中camera并没有在world树下,而是和world树是平级的。其实上一篇文章中我也说过,camera和渲染信息可以不被放在world树下,但是所有的模型信息必须被放到树下。当我们看m3g文件的时候比较重要的是看清楚world节点所在的位置,以及需要我们操作的模型的userid。
准备工作差不多了,现在来看Mobile3D吧,在上一文章中我说过m3g文件使用通过javax.microedition.m3g.Loader.load(String url)载入的,而且该方法返回的是javax.microedition.m3g.Object3D的数组,也许有人要问既然world是根节点,那么为什么不直接返回一个World呢?刚才让大家看m3g文件的结构的时候就已经说明了摄影机和动画设定等等并没有被放到World为节点的书中,而是和World节点同级的。而World节点是场景的根节点才对。那么我们如何才正确的取出World节点呢?方法有两个
1。遍历该Object3D数组,并比较每个元素的userid如果正式World节点的useid将该元素取出。
2。遍历该Object3D数组,并比较每个元素是不是World类的实例,那么既然World节点是场景的根节点,那么在该Object3D数组中也应该只有一个World类的实例对象。
第一个方法比较简单,我在这里只给出第二个方法的片断代码。(其实是一样的)
private void loadWorld(){
System.out.println("now loading...");
try{
buffer=Loader.load("/img/TmpMicroFile.m3g");
for(int i=0;i<BUFFER.LENGTH;I++){
if(buffer[i] instanceof World){
world=(World)buffer[i];
return ;
}
}
}catch(Exception e){
buffer=null;
System.out.println("thorw a exception when loading");
e.printStackTrace();
}
}
然后我们设置摄影机,不同的是,这次我们从World中获得摄影机信息,获取后我们可以对其进行一些基本的设置这里不细说了。下面着重的说一下动画的部分。
在我们导入这个m3g文件时候我们其实已经有了动画的信息了,并且这些动画信息有可能是很复杂的,我测试了连杆两轴的运动可以没问题,从一些资料上看到的IK反向运动也没有问题。也许你已经着急了,怎么还不说如何控制动画的播放呢?简单的说World.animate()来更新动画信息,这个方法需要传进去一个int类型的参数,当你第一次调用该方法的时候,系统会记录下这个数值,后面每次调用的时候都会和这个数值相比较,然后系统替我们计算出动画更新到什么位置,同时该方法会返回一个int类型的参数,这个参数表示的下一次更新的一个建议的数值(是以毫秒为单位的)。我们这时就可以让调用这个方法的线程休眠这个时间,以便下以次更新动画数据。这里也许你会有疑问,我的动画明明只有几十帧,可是这里却反复的播放;这虽然是个好消息,但在有很多情况播放的长度、什么时候播放,都需要我们自己来控制怎么办?这时候我们就需要用到javax.microedition.m3g.AnimationController类了,其实每个动画中的每个可以动的模型都有自己的AnimationController对象,和模型动画一样我们可以通过World.find(int controllerID)来获得,在该类中我们可以通过setActiveInterval(int activeTime,int unactiveTime)来设定动画在该系统中播放的起始和重点时间,另外通过setPosition(int startTime,int endTime)方法控制这个动画需要播放哪一段落。很抱歉有关两个方法的时候在这次教程实例中我并没有使用,不过如果您想了解关于这两个方法的使用,我建议你看看WTK2.2的那个Demo3D中袋鼠的例子,那里面写的挺详细的。
这里呢我给出动画和绘制的代码片断吧
protected void paint(Graphics g) {
startTime= System.currentTimeMillis() - worldStartTime;
validity= world.animate((int)startTime);
perFrameTime=(int)System.currentTimeMillis();
g.setColor(0x00);
g.fillRect(0,0,getWidth(), getHeight());
g.setClip(0,0,getWidth(),getHeight());
g3d.bindTarget(g,true,Graphics3D.DITHER|Graphics3D.TRUE_COLOR);
g3d.setViewport(0,0,getWidth(),getHeight());
g3d.render(world);
g3d.releaseTarget();
framePor=(int)1000/((int)System.currentTimeMillis()-perFrameTime);
System.out.println("3D demo frame/sn:"+framePor);
if(validity < 1)
{ // The validity too small; allow a minimum of 1ms.
validity = 1;
}
if(validity == 0x7fffffff)
{ // The validity is infinite; scehdule a refresh in 1 second.
validity=1000;
}
}
public void run() {
while(isRun){
repaint();
try{
Thread.sleep(validity);
}catch(Exception e){}
}
}
这里如果你不喜欢使用线程的话,你可以换成Timer。个人喜好问题吧,我对线程比较熟悉,所以这里我使用的是线程。
动画似乎我现在也只理解到这些,全部和大家共享出来了。下面我想说一说Transformable类中的几个方法。首先来介绍一下Transformable类吧。Transformable类是很重要的一个类,Node就是它的子类,呵呵……知道它的重要性了吧。Transformable中有四个方法是今天我要简单说一下的
postRotate(float, float, float, float)放是和物体的旋转有关系的在Mobile3D中默认所有的物体的旋转轴都在自身的中心,所以对物体进行旋转操作的话,一定是自转,而不是绕某个点、或某个轴公转,这一点一定要弄清楚。也许这样说有些抽象那么我换个说法,就是这里的旋转只改变物体的朝向,并不改变物体的位置。这下明白了吧,也许有人要问“这不正是我们需要的吗?为什么要强调呢?”原因其实是这样的,在有的3D引擎中,旋转是以原点为基础的。也就是说如果需要做自转运动,就必须做移动、再旋转、再移动这样的操作,其实这样做的好处是可以方便点的运算,因为点不存在自转的概念。而我们的Mobile3D在某种程度上说是不可以对点操作的,所以它的最小单位是Mesh,那么它如何实现自转呢?来看个矩阵你就明白了
90,0,0,0
0,0,0,0
0,0,1,0
0,0,0,0
这个矩阵表示的当前的模型在Y轴上有90度的旋转。现在我们回头来看看postRotate(float a, float x, float y, float z)方法,其中有4个参数,第一个就是这次需要旋转的角度,后三个其实一个这次旋转的轴,是通过一个向量来表示的,postRotate方法就是在原来的朝向上继续进行新的旋转,如果用数学公式来表示的话就是使用原有的矩阵乘以
a,0,0,0
0,x,0,0
0,0,y,0
0,0,0,z
这个矩阵就是新的方向矩阵
这个方法如果从数学角度听起来很难理解的话,你只要记住四个参数第一个是这次旋转的角度,后三个确定旋转轴
同postRotate方法类似的是setOrientation(float a, float x, float y, float z)不同的是这次不再是旋转了而是直接设置到这个朝向
说过旋转再来看看移动,这个似乎就简单很多了translate(float x, float y, float z)这个就是指按照指定的向量平移;setTranslation(float x, float y, float z)这个更简单了,直接移动到指定的位置。
其实还有一个方法scale(float sx, float sy, float sz)是用来进行缩放的,同样还有setScale(float sx, float sy, float sz)直接设置比例尺,这个六个方法是对物体进行直接的操作的,非常有用哦~尤其是前四个,在编写游戏的时候会经常用到,而后两个使用的频率似乎少一些,因为很多时候我们都是直接对摄像机的距离进行操作的(除非有特殊需要)。
下面我给出个使用前四方法的举例例子吧。
public void keyPressed(int keycode){
float[] camerTra;
float x;
float z;
switch(keycode){
case GameCanvas.DOWN:
break;
case GameCanvas.UP:
break;
case 52:
dir=dir-2;
System.out.println(dir);
x=(float)(3*Math.sin((dir * 3.14159f) / 180.0f));
z=(float)(3*Math.cos((dir * 3.14159f) / 180.0f));
camera.setTranslation(x,0,z);
camera.setOrientation(dir,0,1,0);
camerTra=new float[3];
camera.getTranslation(camerTra);
for(int i=0;i<CAMERTRA.LENGTH;I++){
System.out.print(camerTra[i]+" ");
}
System.out.println();
camerTra=new float[4];
camera.getOrientation(camerTra);
for(int i=0;i<CAMERTRA.LENGTH;I++){
System.out.print(camerTra[i]+" ");
}
System.out.println();
break;
case 54:
dir=dir+2;
System.out.println(dir);
x=(float)(3*Math.sin((dir * 3.14159f) / 180.0f));
z=(float)(3*Math.cos((dir * 3.14159f) / 180.0f));
camera.setTranslation(x,0,z);
camera.setOrientation(dir,0,1,0);
camerTra=new float[3];
camera.getTranslation(camerTra);
for(int i=0;i<CAMERTRA.LENGTH;I++){
System.out.print(camerTra[i]+" ");
}
System.out.println();
camerTra=new float[4];
camera.getOrientation(camerTra);
for(int i=0;i<CAMERTRA.LENGTH;I++){
System.out.print(camerTra[i]+" ");
}
System.out.println();
break;
}
}
呵呵……上面简单的对动画的播放和设置,以及对物体进行操作的说明,希望对你能有所帮助,其实现在的内容已经可以写出一个简单操作人物移动的游戏了或者是操作遥控汽车的游戏,还缺少的是碰撞的检测。不过由于时间的关系,我还没有写这样的东西,稍候一定整理一下写个遥控车什么的游戏,这里还是前把这次的代码给大家,另外稍候我会制作一个人物走动的动画,如果能控制m3g文件在合适的大小我会上传给大家做个素材吧。
源码
分享到:
相关推荐
本教程专注于J2ME的3D开发,旨在帮助中国开发者轻松入门移动3D开发领域。 教程内容源自Sony Ericsson Mobile Communications AB,涵盖了JSR-184和Mascot Capsule v3两个关键标准,它们都是为了在J2ME平台上实现3D...
例如,使用二维图形的组合和变换模拟3D效果,或者使用开源库如J3D,该库基于OpenGL ES,可以在J2ME平台上实现硬件加速的3D渲染。 **3. 游戏资源管理** 在J2ME游戏中,资源管理至关重要,因为移动设备的内存和处理...
本教程“J2ME手机游戏编程入门 示例”旨在帮助初学者掌握J2ME的基本概念,并通过19个具体的示例进行实践,从而快速入门游戏开发。 一、用户界面交互 J2ME中的用户界面主要依赖于MIDP(Mobile Information Device ...
掌握J2ME的基础后,可以进一步学习KJava、JSR规范(如JSR-184的3D图形支持)以及如何优化MIDlets以适应资源有限的设备。 总的来说,"J2ME入门最基础的资料"将引导初学者逐步理解J2ME的结构、API、开发流程和实践...
尽管3D游戏在J2ME上具有挑战性,但这个教程可能会提供一些实用的技术和工具,如J3D库,以简化3D游戏的实现。开发者可能学习到如何创建3D场景、物体以及如何处理复杂的3D运算。 J2ME的开发不仅需要理解Java语言的...
JSR172 入门》、《[索尼爱立信] 创建游戏音乐和声效》、《[索尼爱立信] 基于 JavaME 平台的移动 3D 编程》、《[索尼爱立信] 使用 Java Platform MicroEdition 的 3D 图形》、《[索尼爱立信] 手机 Java ME 的许可权限...
《J2MEMIDP编程指南》是一本专为手机Java开发初学者设计的入门教程,旨在帮助读者快速掌握J2ME(Java 2 Micro Edition)平台下的MIDP(Mobile Information Device Profile)应用开发技术。J2ME是Oracle公司推出的...
- **解决方案:** 采取了折中的方法,即保持策划文档的日常更新,并在时间充裕时轮换进行J2ME(Java for Mobile)和Direct3D (D3D) 相关内容的开发。 **技术选择:** - **C++与Windows API:** 由于C++及Windows ...
在"Mobile 3D学习代码"这个压缩包中,很可能是包含了针对移动平台(J2ME)的3D编程实例。J2ME是Java Micro Edition的缩写,主要用于嵌入式设备和移动设备,如手机和平板电脑。虽然Java 3D最初设计用于桌面应用,但...
尽管现在有更多先进的开发平台如Android和iOS,但J2ME的简单性和跨平台性使其在教育和入门级项目中仍然具有价值。 1.3 关于J2ME J2ME是Java平台的一个子集,专为资源有限的嵌入式设备设计,如手机和PDA。它包括一套...
1. **基础篇**:介绍J2ME开发环境的搭建,如MIDP(Mobile Information Device Profile)和CLDC(Connected Limited Device Configuration)的理解,以及NetBeans或Eclipse等IDE的使用。 2. **图形与动画**:讲解...
2. **MIDP (Mobile Information Device Profile)**:J2ME的核心部分,定义了移动设备上应用程序的基本框架。 3. **CLDC (Connected Limited Device Configuration)**:针对低内存设备的配置,与MIDP一起用于构建J2ME...
----------------------------...• 优化的图形库 包括定制的 2D 图形库, 3D 图形库基于 OpenGL ES 1.0 (硬件加速可选) • SQLite SQLite SQLite SQLite 用作结构化的数据存储 • 多媒体支持 包括常见的音频、视频和...
3. **图形与动画**:游戏中的图形和动画是通过Java的图形API实现的,如AWT和Swing,或者在J2ME中使用MIDP(Mobile Information Device Profile)的Canvas类。学习如何绘制图形,创建精灵,以及实现帧动画是游戏开发...
本资料主要针对的是初学者,通过“Java手机_PDA程序设计入门_0”这一章节,将引导读者逐步掌握Java在移动设备上的应用开发。 在Java手机游戏开发中,开发者需要理解Java ME(Micro Edition)平台,它是Java专门为...
2. **MIDP (Mobile Information Device Profile)**:建立在CLDC之上,为移动设备提供了一套应用程序框架,包括用户界面组件、网络连接支持和数据存储功能。MIDP主要用于开发移动应用,如游戏、信息服务等。 3. **...