站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2ME 专题Java 移动设备的 3D 图形2

Java 移动设备的 3D 图形2

摘要: Java 移动设备的 3D 图形2
顶点颜色

创建 VertexBuffer 时,我曾提到可以为一个顶点指派多种类型的信息 —— 颜色也是其中之一。图形硬件是以流水线形式处理顶点的,就像工厂以流水线组装汽车一样。它逐个地对各顶点进行一系列的处理,直至各顶点都显示在屏幕上。在这一架构中,来自所有顶点的所有数据都必须同时可用。可以设想,如果组装工人必须每次从不同的地方取螺丝,效率该有多么低。

图 3 以平面布局展示了立方体的前五个顶点,还包括(R,G,B)格式的颜色信息。角上的数字同样是在三角形带中使用的索引。



图 3. 带有索引、顶点颜色和方位的三角形带


为顶点指派颜色对三角形内的像素会有什么影响呢?可能性之一就是为整个三角形使用同样的顶点颜色。另外还有可能在两个顶点之间插入颜色,实现颜色梯度效果。M3G 允许用户在这两个选项之间任选其一。在平面着色渲染模式下,可用三角形的第三个顶点颜色为整个三角形着色。如果您将图 2 所示第 1 个三角形定义为(0,1,2),则其颜色为红色(255,0,0)。在光影渲染模式下,三角形中的各像素都通过插值而获得了自己的颜色。索引 0 和 2 之间的像素初始颜色为绿色(0,255,0),渐变为红色。有些三角形共享索引 2 和索引 3 处的顶点,由于一个顶点只能有一种颜色,所以这也就意味着这些三角形也使用了一种相同的颜色。

图 3 还指出了索引的定义顺序。例如,(0,1,2)按逆时针方向定义第 1 个三角形的顶点,而第二个三角形为(1,2,3)是按照顺时针方向定义的。这就叫做多边形环绕。可以利用它来确定哪个面在前,哪个面在后。从正前方查看立方体时,您总是会认为自己看的仅仅是外部,但如果盒子能打开呢?您一定也想到里边去看看。立方体的每一面都有正反两面。默认地,逆时针方向表示正面。

但这里还有一个小小的问题:如图 3 所示,三角形带中的环绕在每个后续三角形处都会发生变化。按惯例,由三角形带中的第一个三角形定义其环绕。当我将一个三角形带环绕在清单 1 实现的整个立方体上时,首先从一个逆时针方向环绕的三角形(0,1,2)开始。通过这样的方式,也就隐式地将立方体的外部定义为正面,而将内部作为背面。根据具体的需求,您可以要求 M3G 仅渲染正面、仅渲染背面或同时渲染两面。如果立方体有一个半掩的盖子,您同时可看到其正面和背面,此时同时渲染两面的操作非常有用。如果可能,您应该禁用那些看不到的面,这样可以提高渲染速度。将三角形排除在渲染操作之外的方法称为背景拣出。

清单 4 示范了使用顶点颜色的方法。


清单 4. 各顶点都有颜色的立方体,第 1 部分:初始化顶点颜色


/** The cube's vertex colors (R, G, B). */
private static final byte[] VERTEX_COLORS = {
0, (byte) 255, 0, 0, (byte) 255, (byte) 255,
(byte) 255, 0, 0, (byte) 255, 0, (byte) 255,
(byte) 255, (byte) 255, 0, (byte) 255, (byte) 255, (byte) 255,
0, 0, (byte) 128, 0, 0, (byte) 255,
};


/**
* 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);

VertexArray vertexColors =
new VertexArray(VERTEX_COLORS.length/3, 3, 1);
vertexColors.set(0, VERTEX_COLORS.length/3, VERTEX_COLORS);
_cubeVertexData.setColors(vertexColors);

// 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});

// Define an appearance object and set the polygon mode. The
// default values are: SHADE_SMOOTH, CULL_BACK, and WINDING_CCW.
_cubeAppearance = new Appearance();
_polygonMode = new PolygonMode();
_cubeAppearance.setPolygonMode(_polygonMode);

// 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);
}

/**
* Renders the sample on the screen.
*
* @param graphics the graphics object to draw on.
*/
protected void paint(Graphics graphics)
{
_graphics3d.bindTarget(graphics);
_graphics3d.clear(null);
_graphics3d.render(_cubeVertexData, _cubeTriangles,
_cubeAppearance, null);
_graphics3d.releaseTarget();

drawMenu(graphics);
}


在类成员部分的 VERTEX_COLORS 中定义了各顶点颜色。将颜色放在 init()中全新的 VertexArray 内,并通过调用 setColors() 将其指派给 VertexBuffer。在这段代码中还初始化了一个名为 _cubeAppearance 的 Appearance 对象,_graphics3d.render() 使用该对象来更改立方体外观。PolygonMode 是 _cubeAppearance 的一部分,其中包含更改多边形级属性(包括显示哪些面)的方法。为交互地更改这些属性,我还在代码中增加了一个 keyPressed() 方法,如清单 5 所示。


清单 5. 各顶点都有颜色的立方体,第 2 部分:处理按键事件


/**
* Handles key presses.
*
* @param keyCode key code.
*/
protected void keyPressed(int keyCode)
{
switch (getGameAction(keyCode))
{
case FIRE:
init();
break;

case GAME_A:
if (_polygonMode.getShading() == PolygonMode.SHADE_FLAT)
{
_polygonMode.setShading(PolygonMode.SHADE_SMOOTH);
}
else
{
_polygonMode.setShading(PolygonMode.SHADE_FLAT);
}
break;

case GAME_B:
if (_polygonMode.getCulling() == PolygonMode.CULL_BACK)
{
_polygonMode.setCulling(PolygonMode.CULL_FRONT);
}
else
{
_polygonMode.setCulling(PolygonMode.CULL_BACK);
}
break;

case GAME_C:
if (_polygonMode.getWinding() == PolygonMode.WINDING_CCW)
{
_polygonMode.setWinding(PolygonMode.WINDING_CW);
}
else
{
_polygonMode.setWinding(PolygonMode.WINDING_CCW);
}

break;

// no default
}

repaint();
}

键位映射

示例中使用了 MIDP 的动作游戏作为处理按键事件的范例。其控制游戏动作的物理键映射到运行示例的设备上。Sun 的 Java Wireless Toolkit 将 LEFT、RIGHT、UP、DOWN 和 FIRE 映射为游戏操纵杆。GAME_A 映射为 1 键、GAME_B 映射为 3 键、GAME_C 映射为 7 键、GAME_D 映射为 9 键。


按下相应的键更改以下三个属性之一:渲染模式(平面着色渲染模式或光影渲染模式)、背景拣出(看见的是立方体的外面还是里面)、环绕(逆时针三角形表示的是正面还是背面)。图 4 展示了这些选项。VertexColorsSample.java 中包含该示例的完整源代码。



图 4. 经着色的立方体:a) 光影渲染模式;b) 平面着色渲染模式,背面被拣出;c) 正面被拣出,逆时针环绕





↑返回目录
前一篇: Java 移动设备的 3D 图形3
后一篇: 针对 Java 移动设备的 3D 图形,第 1 部分: M3G 的快速模式