这章用一个Java
D例子来描述一个
D跳棋
这个例子建立了一个场景
包括
由一个暗绿色和兰色格相交平铺的
并带有标签的X轴和Z轴形成的平面
一个兰色背景
一个可以在两个不同方向浮动的球体
用户可以通过鼠标来浏览(拉近放远)场景
左边的截图
显示最初视图
右边的图是用户视图移动一些之后的效果
Figure Initial view and later
D跳棋阐述了Java D编程中一些常用的方法和一些小窍门例如D场景使用CanvasD类来实现显示(这个类和Swing组件结合使用)所有的Java D程序需要一个场景图D跳棋说明了如何增加基本图形灯光背景这些场景图形成了文件的可视形式记录这些场景信息的文本版本通过Daniel Selman的JavadTree包很容易就能实现(在这节的最后我会详细介绍)
地板和球体使用了JavaD的QuadArray TextD and Sphere几何类地板是由QuadArray的一系列四边形组成标签是用TextD对象沿着地板上的主轴形成用户通过一个观察点查看这个D世界你将看到如何初始放置观察点在使用JavaD的OrbitBehavior 类时候如何移动观察点
D跳棋类图
图的类图说明了D跳棋程序的public和private数据项和方法
Figure Class diagrams for CheckersD
CheckersD 是程序的顶层JFrame WrapCheckersD 是场景图拥有的 JPanel 作为一个CanvasD 对象他是可视的 CheckerFloor 建立地板的子图(例如方格轴) with所有同颜色的方格用单独的ColoredTiles 对象表示
提示例子的原代码在CheckersD/目录(可能是原书附带光盘)
Java D和Swing 的结合
就向Swing文本和按纽CheckersD 是GUI控制位置的的一个 JFrame 把他放在必要的地方在这个例子中他建立一个WrapCheckersD (一个 JPanel) 实例并把他放在 BorderLayout 中间
csetLayout( new BorderLayout( ) );
WrapCheckersD wd = new WrapCheckersD( ); // panel for D canvas
cadd(wd BorderLayoutCENTER);
场景中的CanvasD 视图建立在WrapCheckersD 类里
public WrapCheckersD( )
{
setLayout( new BorderLayout( ) );
// other initialization code
GraphicsConfiguration config =
SimpleUniversegetPreferredConfiguration( );
CanvasD canvasD = new CanvasD(config);
add(Center canvasD);
// other initialization code}
虽然 CanvasD 是一个重量级的GUI 元素(一个系统产生窗口的轻量层)还是有一些必须注意的重量级的组件没那么容易与Swing控件组合(Swing是一个轻量组件)这些控件主要由Java产生如果 CanvasD 对象内嵌到一个 JPanel问题就可以消除并且建立出来的panel可以安全地和Swing程序的其他部分结合
提示: 这是在的一个关于结合 CanvasD 和Swing的详细讨论()
相比前几章这里没有update/draw循环因为Java D自身有机制来监视场景和最初视图的变化下面以伪代码给出算法
while(true) {
process user input; //用户输入
if (exit request) break;
perform behaviors;
if (scene graph has changed)//场景改变
traverse scene graph and render;//移动场景视图
}
其中的behaviors是一些影响其他部分图象的代码比如移动的图形或改变灯光他们用来监视图象传递给程序中非D部分详情详细代码比例子中的伪代码更加复杂Java D用多线程来并发移动和图形描述因此对这个过程有一个概括了解会对本章其他部分的理解有帮助
场景图形建立
场景图形用 WrapCheckersD的构造函数建立
public WrapCheckersD( )
{
// initialization code
GraphicsConfiguration config =
SimpleUniversegetPreferredConfiguration( );
CanvasD canvasD = new CanvasD(config);
add(Center canvasD);
canvasDsetFocusable(true); // give focus to the canvas
canvasDrequestFocus( );
su = new SimpleUniverse(canvasD);
createSceneGraph( );
initUserPosition( );// set users viewpoint
orbitControls(canvasD); // controls for moving the viewpoint
suaddBranchGraph( sceneBG );
}
CanvasD 对象用从getPreferredConfiguration( );获得的配置来初始化这个方法能取得硬件的图形信息一些老的Java D程序没有初始化一个GraphicsConfiguration 对象而是用null作为 CanvasD 的构造函数的参数这种编程可不太好canvasD 被设置成焦点以便键盘能传递动作给场景图形这些动作的触发通常是按键的按压和弹起但是他们也能由定时器帧的改变和由Java D内部产生的事件触发 CheckersD就不需要设置焦点因为他没有任何动作因为在所有的其他程序中我们都会考虑到线条所以我没有给出线条的描绘代码
su SimpleUniverse 对象建立了标准子视图场景图形的VirtualUniverse 和Locale 节点
createSceneGraph( ) 设置了灯光天空的背景地板还有浮动球体initUserPosition( ) 和 orbitControls( ) 处理用户视角问题最后把配置好的 BranchGroup 加入到方法
private void createSceneGraph( )
{
sceneBG = new BranchGroup( );
bounds = new BoundingSphere(new Pointd() BOUNDSIZE);
lightScene( ); // add the lights
addBackground( );// add the sky
sceneBGaddChild( new CheckerFloor( )getBG( ) );// add floor
floatingSphere( ); // add the floating sphere
pile( ); // fix the scene
} // end of createSceneGraph( )
使用不同的方法来增加子图到 sceneBG以建立需要的子视图一旦图形被绘制完毕后并允许JavaD来优化他sceneBG 便只被编译一次优化包括重排图形重新组合编译节点例如一连串的包含不同转换的TransformGroup 节点会被编译成一个独立节点另一个可能的优化是把具有相同显示属性的图形编成组以便能更快地描绘
bounds是一个 BoundingSphere 类的全局实例他用来指定环境节点对灯光背景和OrbitBehavior 对象的影响跳跃的球体被放在场景的中心被赋 BOUNDSIZE 单位半径并影响场景中所有事件
最后的 WrapCheckersD( ) 所显示的场景图象在图中Floor Branch 节点是我发明出来掩藏一些细节稍后将会涉及图所缺少的是场景图形的分支部分
场景灯光
通过 lightScene( )把一个环境灯光两个有向灯光加入到场景中环境灯光能到达场景中的每个角落并且强度相同
Colorf white = new Colorf(f f f);
// Set up the ambient light
AmbientLight ambientLightNode = new AmbientLight(white);
ambientLightNodesetInfluencingBounds(bounds);
sceneBGaddChild(ambientLightNode);
代码设置了灯光的颜色
环境灯光以bounds配置建立
并加入到场景中
类 Color
f( ) 的构造函数设置RGB颜色为
f到
f(
f是全色)
有向灯光模拟的一个从原处照射来的一束灯光并从特定方向碰上物体表面有向灯光和环境灯光的区别是有向灯光必须是方向向量
Vectorf lightDirection= new Vectorf(f f f);
// left down backwards
DirectionalLight light =new DirectionalLight(white lightDirection);
lightsetInfluencingBounds(bounds);
sceneBGaddChild(light);
Figure Partial scene graph for CheckersD
方向是介于()和()的向量灯光可以想象成是很多从不同方向不同来源的平行灯光汇聚而成点光和场光是Java D灯光的另外一种形式点光放置在空间中并向所有方向发射场光以特定方向朝点光聚焦
场景的背景
场景的背景可以指定为特定的背景(如下所示)一个静态图像或这是一个带形体的几何材质
Background back = new Background( );
backsetApplicationBounds( bounds );
backsetColor(f f f);// sky color
sceneBGaddChild( back );
浮动的球体
Sphere 是来自Java D的 comsunjdutilsgeometry 包的一个工具类是Primitive 类的一个子类Primitive 类为带有 ShapeD 孩子节点的一个 Group 节点他的几何特性存储在Java D的 TriangleStripArray这种类把球体看成一组可连接的三角形体我没必要校准他的几何特性但是他的现实和位置要改变
Appearance 节点是一个包含很多信息的容器包含颜色线条点多边形描绘透明度和材质特性ColouringAttributes 确定形体的颜色而且不受场景灯光影响如果一个形体需要颜色和灯光的交互作用就要用到 Material 组件灯光要影响形体的颜色必须满足三种情况
;形体的几何特性必须是标准的
;形体的 Appearance 节点必须拥有 Material 组件
;Material 必须用 setLightingEnable( )打开他的光照允许
用工具类 Sphere 能自动制作成标准形体所以第一种情况容易满足
形体颜色
Java D Material 组件控制当一个形体被不同种类的灯光照射后的颜色
Material mat = new Material(ambientColor emissiveColor
diffuseColor specularColor shininess);
环境颜色参数指定当形体被环境灯光照射后的颜色
他给对象统一的颜色
放射性颜色贡献形体生成的颜色
这个参数经常被设置成黑色(相当于关闭)
当照射的时候
发散颜色就是对象的颜色
他的强度取决于光波照射到形体的角度
提示发散灯光和环境灯光通常被设置成相同这与真实世界中的对象被照射时候的颜色一样
镜子颜色参数的强度与从形体的光亮区域反射出的多少有关他由控制reflective highlight尺寸的发光参数组合成
提示镜子颜色通常设置成白色符合真实世界中大部分对象产生的颜色
CheckersD类中有两个不同方向的光他们在球体顶部建立了两个不同的光路(如图)地板在他们的颜色未在形体的几何特性中设置前是没有被照射到的
floatingSphere( ) 中处理形体现实的代码如下
Colorf black = new Colorf(f f f);
Colorf blue = new Colorf(f f f);
Colorf specular = new Colorf(f f f); // near white
Material blueMat= new Material(blue black blue specular f);
blueMatsetLightingEnable(true);
Appearance blueApp = new Appearance( );
blueAppsetMaterial(blueMat);
布置形体形体放置一般是在TransformGroup 下放置图形节点(参见图 sphere Group)一个 TransformGroup 用来放置旋转和度量旗下节点他由Java D TransformD 对象定义其格式
TransformD td = new TransformD( );
tdset( new Vectorf()); // place at ()
TransformGroup tg = new TransformGroup(td);
tgaddChild(new Sphere(f blueApp));
// set the spheres radius and appearance
// and its normals by default
sceneBGaddChild(tg);
set( ) 方法将形体的中心放置在()重置先前的旋转和度量在重置其他格式的时候set( ) 能用来改变度量和角度方法setTranslation( ) setScale( )和setRotation( ) 只能对已给格式起作用
与其他D画图程序包不同的是Java D中的Y轴是垂直方向而水平面由xoz决定如图球体的位置被设置为()在XOZ面中心上方个单位
图Java D中的坐标系
完请等待Part