JSR184 是J2ME3D的核心规范,3D图形基本都是围绕此规范进行开发.
在CLDC建立3D模型的方法主要就是2种:1.编写静态多面体的空间位置数组进行构造多面体.2.利用外部工具构造立体图形然后导入到程序中.
两种方法各有优缺点.第一种方法适宜构造简单多面体,例如,立方体,凌锥体.运行速度快,资源占用少,有效缩小打包后程序的体积;第二种方法适宜建立比较复杂的模型,例如建立飞机,轮船,人物这些,\多边形数目较多的物体.结合Autodesk 3ds Max 这些软件,美工能快速地开发出模型.不足之处在于程序体积会变大,但是推荐使用此种方法,因为M3G的移植比较方便..
先总体介绍JSR184规范的大概内容:打开Mobile 3D Graphics API Document.
发现一共30个类.其中极其重要并且必然用到的类有: Appearance Background Camera Graphics3D group Image2D IndexBuffer Light Loader Mesh Node Object3D Sprite3D Texture2D Transform TransformAble TriangleStripArray VertexArray VertexBuffer World
其他类在一些特别效果下也会用到的例如KeyfameSequence,AnimationTrack.
3D图形整个结构就是这样的.因为3D图形就是多个面(Mesh)构成的.
下面介绍一下综合使用的例子:
实例一 : 构造简单立方体.
1. 立方体一共6个面8个顶点. 假设在3D立体空间中(0,0,0)表示原点位于立方体的最中心.我们就可以建立一下一种表示空间位置的数组.
这种定义位置数组的规则是有多个面是共用一个顶点的,此种定义法比较直观,从面个角度去考虑,兼顾法向量数组的定义.注意,定义点的顺序是有规律的,例如front面,0 1 2 够成一个三角形,1 2 3就构成另外一个三角形.刚好这两个三角形构成一个四方形面.如果是 0 1 3 2,构造一个面013,侧另外一个面 1 3 2 构成的三角形就会重叠的. (此是三角带建模的知识点)
VertexArray 目的就是把数组封装成点的形式,因为定义的POINTS[]还不过是一个数组而已,还不能代表空间点. 首先要定义一个pointasArray ,其内容包含 POINTS.length/3个顶点,每个顶点包含3个数据,1表示byte型的记录深度,2的话就表示是short的记录深度.
pointasArray Set()方法:0表示第一个顶点在POINTS中的位置是0, 封装的顶点数POINTS.length/3个,存储的顶点坐标数据的数组是POINTS.
VertexArray类就这两个重要的方法.
2. 定义好位置之后还不够.还要定义法向量. 当有光线照射到立方体的时候,远近不同的点的位置,自然有不同的效果, 理论上,每个面的法向量都是垂直于面的,例如top 面,其法向量自然就是Y轴,front面就是Z轴了.点的法向量理论上总是垂直于该点所处的切平面,但是空间的点切平面可以说是无限个又或者说没.因此我们自己设定它的法向量!(还有其他的方法).因为幸好我们之前定义的位置数组是按面来定义的,所以每个点都表示了3个面.因此我们可以定义每个面的四个点都朝向一个面法向量的方向.
3. 定义好法向量,就可以定义颜色了.J2ME中最常用的颜色模式就是RGB模式(还有其他的模式.) 用byte的深度去记录颜色16.77M色彩,J2ME领域中绰绰有余, 我的单反相机LCD才23w色.效果就一流了.
4除了颜色,还可以定义纹理,就是给立方体贴图.首先找到自己需要的图片,另外要记住立方体每个面所对应的图片的位置,记住4个点的坐标就可以了.图片推荐用PNG格式的,理由是,够用,够小,够快. 图片的位置是按照像素来记录的,图片左上角为(0,0)坐标都是正向的..图片大小推荐用16X16,32X32,64X64,128X128,256X256.再大或再小就不要用了.
4. 利用三角带建模的原理来把定义好的点串联成一个立方体. TriangleStripArray三角带序列.道理很简单.定义好的了点的位置了,就需要用一个循序去把点画好,这样才能使纹理贴图的时候有规律,否者纵使把点都画好,但是贴图都乱套也不行.
计算机绘图的时候都是绘制三角形的Triangle,利用无限多的Triangle去接近曲面, TriangleStripArray根据定义好序列(就是点的构造方向的序列),去组织三角形的绘制循序.
首先定义好序列(索引)INDICES(Index的复数).
先定义好INDICES索引,StripLengths三角带长度.两者相互配合的,StripLengths把INDICES分成六组,每组4个元素. TriangleStripArray构造的时候,根据StripLengths的每组取INDICES中的4个数据去构成一个面.一共构造6个面.
TriangleStripArray构造面就是构造三角形.这里定义了四个元素为一组(8,9,10,11),就是(8,9,10)构成一个面(9,10,11)构成了一个面.前三个点构成一个面后,后三个点构成一个面.
IndexBuffer是一个抽象类,TriangleStripArray是子类.TriangleStripArray就两个构造方法,作用都一样.这个好理解.
5. 然后要定义多面体的外观Appearance.因为要用到图片,所以先引入图片再说.在3D中,图片都归属于Image2D类.用图片去产生纹理Texture2D.
通常要引入file中的图片,都用到Loader类.Loader里面就2个静态方法.目的都是导入外部的Object3D()类.Loader的效率比Image.creatImage()方法快一些,用Image的导入的是Image还要用Image2D重新构造一次以变成Image2D的格式..
Texture中的方法解说:
SetBlendColor(int RGB);因为有的Image2D是透明的,设置透明部分的颜色;
SetBlending(int func);融合方式有5种.特殊要表现纹理特殊光泽的时候用.
SetFiltering(int leveFilter,int ImageFilter);滤波方式.滤波等级和图像滤波.影响性能.
SetWraping(int wrapS,int wrapT),s或t方向的重复或钳位.影响贴图的方法..
Appearance是要把fog material texture polygnmode compositingmode 的各项设置融合在一个,对外就表现为一个Appearance属性.然后添加到Mesh中的.
因为材质属性和雾化属性本人用的比较少(添加光线较多的时候,要表现一些特效的时候用),而且这2个影响机器性能比较大.所以我就只列出其他几个属性的设置.
6. 最重要的部分,就是Mesh如何把以上的东西都融合在一起构成一个立方体.
.
VertexBuffer 顶点缓冲.目的是把所有的顶点都归纳到VertexBuffer中.其中最重要的方法就是setNormals,setPositions,setTexCoords.方法.因为在本例子中,只用顶点和贴图.对法向量没要求,所以不用设置法向量也可以.当然设置发向量也会有不同的效果.读者可以试试.
解读一下setTexCoords(int index,VertexArray texCoords,floatScale,float[] bias).
index从纹理坐标哪个点开始的索引.通常都是从第一个点开始的.texCoords就是纹理坐标的vertexArray对象.scale是所有的纹理坐标共用的缩放因子.因为构造的面是边长都是2个单位的,而texCords所引用的图像实际在我这里是128X128.所以缩放.使纹理的像素于面构成适当的比例.读者可以试试,此比例按照2的倍数进行缩放.贴在面上的纹理也相应的变大变小.
7. 最终一步骤.构造Mesh.最重要的就是Mesh的构造方法.通过传入VertexBuffer,IndexBuffer,Appearance就能构造一个多面体(立方体)了.Mesh的实例直接就能在world中显示.
(完)
实例二.保留模式下构造3D场景.
1.Jsr184定义了一种M3G文件.此格式的文件保存,了Mesh,Light,Camera,World,Group,Appearance等内容.保留模式就是只在保存原来M3G文件内容不变的情况下,方便地从M3G文件中导出 Camera,Mesh等内容.
2.M3G的开发是通过 3DS MAX,或Maya,或Blender这些开发工具来建立的.美工的工作.
当file中有M3G文件的时候,如何导入呢.因为M3G文件中既有Mesh ,也有Camera,有Group,也有Light.我只需要某一样东西.怎么办?
3.用M3Gtoolkit这个工具打开M3G文件.能看到一个重要的信息.userID,并有个Value数.
在程序用直接更具value值就能找到你需要的Mesh.
4.利用Loader类来把M3G中重要文件导出.Loader中就2个重要的方法,而且是static的,不用实例化,直接用就是了.
5.1.首先,把M3G文件放到res文件夹中.用M3Gtoolkit查看这个文件中的需要用到的Object类的UserId值,知道需要用到哪个就记得哪个值.
5.2.然后在 程序用直接用Loader.load的方法打开文件,返回的是Object3D数组.此处有异常捕获.
loader返回的是一组Object3D对象,就是把里面的所有对象都分离了出来.
5.3.抽象类Object3D里面有个find(int userID)的方法,目的就是传入userID来找到对象.
在M3G文件结构中,必然有WORLD(Group的子类),而World又是在M3G中最上层,最先导出就是他,就是userID数值最小的(3dsmax自动分配userID的情况下).所以强制指定Object3D中第一个对象是Group,然后在Group(组节点)中找到需要的Mesh或者Camera之类.
5.4.在M3G中找到的Mesh或Light 等Object子类,不能直接就添加到程序(程序中的Group或World)中,应为每个节点都有一个唯一父节点,必须脱离父子关系才能变成其他节点的子节点.
介绍一个比较保险的方法:
5.5.这样就可以把Mesh等添加到其他的节点中了.
(完).