3d技术对我们来说已经非常熟悉了,最常用的3d api有opengl和microsoft的direct 3d,在桌面游戏中早已广泛应用。对于j2me程序而言,mobile 3d graphics api(jsr184)的出现,使得为手机应用程序添加3d功能成为可能。
jsr184标准(m3g:mobile 3d graphics)为java移动应用程序定义了一个简洁的3d api接口,j2me程序可以非常方便地使用m3g来实现3d应用比如游戏等等。m3g被设计为非常轻量级的,整个api的完整实现不超过150kb。
m3g是j2me的一个可选包,以opengl为基础的精简版,一共有30个类,运行在cldc1.1/cldc2.0上(必须支持浮点运算),可以在midp1.0和midp2.0中使用。目前,支持m3g的手机有nokia 6230/3650/7650/6600、siemens s65/cx65/s55/m55、sony-ericsson k700i/p800/p900、moto 220/t720等。m3g只是一个java接口,具体的底层3d引擎一般由c代码实现,比如许多手机厂商的3d引擎采用的便是superscape公司的swerve引擎,这是一个专门为移动设备设计的高性能3d引擎。
类似于microsoft的d3d,m3g支持两种3d模式:立即模式(immediate mode)和保留模式(retained mode)。在立即模式下,开发者必须手动渲染每一帧,从而获得较快的速度,但代码较繁琐;在保留模式下,开发者只需设置好关键帧,剩下的动画由m3g完成,代码较简单,但速度较慢。m3g也允许混合使用这两种模式。
3d模型可以在程序中创建,但是非常繁琐。因此,m3g提供一个loader类,允许直接从一个单一的.m3g文件中读入全部3d场景。m3g文件可以通过3d studio max之类的软件创建。
如果熟悉opengl,那么m3g是非常容易理解的。在m3g中,graphics3d是3d渲染的屏幕接口,world代表整个3d场景,包括camera(用于设置观察者视角)、light(灯光)、background(背景)和树型结构的任意数量的3d物体。3d对象在计算机中用点(point, pixel)、线(line, polyline, spline)、面(mesh)来描述,具体存储和运算(如旋转、投影)都是矩阵运算和变换。
sun的wtk2.2已经内置了m3g的实现包,如果安装了wtk2.2,就可以在模拟器上运行3d midp程序。可以参考wtk2.2的示例demo3d。
下面是一个最简单的m3g程序,来自sony-ericsson的示例代码,它创建一个旋转的金字塔,可以从 此处下载完整代码并在wtk2.2中运行。
首先,我们要获得唯一的graphics3d实例,用于渲染3d场景。graphics3d是一个singleton实现,可以在任何地方获得:
g3d = graphics3d.getinstance();
然后,在canvas中渲染:
public class mycanvas extends canvas
{
public void paint(graphics g) {
try {
g3d.bindtarget(g);
… update the scene …
… render the scene …
} finally {
g3d.releasetarget();
}
}
接下来创建一个world并设置camera:
world = new world();
camera = new camera();
world.addchild(camera);
// the width and height of the canvas.
float w = getwidth();
float h = getheight();
// constructs a perspective projection matrix and sets that as the current projection matrix.
camera.setperspective(60.0f, w / h, 0.1f, 50f);
world.setactivecamera(camera);
接着,在createpyramid()方法中创建一个mesh,代表金字塔,并添加到world中:
private mesh pyramidmesh; // the pyramid in the scene
pyramidmesh = createpyramid(); // create our pyramid.
pyramidmesh.settranslation(0.0f, 0.0f, -3.0f); // move the pyramid 3 units into the screen.
world.addchild(pyramidmesh); // add the pyramid to the world
最后,在一个线程中让金字塔绕y轴旋转起来:
public void run() {
graphics g = getgraphics();
while(true) {
// rotate the pyramid 1 degree around the y-axis.
pyramidmesh.postrotate(3.0f, 0.0f, 1.0f, 0.0f);
draw3d(g);
flushgraphics();
}
}
