这篇文章主要描述如何利用移动3d图形api(mobile 3d graphics api,m3g,又称为jsr-184)来建立一个3d的场景。
在这个3d场景的例子中,我们有一个活动的照相机(译者注:照相机就相当于观察者的位置),它聚焦在我们唯一的一个3d对象――一个旋转的棱锥上。源程序可以在本文的最后下载。
所有在场景中用到的对象都在m3gcanvas的构造函数中进行初始化。
我们首先建立一个graphis3d对象,并且利用它来渲染屏幕。world对象包含了所有在 场景中用到的对象和照相机的信息。
照相机利用setperspective方法设置在它前端的坐标系统中的0.1到50单位范围内的对象,都应该是可见的。
因为照相机和棱锥都定位在xyz(0.0f, 0.0f, 0.0f)的位置上,所以为了看到棱锥,我们必须把它移动到屏幕内。这个操作由mesh类里的settranslation方法完成。
//得到一个graphics3d的实例
g3d = graphics3d.getinstance();
world = new world();
//向world中增加camera
camera = new camera();
world.addchild(camera);
// canvas的宽和高
float w = getwidth();
float h = getheight();
//构造一个透视射影矩阵,并且设为当前的射影矩阵
camera.setperspective(60.0f, w / h, 0.1f, 50f);
//创建棱锥
pyramidmesh = createpyramid();
//将棱锥移动3个单位使其到屏幕内
pyramidmesh.settranslation(0.0f, 0.0f, -3.0f);
//将pyramid添加到world中
world.addchild(pyramidmesh);
world.setactivecamera(camera);
在这个例子中,最主要的3d对象就是在createpyramid方法中创建的棱锥(pyramid)。createpyramid方法中的代码相当的简单。
为了创建棱锥,我们首先指定需要用到的顶点。因为在这个例子中,我们必须为每一个顶点声明一种颜色。其中indices数组保存了points和colors的顺序。点1到点5的颜色依次是红色、绿色、蓝色、紫罗兰色和青色。
我们使用setshading(polygonmode.shade_smooth)方法实现很好的颜色渐变效果,如果每个侧面只有一种颜色,那么就指定shade_flat。
这个棱锥有6个三角形组成,其中每个侧面包含一个,底面包含两个。如果我们仅仅需要创建一个三角形,那么我们只需指定这个三角形所用到的三个顶点,下面的代码正展示了这一点。
// 一个三角形用到的顶点。 x, y, z
short []points = new short[] {-1, -1, 0, // 点1
1, -1, 0, // 点2
0, 1, 0}; // 点3
// 点和颜色的序列。
int [] indices = new int[] {0, 1, 2};
byte [] colors = new byte [] {127, 0, 0, //r
0, 127, 0, //g
0, 0, 127}; //b
// indices数组中每一个序列的长度。
int [] length = new int[] {3};
下面我们指定创建整个棱锥所需要的五个点。
// 棱锥用到的顶点. x, y, z
short []points = new short[] {-1, -1, 1, // 点1
1, -1, 1, // 点2
1, -1, -1, // 点3
-1, -1, -1, // 点4
0, 1, 0}; // 点5, 顶点
// 点序列
int []indices = new int[] {0, 1, 4, 1, 2, 4, 2, 3, 4, 3, 0, 4, 2, 1, 0, 2, 0, 3};
byte []colors = new byte[] {127, 0, 0, //r
0, 127, 0, //g
0, 0, 127, //b
127, 0, 127, //b
0, 127, 127}; //b
//indices数组中每一个序列的长度。
int []length = new int[] {3, 3, 3, 3, 3, 3}; // 棱锥由6个三角形组成
无论是创建一个三角形还是一个棱锥,下面的代码都是一样。
vertexarray position_array, color_array;
indexbuffer index_buffer;
// 创建一个被vertexbuffer用到的vertexarray
position_array = new vertexarray (points.length / 3, 3, 2);
position_array.set (0, points.length / 3, points);
color_array = new vertexarray (colors.length / 3, 3, 1);
color_array.set (0, colors.length / 3, colors);
index_buffer = new trianglestriparray (indices, length);
// vertexbuffer保存了对vertexarray对象的引用,而这些vertexarray对象可能包// 含了一系列顶点的位置、法线、颜色和纹理信息。
vertexbuffer vertexbuffer = new vertexbuffer ();
vertexbuffer.setpositions (position_array, 1.0f, null);
vertexbuffer.setcolors (color_array);
// 创建一个3d对象,定义为一个多边形的平面
mesh mesh = new mesh (vertexbuffer, index_buffer, null);
// 一个包含了定义mesh渲染特征的组件对象的集合。
appearance appearance = new appearance (); // a set of component objects that define the rendering attributes of a mesh
// 一个appearance组件,它封装了多边形级别的特征
polygonmode polygonmode = new polygonmode ();
polygonmode.setperspectivecorrectionenable (true);
// 通过使用cull_none棱锥的所有面都会显示
polygonmode.setculling (polygonmode.cull_none);
// 棱锥使用平滑的颜色渐变
polygonmode.setshading (polygonmode.shade_smooth);
appearance.setpolygonmode (polygonmode);
// 为3d对象设置外观(appearance)
mesh.setappearance (0, appearance);
下面我们重点看一下本篇文章中建立3d对象(棱锥)的过程。
1.这一步比较简单,指定棱锥用到的五个点。
2.建立一个点序列的indices 数组,这个数组中包含了顶点的信息,其中0到4依次和第一步中建立的点1到点5对应,对应关系如右图。
3.分别指定五个点对应的颜色信息,每个顶点都是按照rgb的顺序。在以上的步骤中请大家注意一点,就是每一步中的数组的类型。
4.指定一个length数组,它其中的元素是表示将对应的indices数组中元素划分为序列时,每个序列的长度。例子中的值是3,就表示indices中每三个元素作为一个序列。我们会发现,将indices中按照三个一组进行划分,所得到的每组序列刚好是组成一个三角形所需要的三个顶点。
5.使用vertexarray对象来保存顶点位置和颜色信息。vertexarray中三个参数的意义分别为:第一个是创建的对象中元素的个数,第二个是每个元素所包含的子元素数,第三个用来指定每个子元素所占的字节数。
6.使用trianglestriparray对象创建组成棱锥的三角面。trianglestriparray是indexbuffer类的子类,它是根据第二个参数将第一个参数也就是indices数组中的元素划为序列,组成三角面。在例子中是将indices中元素每三个划分为一个序列,刚好组成一个三角面。但是有时可能不是三个划分的,例如对于正方体我们可以定义length={4,4,4,4,4,4},这时indices中元素就会按照四个一组划分,于是这四个元素中的前三个先组成一个三角面,然后后面的两个元素交换位置和第四个元素再组成一个三角面,例如s=(2,0,1,4)就定义了两个三角面:(2,0,1)和(1,0,4)。另外trianglestriparray中的indices数组也可以隐式声明,即trianglestriparray(int, int[]),此时第一个参数指定了数组中起始元素,后面的元素依次加1递增。例如length={3,4},那么trianglestriparray(0, length)就相当于指定了indices={0,1,2,3,4,5,6}。
7.利用vertexbuffer保存位置和颜色信息,有时也可能会保存法线信息(setnormals)。
8.这是最后一步,使用mesh建立3d对象。这里mesh的构造函数有三个参数,第一个是顶点的相关信息,例如位置、颜色和法线等,第二个是组成3d对象的三角面或子mesh对象(并不是指mesh的子类或mesh对象)的信息,第三个是外观,appearance对象,如果在这里指定为null,那么在建立mesh对象以后,还可以通过setappearance设定。
下载源码第一个jsr 184 midlet
闽公网安备 35060202000074号