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

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

Java 移动设备的 3D 图形4

摘要: Java 移动设备的 3D 图形4
照明

在一个没有光线的房间中,所有的东西看上去都是黑的。那么前面的示例中没有光线,怎么还能看到东西呢?顶点颜色和后面即将介绍的材质是不需要光线的,它们永远显示为定义好的颜色。但光线会使它们发生一些变化,可增加景深。

光线的方向会根据对象的位置发生反射。如果您用手电筒垂直地照射您面前的镜子,那么光线会反射到您身上。如果镜子是倾斜的,则光线的入射角和反射角是完全相同的。总的来说,您需要一个与照射平面相垂直的方向向量。这一向量就称为法线向量 或简称为法线。M3G 会根据法线、光源位置和摄像机位置计算着色情况。

此外,法线是各顶点都具备的属性,各顶点之间的像素着色既可采用插值法(PolygonMode.SHADE_SMOOTH)也可从三角形的第三个顶点处选取(PolygonMode.SHADE_FLAT)。由于立方体有 8 个顶点,支持法线的方法之一就是指定从立方体中心指向各角的向量,如图 7a 所示。但这样做可能会导致立方体着色不当。有三个面的颜色可能会相同,其中有些边成为不可见状态,使立方体看上去缺乏棱角。这显然更适合球体,不太适合立方体。图 7b 展示了如何为每边使用 4 条法线 —— 共 24 条,从而创建棱角分明的边线。由于一个顶点只能有一条法线,所以还要复制顶点。


图 7.带有法线向量的立方体:a) 8 条法线;b) 24 条法线(每边 4 条)


可使用法线计算光线后,还需要告诉 M3G 您需要什么类型的光线。光线来源于不同形式:灯泡、太阳、手电筒等等。在 M3G 中的对应术语分别为全向光、定向光和聚光。

全向光是从一个点发出的,并平均地照射各个方向。没有灯罩的灯泡发出的就是这样的光。
定向光向一个方向发出平行的光线。太阳离我们的距离非常远,所以可以将其光线视为平行的。定向光没有位置,只有方向。
手电筒或剧场中使用的聚光灯发射出的光线就是聚光。其光线呈锥形,与圆锥相交的平面上的对象会被照亮。
在真实世界中,光线还会从对象上反射回来而将周围照亮。如果您打开卧室灯,就会发现即便没有能直接照射到床底下的光线,但床下仍会被照亮。Raytracer 通过追踪从摄像机到光源的路径而清晰真实地展示了图像,但需要很长时间。要获得交互式帧频,必须满足一个简单的模型:环境光。环境光以不变的频率从各方向照亮对象。您可以用环境光模拟前面的卧室场景,将所有对象都照亮到一定程度,从而提供了另外一个全向光源。

清单 8 描述了设置不同光线的方法。


清单 8. 设置光线模式


// Create light.
_light = new Light();
_lightMode = LIGHT_OMNI;
setLightMode(_light, _lightMode);
Transform lightTransform = new Transform();
lightTransform.postTranslate(0.0f, 0.0f, 3.0f);
_graphics3d.resetLights();
_graphics3d.addLight(_light, lightTransform);

/**
* Sets the light mode.
*
* @param light light to be modified.
* @param mode light mode.
*/
protected void setLightMode(Light light, int mode)
{
switch (mode)
{
case LIGHT_AMBIENT:
light.setMode(Light.AMBIENT);
light.setIntensity(2.0f);
break;

case LIGHT_DIRECTIONAL:
light.setMode(Light.DIRECTIONAL);
light.setIntensity(1.0f);
break;

case LIGHT_OMNI:
light.setMode(Light.OMNI);
light.setIntensity(2.0f);
break;

case LIGHT_SPOT:
light.setMode(Light.SPOT);
light.setSpotAngle(20.0f);
light.setIntensity(2.0f);
break;

// no default
}
}


在图 8 中,您可以看到各种光线模式的不同效果。分别以 4 种类型的光照射示例立方体。这里的光线均为白色,就在摄像机前面,朝向立方体的三个面。



图 8. 使用不同的光线照射立方体 a) 全向光;b) 聚光;c) 环境光;d) 定向光


全向光在面对光源的顶点处最亮,然后逐渐暗淡下来。另外,聚光在聚光圆锥的边缘处制造了强烈的明暗对比。如果定义了一个足够大的光锥,那么所得到的结果可能与全向光相同。环境光从各个方向照亮立方体,立方体看上去是平的,这是因为缺乏阴影。最后,定向光使每面都具有不同的颜色。每面内的颜色都相同,这是因为光线是平行的。

照明并不精确,否则,聚光照亮的圆锥体范围应该是圆形。这是因为光线计算比较复杂,手机的部件将简化这一计算。可以为立方体的各边添加更多的三角形,从而提高其显示质量。尽管三角形并不能定义一个可见的几何图形,但可使 M3G 拥有更多的控制点(要计算的数量也更多)。









材质

通过光线可实现不同的效果。一个闪闪发光的银色球反射光线的方式与一张纸显然不同。M3G 使用以下属性为这些材质的特征建立模型:

环境反射:由环境光源反射的光线。
漫反射:反射光均匀地分散到各个方向。
放射光:一个像炽热的物体那样发射光线的对象。
镜面反射:光线从有光亮平面的对象反射回来。
您可为各材质属性设置颜色。闪闪发光的银色球的漫反射光线应该是银色的,其镜面反射部分为白色。材质的颜色与光线的颜色相融合,从而得到最终的对象颜色。如果您用蓝光照射银色球,那么球看上去应该略带蓝色。

清单 9 展示了使用材质的方式:


清单 9. 设置材质


// Create appearance and the material.
_cubeAppearance = new Appearance();
_colorTarget = COLOR_DEFAULT;
setMaterial(_cubeAppearance, _colorTarget);

/**
* Sets the material according to the given target.
*
* @param appearance appearance to be modified.
* @param colorTarget target color.
*/
protected void setMaterial(Appearance appearance, int colorTarget)
{
Material material = new Material();

switch (colorTarget)
{
case COLOR_DEFAULT:
break;

case COLOR_AMBIENT:
material.setColor(Material.AMBIENT, 0x00FF0000);
break;


case COLOR_DIFFUSE:
material.setColor(Material.DIFFUSE, 0x00FF0000);
break;

case COLOR_EMISSIVE:
material.setColor(Material.EMISSIVE, 0x00FF0000);
break;

case COLOR_SPECULAR:

material.setColor(Material.SPECULAR, 0x00FF0000);
material.setShininess(2);
break;

// no default
}

appearance.setMaterial(material);
}


setMaterial() 创建了一个新的 Material 对象,通过使用各颜色组件标识符的 setColor() 设置颜色。Material 对象随后被指派给 Appearance 对象,该对象用于调用 Graphics3D.render()。尽管这里没有展示,但您还可以使用 Material.setVertexColorTrackingEnable() 为环境反射和漫反射使用顶点颜色,不必使用 Material.setColor()。LightingMaterialsSample.java 这一示例中实现了光线和材质。按其中的键可以将不同的颜色与材质综合,感受不同的效果。

在图 9 中,用全向光展示了不同的材质特征。各截图都将颜色组件设置为红色,以突出表现其效果。



图 9. 不同的颜色组件:a) 环境反射;b) 漫反射;c) 放射光;d) 镜面反射


环境反射仅对环境光起作用,因此,使用全向光是无效的。漫反射材质组件会造成一种不光滑的表面,而放射光组件则制造出一种发光效果。镜面反射颜色组件强调了发亮的效果。此外,您还可以通过使用更多的三角形改进明暗对比的着色质量。






↑返回目录
前一篇: Java 移动设备的 3D 图形5
后一篇: Java 移动设备的 3D 图形3