TWaver MONO Design

  1. MONO Design
  2. 镜头、动画、巡航、告警、polygon offset

使用镜头

在图形学中,相机的概念不同于我们日常生活中的相机,mono创建的场景是三维的,但是通常情况下我们的显示屏是二维的,如何把三维的场景显示到二维的显示屏上呢?相机就是用来做这件事的,相机定义了三维空间到二维屏幕的投影方式,mono中采用的是透视投影相机。使用透视投影镜头获得的结果是类似人眼在真实世界中看到的“近大远小”的效果。

相机的构造函数:mono.PerspectiveCamera (fov, aspect, near, far )

可以通过以下两幅图去了解相机各个参数的含义,透视图中绿色部分是视景体,是可能被渲染的物体所在的区域,

  • fov 是视景体在竖直方向上的张角,如下图的侧视图所示。
  • aspect 等于 width / height,是照相机水平方向和竖直方向长度的比值,通常设为canvas的横纵比例。
  • nearfar 分别是照相机到视景体最近、最远的距离,均为正值,并且 far 应大于near

透视图:
camera
侧视图:
camera1

以下代码展示了相机的使用,首先创建一个相机,竖直方向的张角为30度,(注意:这里的张角为角度制)照相机水平方向和竖直方向的长度比值为1.5,照相机到视景体最近距离为0.1,最远距离为1000。我们注意到代码中有两个方法,setPositionlooksetPosition 用来设置相机的位置,如果我们不进行设置,相机默认的位置是(0,0,0),look 用来设置相机的观察方向,如果不进行设置的话,默认是 Vec3(0,0,0),(注意:此处的单位是Vec3),代码中的相机观察方向是从 (-800,800,-800) 到 (0,0,0)。

var camera = new mono.PerspectiveCamera(30, 1.5, 0.1, 10000);
camera.setPosition(-800,800,-800);
camera.look(new mono.Vec3(0, 0, 0));

接下来我们看一下 fov 的改变对渲染效果的影响,以下两幅图片是 fov 的值分别为 30 和 60 时的效果,我们会发现 fov 的值变大,立方体反而显得更小了,其实立方体的实际大小并未改变,当我们把照相机的竖直张角设置得更大时,视景体变大了,因而立方体相对于整个视景体的大小就变小了,看起来立方体就显得变小了。

张角为30度时的渲染效果图:

cube2

张角为60度时的渲染效果图:

cube3

特别提出的是,mono中提供了addChild()方法,为camera添加一个子对象。例如我们想实现灯光Light和camera的position一起移动,像手电筒一样的效果,可以使用camera.addChild(light),light为自定义的灯光。

使用动画

Mono提供了内置的动画支持。使用mono.Animation可以方便的驱动各种动画效果。类定义如下:

mono.Animation =function(element, startValue, endValue, duration, callback)

其中:

  • element – 发生动画的3D对象
  • startValue – 动画要驱动的数值开始值。例如,沿x轴从0度旋转至90度,则开始值是0度
  • endValue – 动画要驱动的数值结束值。例如,沿x轴从0度旋转至90度,则结束值是90度
  • duration – 动画帧插入的时间间隔,单位是毫秒(1/1000秒)。如果设置了该值,则表示network刷新一帧后,会强行等待指定时间,再进行下一帧的绘制。数值越大,动画越慢、不流畅,但CPU负载越低。反之,动画会更加流畅,但负载会更大。设置为0则会全速渲染
  • callback – 动画结束时的回调函数。例如,可利用该机制在动画结束后继续重复播放

主要方法

  • play: function () – 开始播放动画
  • function getAllAnimationTypes() – 获得所有支持的动画类型
    • ‘LeftMove’ – 向左移动
    • ‘RightMove’ – 向右移动
    • ‘FrontMove’ – 向前移动
    • ‘BackMove’ – 向后移动
    • ‘LeftRotationClockwise90′ – 以左侧为中心顺时针旋转90度
    • ‘LeftRotationAnticlockwise90′ – 以左侧为中心逆时针旋转90度
    • ‘LeftRotationClockwise120′ – 以左侧为中心顺时针旋转120度
    • ‘LeftRotationAnticlockwise120′ – 以左侧为中心逆时针旋转120度
  • function playAnimation (element, animation) – 为指定对象播放指定类型的动画
  • function playAlarmAnimation(element, alarmBillboard) – 为指定对象播放告警动画。alarmBillboard是一个表示告警样式的公告牌对象,可按喜好进行定义

使用自动巡航

自动巡航是一种动画,主要是自动控制镜头沿着预定义好的轨迹进行移动,产生“自动巡视”的效果。可以应用于各种机房的自动巡查、设备巡视等。

通过mono.Inspection类可以创建自动巡航应用。Inspection最主要的参数是一个轨迹点数组,数组中每一个点代表需要巡视的一个3D空间点。在运行时镜头会沿着这些点定义的轨迹进行移动。

new inspection = new mono.Inspection(network, defaultInteraction, points, callback, callbackDelay);
  • network – network对象
  • defaultInteraction – network上设置的DefaultInteraction。它会控制用户交互时的镜头目标点,因此这里需要指定它
  • points – 巡航点数组。数组中每一个点都是一个mono.Vec3(x,y,z)实例
  • callback – 巡航结束后的后续动作,是一个回调函数
  • callbackDelay – 巡航结束后,延迟多少时间(毫秒),再执行后续动作(回调函数)

下面代码演示了如何使用Inspection创建轨迹,并进行播放。代码中,巡航结束后,延迟2秒自动重复巡航。代码如下:

var playInspection = function() {
	var points=new Array();
	points.push(new mono.Vec3(1000,500,1000));
	points.push(new mono.Vec3(500,250,500));
	points.push(new mono.Vec3(500,100,-500));
	points.push(new mono.Vec3(-500,100,-500));
	points.push(new mono.Vec3(-500,100,600));
	points.push(new mono.Vec3(300,100,300));
	points.push(new mono.Vec3(250,100,250));
	
	var inspection = new Inspection(network, interaction, points, playInspection, 2*1000);
	inspection.play();
}

mono.Inspection最主要的一个函数就是play(),用来启动动画。

使用告警

Mono中的告警机制和TWaver 2D中完全一样。Mono定义了告警级别,并在DataBox中内置了告警管理容器AlarmBox。AlarmBox可以通过函数box.getAlarmBox()获得。当告警发生时,可以创建告警对象并添加到AlarmBox中即可。

告警级别

告警级别都定义在mono.AlarmSeverity类中,它代表了不同严重级别的告警,并具有不同的颜色定义。

告警级别 严重值 名称 标志代码 颜色
mono.AlarmSeverity.CRITICAL 500 Critical C #FF0000
mono.AlarmSeverity.MAJOR 400 Major M #FFA000
mono.AlarmSeverity.MINOR 300 Minor m #FFFF00
mono.AlarmSeverity.WARNING 200 Warning W #00FFFF
mono.AlarmSeverity.INDETERMINATE 100 Indeterminate N #C800FF
mono.AlarmSeverity.CLEARED 0 Cleared R #00FF00

创建告警对象

下面代码构造了一个新的告警对象:

var alarm = new mono.Alarm(id, elementId, alarmSeverity, isAcked, isCleared);

其中:

  • id – 告警的id
  • elementId – 告警对应的3D对象的id
  • alarmSeverity – 告警级别
  • isAcked – 告警是否已经确认
  • isCleared – 告警是否已经清除

下面代码演示了如何创建一个告警,并添加到DataBox中。

var alarm = new mono.Alarm(id, id, mono.AlarmSeverity.CRITICAL);
box3d.getAlarmBox().add(alarm);

下图显示了发生告警的设备与未发生告警设备的对比:
76

polygon offset

Z-fighting现象就是指当两个面共面时,二者的深度值一样,深度缓冲就不能清楚的将它们两者分离开来,位于后面的图元上的一些像素就会被渲染到前面的图元上,最终导致图象在帧与帧之间产生微弱的闪光。如下图所示。
polyoffsetoff
那么如何解决这个问题呢?
在webGL中提供了polygon offset方法计算3D图形像素点的深度偏移量。该偏移量在深度测试和深度值被写入深度缓冲区之前被添加。下面详细介绍PolygonOffset方法的使用。
wenGL中PolygonOffset方法的原型为:

/**
  * factor: 比例因子,为每个多边形创建一个偏移量
  * units:  units乘以一个特定实现的值来创建一个常量深度偏移量
  */
void polygonOffset (float factor, float units) 
enable|disable (POLYGON_OFFSET_FILL)//开启/关闭polygon offset。

常用的参数有:

    POLYGON_OFFSET_UNITS
    POLYGON_OFFSET_FACTOR
    POLYGON_OFFSET_FILL

使用方法:

polygonOffset( 1.0, 1.0 );

enable(POLYGON_OFFSET_FILL);
polygonMode(FRONT_AND_BACK, FILL);
drawShapes();
disable(POLYGON_OFFSET_FILL);

polygonMode(FRONT_AND_BACK, LINE);
drawLines();

使用polygon offset方法后生成的效果如下:
polyoffseton