王朝网络
分享
 
 
 

J2MEMobile3D入门教程系列文章之二

王朝java/jsp·作者佚名  2008-05-31
宽屏版  字体: |||超大  

在这里我首先感谢大家对上一篇文章J2ME Mobile 3D入门教程系列文章之一的支持,也正是有了大家的支持,我决定把我的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;iif(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.DITHERGraphics3D.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)

(出处:http://www.knowsky.com)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有