Extensible 3D (X3D)
Part 1: Architecture and base components

8 Time component

时间组件

--- X3D separator bar ---

cube 8.1 介绍

8.1.1 名称

这部分组件的名称是 “Time”。当在 COMPONENT 语句中引用这个组件时需要使用这个名称(参见 7.2.3.4 Component 语句)。

8.1.2 概述

本条款描述了 ISO/IEC 19775 标准这部分中的 Time component(时间组件)。其中包括 TimeSensor 节点的定义,以及连接 X3D 场景和时间相关浏览器的基本方法。表 8.1 列出了这一条款的主要主题。

表 8.1: 本条款的主题

cube 8.2 概念

8.2.1 时间模型

浏览器通过 TimeSensors 对场景中时间变化进行控制,当时间流逝时,TimeSensors 会不断产生事件。使用特殊的浏览器或者创作特定的应用程序可以使时间的流逝比真实世界中的时间更快或更慢,但典型的由 TimeSensors 产生的时间将基本等于“真实”时间。场景作者不应考虑 TimeSensor 多长时间产生一个事件,但可以认定每后一次时间事件的时间戳都会大于前一时间事件的时间戳。

8.2.2 时间原点

时间 (0.0) 等于格林尼治标准时间1970年1月1日零点(00:00:00 GMT January 1, 1970)。SFTime 或 MFTimeAbsolute 域中指定的绝对时间是双精度浮点数,单位是秒。负的绝对时间说明 1970 年以前发生的。

处理时间戳 t 的事件只可能导致产生时间戳大于 t 或等于 t 的事件产生。

8.2.3 离散变化和连续变化

ISO/IEC 19775 中不区分离散事件(例如 TouchSensor 产生的事件)和从概念上连续变化过程中采样导致的事件(例如 TimeSensor 产生的片断事件 )。理想的 X3D 执行应能对连续变化进行无限多的采样,对这些采样的处理也应是无限快的。

在处理一个离散事件时,发生在此时的所有的连续变化的事件都和这个离散事件具有相同的时间戳。

除了为和处理离散事件同步的做的采样更新,对连续变化的采样频率是基于执行模式的。代表性的如影响场景可视性(或其它可察觉)部分的 TimeSensor 将每帧(frame)产生一个事件,这时帧为一次场景的渲染或一次仿真的时间步。

8.2.4 时间相关节点

8.2.4.1 概述

AudioClipMovieTextureTimeSensor 都是 X3DTimeDependentNode 类型的节点,这些节点都可以在指定的时间中 activate(激活)、pause(暂停)、resume(继续)、deactivate(停用)实例自身。这些节点类型都包括 inputOutput 域:startTime、pauseTime、resumeTime、stopTime、loop、elapsedTime、isActive、isPaused。inputOutput 域的值用来决定什么时候实例化的节点被激活或停用,或什么时候暂停或继续。在某些情况下,发送到实例化节点某些 inputOutput 域的事件将被忽略。忽略事件可能是不接受新值,或不产生 xxx_changed 事件。抽象的时间相关的节点可以认为是 AudioClip、或 MovieTexture、或 TimeSensor 中的一个。

8.2.4.1 时间循环周期

时间相关节点以循环方式执行。循环由节点中的域的数据定义。如果循环结束时 loop 域的值为 FALSE节点执行将被终止(参见下文的终止时事件)。相反,如果循环结束时 loop 域的值为 TRUE ,节点将继续执行下一个循环。当startTime >= stopTime 每次循环时 loop 都值为 TRUE 的节点将一直循环,如果 startTime < stopTime 将循环到 stopTime,或设置暂停条件可以打断循环。

elapsedTime outputOnly 域发送当前的 TimeSensor 激活并运行的经过的以秒累计的时间,不包括暂停时经过的时间。

8.2.4.2 时间激活

每个时间相关节点的缺省值都被指定为非活动的或可继续的(因此在载入时不会产生事件)。当 loop 值设置为 TRUE 时,可以指定时间相关节点在载入时就被激活。要谨慎使用这种不终止的时间相关节点,因为这样会导致仿真时连续不断的开销。

时间相关节点当被激活时产生一个 isActive TRUE 时间,当被停用时产生一个 isActive FALSE 事件。只有这两种时候会产生 isActive 事件。特别要说明的是,并不在每个仿真的时间步中发送 isActive 事件。

在到达 startTime 之前,时间相关节点都是不激活的。当当前时间 now 变得大于或等于 startTime 时,时间相关节点被激活,并产生一个 isActive TRUE 事件(now 参考浏览器对虚拟场景模拟和显示的时间)。当从 X3D 文件中读取了时间相关节点,并建立了由文件中 ROUTE 指定的路由以后,这个节点将决定是否被激活,如果被激活,就产生一个 isActive TRUE 事件和其它需要的事件。但是,如果节点在设计为读取文件前不被激活,则在读取完成之后不会立即产生任何事件。

如果 stopTime > startTime,一个激活的时间相关节点将在达到 stopTime 被停用。如果 stopTime <= startTimestopTime 的值将被忽略。当 loop 值为 FALSE 时,激活的时间相关节点在当前循环结束后就被停用。当激活的时间相关节点接受到 set_loop FALSE 事件时,将会继续执行到当前循环的结束或执行到 stopTime (如果 stopTime > startTime),这取决于那种情况先发生。循环结束后的终止可以有后发的 set_loop TRUE 事件取消。

任何发送到激活的时间相关节点的 set_startTime 事件都将被忽略。任何发送到stopTime <= startTime 的激活的时间相关节点的 set_stopTime 事件也将被忽略。当 startTime < stopTime <= now 时,发送到激活的时间相关节点的 set_stopTime 事件,将产生和达到 stopTime 时产生事件一样的事件。这就是说,最终的结果,包括产生一个 isActive FALSE 事件,一个值和 set_stopTime 值相同的 stopTime_changed 事件,并使节点变为不激活。其它收尾事件是基于节点的(参见 TimeSensor)。

时间相关节点在激活时可以被设置重新启动,方法时发送一个和当前时间相同的 set_stopTime 事件(设置节点为不活动)并发送一个设置为当前时间或将来的时间的 set_startTime 事件。为保证产生正确的行为,这些事件应该被设置为相同的时间戳,并且保证先处理 set_stopTime,然后是 set_startTime

8.2.4.3 时间暂停

当时间相关节点暂停时,产生 isPaused TRUE 事件和 pauseTime_changed 事件,并停止产生其它输出事件,并维持(或说‘冻结’)其状态(维持最后的输出值并维持暂停时内部时钟的时间)。

时间相关节点在其相关的 SFTime 类域满足以下情况时会暂停,now >= pauseTime > resumeTime。当时间相关节点暂停时,其 isPaused 域将发送一个 isPaused TRUE 事件,并通过发送 pauseTime_changed 指明节点暂停的时间。

激活的但暂停的时间相关节点将在满足 now >= resumeTime > pauseTimeshall 的第一个仿真时间步继续执行。此时的 eventOut 从暂停时仿真时间步的状态开始继续输出事件。节点继续时将产生一个 resumeTime_changed 事件以提示继续时的时间。

附图 8.1 介绍了时间相关节点的一些通常的行为。在每个例子中标出了 startTime、stopTime、loop 的初始条件和时间相关节点的节点循环周期,红色区域表示时间相关节点被激活的持续时间,箭头表示时间相关节点接受到的 input 事件和发送的 output 事件,水平轴表示时间。

Time dependent examples

附图 8.1 — 执行时间相关节点的例子

cube 8.3 抽象类型

8.3.1 X3DTimeDependentNode

X3DTimeDependentNode : X3DChildNode {
  SFTime  [out]    elapsedTime
  SFBool  [out]    isActive
  SFBool  [out]    isPaused
  SFBool  [in,out] loop         FALSE
  SFTime  [in,out] pauseTime    0     (-∞,∞)
  SFTime  [in,out] resumeTime   0     (-∞,∞)
  SFTime  [in,out] startTime    0     (-∞,∞)
  SFTime  [in,out] stopTime     0     (-∞,∞)
}

这个抽象节点类型是衍生所有的时间相关节点的基本节点类型。是 X3D 系统中所有节点的抽象基本节点类型。 8.2, 概念 中包含了基于时间节点的详细描述。

cube 8.4 节点参考

8.4.1 TimeSensor

TimeSensor : X3DTimeDependentNode, X3DSensorNode {
  SFTime  [in,out] cycleInterval    1     (0,∞)
  SFBool  [in,out] enabled          TRUE
  SFBool  [in,out] loop             FALSE
  SFTime  [in,out] pauseTime        0     (-∞,∞)
  SFTime  [in,out] resumeTime       0
  SFTime  [in,out] startTime        0     (-∞,∞)
  SFTime  [in,out] stopTime         0     (-∞,∞)
  SFTime  [out]    cycleTime
  SFFloat [out]    fraction_changed
  SFBool  [out]    isActive
  SFBool  [out]    isPaused
  SFTime  [out]    time
}

TimeSensor 节点随时间流逝不断产生事件。TimeSensor 节点的用途可以包以下方面:

  1. 驱动连续性仿真和动画;
  2. 控制周期性活动(例如每分钟一次);
  3. 开始单独发生的事件,例如闹钟。

TimeSensor 节点包含两个离散 outputOnly 域:isActivecycleTimeisActive outputOnly 域在 TimeSensorfield 节点开始运行时发送 TRUE,当停止运行时发送 FALSE startTime 和每个循环开始时 cycleTime outputOnly 域发送时间事件(可以用于同步其它的时间相关对象)。其余的 outputOnly 域都连续地产生事件。fraction_changed outputOnly 域,发送 [0,1] 范围之间的 SFFloat 浮点值,用以指明当前循环进行时间在整个循环中的百分比。time outputOnly 域根据给定的仿真时间步(simulation tick)发送绝对时间。

如果 enabled 域为 TRUE,TimeSensor 节点可以被激活并可能正在运行。当正在运行的 TimeSensor 节点接收到 set_enabled FALSE 事件时,则执行以下动作:

  1. 计算并发送所有相关的输出;
  2. isActive 域发送 FALSE 值;
  3. 停用自身。

不管 enabled 域的状态如何,TimeSensor 节点都将处理域的输入事件(例如 set_startTime)并由 outputOnly 域(例如 startTime_changed) 发送相应的事件。以下的讨论假设 enabled 值为 TRUE

loop、startTime、stopTime、isActive 域和其对 TimeSensor 节点的影响参见 8.2, 概念。TimeSensor 节点的“循环周期cycle”将持续 cycleInterval 秒。cycleInterval 应大于 0

cycleTime outputOnly 域可以用于同步,比如同步动画和声音。cycleTime 事件的值将等于当前循环开始的时间。在每次循环开始时产生 cycleTime 事件,这也包括在 startTime 开始的那个循环。可以用 TimeSensor 节点的第一个 cycleTime 事件做闹钟(在指定时间发送单个脉冲)。

当 TimeSensor 节点被激活时,会产生一个 isActive = TRUE 事件,同时开始产生 time、fraction_changed、cycleTime 事件,这些事件可以被路由到其它节点以驱动动画或仿真行为。 读取时的行为参照以下的描述。TimeSensor 节点的 time 事件发送给定时间步的绝对时间(time 域和事件描述从格林尼治标准时间 1970 年午夜(midnight GMT January 1, 1970)经过的秒数)。

fraction_changed 事件输出 [0, 1] 之间的一个浮点值。在 startTimefraction_changed 值为 0。在 startTime 后,任何循环周期中的 fraction_changed 的值在 (0.0, 1.0] 之间不断增加。在 startTime + N × cycleInterval,其中 N = 1, 2, ...,(例如每次循环周期结束时),fraction_changed 的值为 1。

now 描述当前时间步的时间时,timefraction_changed output-only 域的值可以由以下公式算出:

time = now

temp = (now - startTime) / cycleInterval
   f = fractionalPart(temp)

 if (f == 0.0 && now > startTime) fraction_changed = 1.0
 else fraction_changed = f

这里 fractionalPart(x) 是一个返回非负浮点数的小数部分的函数(即小数点右边)

当指定 loop TRUE(不是缺省值)并指定 stopTime 小于或等于 startTime(缺省值就满足这个条件)时,TimeSensor 节点可以设置为读取时就被激活。time 事件在 TimeSensor 节点仿真的每个时间步输出绝对此时的时间。time 事件输出开始与仿真时间步大于等于 startTime 时。time  事件输出结束于 stopTime 或结束于 startTime N × cycleInterval (其中 N 为正整数),或者根据其它相关的域值也可以一直循环下去。激活的 TimeSensor 节点会在 now >= stopTime > startTime 时的第一个仿真时间段停止

不保证相关 TimeSensor 节点多长时间产生一个事件,但 TimeSensor 节点至少每个仿真时间步都要产生事件。TimeSensor 保证产生最后的 time 事件和 fraction_changed 事件。如果在第 N 个 cycleInterval 循环结束后 loop 值为 FALSE,但在 startTime + M cycleInterval 时 loop 值为 TRUE(其中 0 < M < N,则最终产生的 time 事件的值为 startTime + N × cycleIntervalstopTime(如果 stopTime startTime)中较小的一个值。如果在完成每个循环时 loop 值都为 TRUE,最终事件将在 stopTime 时产生(如果 stopTime startTime)或永远不产生。

激活的 TimeSensor 节点将忽略 set_cycleInterval 事件和 set_startTime 事件。激活的 TimeSensor 节点也将忽略 set_stopTime 小于或等于 startTime set_stopTime 事件。举例来说,如果激活的 TimeSensor 节点接收到一个 set_startTime 事件,这个 set_startTime 事件将被忽略(startTime 域将不会改变,也不产生 startTime_changed 事件)。如果激活的 TimeSensor 节点接收到一个 set_stopTime 事件同时这个 set_stopTime 大于 startTime 并小于当前时间,这时节点会像当前行时间就是 stopTime 那样运作,并基于当前时间发送最终事件 (注意 stopTime 为域中指定的值)。

如果 TimeSensor 节点设置为允许被激活并满足所有激活的条件,则此节点从 X3D 文件读取以后就产生 isActive TRUEtimefraction_changed 事件。

cube 8.5 支持层

Time 组件提供 表 8.2 中规定的四个支持层(levels)。

Level 1 提供了 TimeSensor 的基本支持。Level 2 添加了 TimeSensor 节点所有域的支持。

表 8.2 — Time 组件支持层

层Level 必备条件 节点 支持
1
TimeSensor pause,可选支持项。
isPaused,可选支持项。
resumeTime,可选支持项。
  X3DTimeDependentNode (abstract) n/a
2
Level 1 TimeSensor Level 1 中支持的所有域。
TimeSensor 所有域的完全支持。
--- X3D separator bar ---