本文是此系列两部分中的第 1 部分,介绍了 Mobile 3D Graphics API (JSR 184) 的有关内容。作者将带领您进入 Java 移动设备的 3D 编程世界,并展示了处理光线、摄像机和材质的方法。
作者:builder.com.cn 2007年8月24日
关键字:
在清单 1 中,您可以看到 VerticesSample 类,实现了上面提到的所有内容。
清单 1. 显示立方体的示例,第 1 部分:类成员
package m3gsamples1;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
/**
* Sample displaying a cube defined by eight vertices, which are connected
* by triangles.
*
* @author Claus Hoefele
*/
public class VerticesSample extends Canvas implements Sample
{
/** The cube's vertex positions (x, y, z). */
private static final byte[] VERTEX_POSITIONS = {
-1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1,
-1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1
};
/** Indices that define how to connect the vertices to build
* triangles. */
private static int[] TRIANGLE_INDICES = {
0, 1, 2, 3, 7, 1, 5, 4, 7, 6, 2, 4, 0, 1
};
/** The cube's vertex data. */
private VertexBuffer _cubeVertexData;
/** The cube's triangles defined as triangle strips. */
private TriangleStripArray _cubeTriangles;
/** Graphics singleton used for rendering. */
private Graphics3D _graphics3d;
VerticesSample 继承自 Canvas,应该能够直接绘制到屏幕。并且还实现了 Sample,定义它的目的是协助组织本文中的其他源代码示例。VERTEX_POSITIONS 以同样的顺序定义了与图 1a 相同的 8 个顶点。例如,顶点 0 定义为坐标(-1, -1, 1)。由于我将立方体的中心点放在坐标系原点位置处,因此立方体的各边长应为 2 个单位。随后,摄像机的位置和视角可定义一个单位在屏幕上所占的像素数。
仅有顶点位置还不够,您还必须描述出想要建立的几何图形。只能像逐点描图法那样,将顶点用直线连接起来,最终得到所需图形。但 M3G 也带来了一个约束:必须用三角形建立几何图形。任何多边形都可定义为一组三角形的集合,因此三角形在 3D 实现中应用十分广泛。三角形是基本的绘图操作,在此基础上可建立更为抽象的操作。
不幸的是,如果只能使用三角形描述立方体,就需要 6 条边 * 2 个三角形 * 3 个顶点 = 36 个顶点。这么多重复的顶点显然浪费了大量内存。为节约内存,首先应将顶点与其三角形定义分隔开来。TRIANGLE_INDICES 使用 VERTEX_POSITIONS 数组索引定义几何图形,使顶点可重用。然后用三角形带取代三角形,从而减少索引数量。通过使用三角形带,新的三角形可重用最后两个索引。举例来说,三角形带(0,1,2,3)可转换为两个三角形(0,1,2)及(1,2,3)。图 1a 的各角均已标注相应索引数,如果您在图 1a 的 TRIANGLE_INDICES 中遵循这一规则处理,就会发现两个面之间意外地多出了一些三角形。这只是一种用于避免定义某些三角形带的模式。我曾用一个有 14 个立方体索引的三角形带处理过 8 个顶点的情况。
使用其余的类成员即可绘制出立方体。清单 2 展示了其初始化方法。
清单 2. 显示立方体的示例,第 2 部分:初始化
/**
* Called when this sample is displayed.
*/
public void showNotify()
{
init();
}
/**
* Initializes the sample.
*/
protected void init()
{
// Get the singleton for 3D rendering.
_graphics3d = Graphics3D.getInstance();
// Create vertex data.
_cubeVertexData = new VertexBuffer();
VertexArray vertexPositions =
new VertexArray(VERTEX_POSITIONS.length/3, 3, 1);
vertexPositions.set(0, VERTEX_POSITIONS.length/3, VERTEX_POSITIONS);
_cubeVertexData.setPositions(vertexPositions, 1.0f, null);
// Create the triangles that define the cube; the indices point to
// vertices in VERTEX_POSITIONS.
_cubeTriangles = new TriangleStripArray(TRIANGLE_INDICES,
new int[] {TRIANGLE_INDICES.length});
// Create a camera with perspective projection.
Camera camera = new Camera();
float aspect = (float) getWidth() / (float) getHeight();
camera.setPerspective(30.0f, aspect, 1.0f, 1000.0f);
Transform cameraTransform = new Transform();
cameraTransform.postTranslate(0.0f, 0.0f, 10.0f);
_graphics3d.setCamera(camera, cameraTransform);
}