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

8 Time component

# 8.1 Introduction

## 8.1.1 Name

The name of this component is "Time". This name shall be used when referring to this component in the COMPONENT statement (see 7.2.5.4 Component statement).

## 8.1.2 Overview

This clause describes the Time component of this document. This includes a definition of the TimeSensor node, the fundamental means for connecting the X3D world to the time base of the X3D browser. Table 8.1 links to the major topics in this clause.

Table 8.1 — Topics

8.1 Introduction 8.1.1 Name 8.1.2 Overview 8.2 Concepts 8.2.1 Time model 8.2.2 Time origin 8.2.3 Discrete and continuous changes 8.2.4 Time-dependent nodes 8.2.4.1 Overview 8.2.4.2 Time cycles 8.2.4.3 Time activation 8.2.4.4 Pausingand resumingtime 8.3 Abstract types 8.3.1 X3DTimeDependentNode 8.4 Node reference 8.4.1 TimeSensor 8.5 Support levels Figure 8.1 — Examples of time-dependent node execution Table 8.1 — Topics Table 8.2 — Time component support levels

# 8.2 Concepts

## 8.2.1 Time model

The X3D browser controls the passage of time in a world by causing TimeSensor nodes to generate events as time passes. Specialized X3D browsers or authoring applications may cause time to pass more quickly or slowly than in the real world, but typically the times generated by TimeSensor nodes will approximate "real" time. A world's creator should make no assumptions about how frequently a TimeSensor will generate events but can safely assume that each time event generated will have a timestamp greater than any previous time event.

### 8.2.2 Time origin

Time (0.0) is equivalent to 00:00:00 GMT January 1, 1970. Absolute times are specified in SFTime or MFTime fields as double-precision floating point numbers representing seconds. Negative absolute times are interpreted as happening before 1970.

When an SFTime value represents a time-interval duration, negative values are not allowed.

Processing an event with timestamp t may only result in generating events with timestamps greater than or equal to t.

## 8.2.3 Discrete and continuous changes

This document does not distinguish between discrete events (such as those generated by a TouchSensor) and events that are the result of sampling a conceptually continuous set of changes (such as the fraction events generated by a TimeSensor). An ideal X3D implementation would generate an infinite number of samples for continuous changes, each of which would be processed infinitely quickly.

Before processing a discrete event, all continuous changes that are occurring at the discrete event's timestamp shall behave as if they generate events at that same timestamp.

Beyond the requirements that continuous changes be up-to-date during the processing of discrete changes, the sampling frequency of continuous changes is implementation dependent. Typically, a TimeSensor affecting a visible (or otherwise perceptible) portion of the world will generate events once per frame, where a frame is a single rendering of the world or one time-step in a simulation.

## 8.2.4 Time-dependent nodes

### 8.2.4.1 Overview

AudioClip, MovieTexture, and TimeSensor are examples of nodes of X3DTimeDependentNode type that can activate, pause, resume, and deactivate instantiations of themselves at specified times. Each of these node types contains the inputOutput fields: startTime, pauseTime, resumeTime, stopTime, loop, elapsedTime, isActive and isPaused. The values of the inputOutput fields are used to determine when an instantiated node becomes active or inactive and enters or exits a paused state. Also, under certain conditions, these instantiated nodes ignore events to some of their inputOutput fields. A node ignores an input event by not accepting the new value and not generating an xxx _changed event. An abstract time-dependent node type can be realized as any one of AudioClip, MovieTexture, or TimeSensor.

### 8.2.4.2 Time cycles

Time-dependent nodes execute in cycles. A cycle is defined by field data within the node. If, at the end of a cycle, the value of loop is FALSE, execution is terminated (see below for events at termination). Conversely, if loop is TRUE at the end of a cycle, a time-dependent node continues execution into the next cycle. Thus, a time-dependent node with loop TRUE at the end of every cycle continues cycling forever if startTime ≥ stopTime, or until stopTime if startTime < stopTime, or until the conditions to pause are set.

The elapsedTime outputOnly field delivers the current elapsed time since the TimeSensor was activated and running, cumulative in seconds and not counting any time while in a paused state.

### 8.2.4.3 Time activation

The default values for each of the time-dependent nodes are specified such that any node with default values is already inactive and resumed (and, therefore, will generate no events upon loading). A time-dependent node can be defined such that it will be active upon reading by specifying loop TRUE. This use of a non-terminating time-dependent node should be used with caution since it incurs continuous overhead on the simulation.

A time-dependent node generates an isActive TRUE event when it becomes active and generates an isActive FALSE event when it becomes inactive. These are the only times at which an isActive event is generated. In particular, isActive events are not sent at each tick of a simulation.

A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active ( now refers to the time at which the browser is simulating and displaying the virtual world). When a time-dependent node is read from a X3D file and the ROUTEs specified within the X3D file have been established, the node should determine if it is active and, if so, generate an isActive TRUE event and begin generating any other necessary events. However, if a node would have become inactive at any time before the reading of the X3D file, no events are generated upon the completion of the read.

An active time-dependent node will become inactive when stopTime is reached if stopTime > startTime. The value of stopTime is ignored if stopTime ≤ startTime. Also, an active time-dependent node will become inactive at the end of the current cycle if loop is FALSE. If an active time-dependent node receives a set_loop FALSE event, execution continues until the end of the current cycle or until stopTime (if stopTime > startTime), whichever occurs first. The termination at the end of cycle can be overridden by a subsequent set_loop TRUE event.

Any set_startTime events to an active time-dependent node are ignored. Any set_stopTime event where stopTime ≤ startTime sent to an active time-dependent node is also ignored. A set_stopTime event where startTime < stopTime ≤ now sent to an active time-dependent node results in events being generated as if stopTime has just been reached. That is, final events, including an isActive FALSE, are generated and the node becomes inactive. The stopTime_changed event will have the set_stopTime value. Other final events are node-dependent (see 8.4.1 TimeSensor).

A time-dependent node may be restarted while it is active by sending a set_stopTime event equal to the current time (which will cause the node to become inactive) and a set_startTime event, setting it to the current time or any time in the future. These events will have the same time stamp and should be processed as set_stopTime, then set_startTime to produce the correct behaviour.

Figure 8.1 illustrates the behavior of several common cases of time-dependent nodes. In each case, the initial conditions of startTime, stopTime, loop, and the time-dependent node's cycle interval are labelled, the red region denotes the time period during which the time-dependent node is active, the arrows represent input events received by (and output events sent by) the time-dependent node, and the horizontal axis represents time. Slanted lines indicate the time interval associated with each cycle.

Figure 8.1 — Examples of time-dependent node execution

### 8.2.4.4 Pausing and resuming time

While an active time-dependent node is paused, it generates TRUE isPaused and pauseTime_changed events and ceases to generate all other output events, while maintaining (or "freezing") its state (holding the last output values and the clock's internal time when the pausing conditions are met).

An active time-dependent node may be paused when its SFTime fields are such that now ≥ pauseTime > resumeTime. When a time-dependent node is paused, the time-dependent node shall send out a TRUE event on isPaused and a pauseTime_changed event reporting the simulation time when the node was paused.

An active but paused time-dependent node shall resume at the first simulation tick when now ≥ resumeTime > pauseTime. The time-dependent node then resumes generating its output events from the paused state at the simulation tick. At the time when the node resumes, the `fraction_changed` event continues from its value when paused. A resumeTime_changed event is also generated reporting the simulation time when the node was resumed.

# 8.3 Abstract types

## 8.3.1 X3DTimeDependentNode

    X3DTimeDependentNode : X3DChildNode {
      SFString [in,out] description  ""
      SFBool   [in,out] enabled      FALSE
      SFBool   [in,out] loop         FALSE
      SFNode   [in,out] metadata     NULL  [X3DMetadataObject]
      SFTime   [in,out] pauseTime    0     (-∞,∞)
      SFTime   [in,out] resumeTime   0     (-∞,∞)
      SFTime   [in,out] startTime    0     (-∞,∞)
      SFTime   [in,out] stopTime     0     (-∞,∞)
      SFTime   [out]    elapsedTime
      SFBool   [out]    isActive
      SFBool   [out]    isPaused
    }

This abstract node type is the base node type from which all time-dependent nodes are derived.

The description field specifies a textual description for intended purpose of the node. This information is beneficial for authoring, and may be used by optional X3D browser-specific user interfaces that present users with more detailed information about active time-dependent behavior.

The enabled field enables and disables operation in a manner appropriate for the associated node.

See 8.2 Concepts for a detailed discussion of fields and corresponding behavior responses in time-dependent nodes.

# 8.4 Node reference

## 8.4.1 TimeSensor

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

TimeSensor nodes generate events as time passes. TimeSensor nodes can be used for many purposes including:

1. driving continuous simulations and animations;
2. controlling periodic activities ( e.g., one per minute);
3. initiating single occurrence events such as an alarm clock.

The TimeSensor node contains two discrete outputOnly fields: isActive and cycleTime. The isActive outputOnly field sends TRUE when the TimeSensor node begins running, and FALSE when it stops running. The cycleTime outputOnly field sends a time event at startTime and at the beginning of each new cycle (useful for synchronization with other time-based objects). The remaining outputOnly fields generate continuous events. The fraction_changed outputOnly field, an SFFloat in the closed interval [0,1], sends the completed fraction of the current cycle. The time outputOnly field sends the absolute time for a given simulation tick.

If the enabled field is TRUE, the TimeSensor node is enabled and may be running. If a set_enabled FALSE event is received while the TimeSensor node is running, the sensor performs the following actions:

4. evaluates and sends all relevant outputs;
5. sends a FALSE value for isActive;
6. disables itself.

Input events on the fields of the TimeSensor node ( e.g., set_startTime) are processed and their corresponding outputOnly fields ( e.g., startTime_changed) are sent regardless of the state of the enabled field. The remaining discussion assumes enabled is TRUE.

The loop, startTime, stopTime and isActive fields and their effects on the TimeSensor node are discussed in detail in 8.2 Concepts.

The computation of `elapsedTime` is defined in 8.2.4.2 Time cycles.

The effects of the `isPaused`, `pauseTime`, and `resumeTime` fields are defined in 8.2.4.4 Pausing and resuming time.

The cycle of a TimeSensor node lasts for cycleInterval seconds. The value of cycleInterval shall be greater than zero. If the value of cycleInterval changes during an active loop, `fraction_changed` events continue to increase smoothly at a correspondingly faster or slower rate. If the new value of cycleInterval is less than the currently elapsed cycle duration, then the current loop is complete.

A cycleTime outputOnly field can be used for synchronization purposes such as sound with animation. The value of a cycleTime event will be equal to the time at the beginning of the current cycle. A cycleTime event is generated at the beginning of every cycle, including the cycle starting at startTime. The first cycleTime event for a TimeSensor node can be used as an alarm (single pulse at a specified time).

When a TimeSensor node becomes active, it generates an isActive = TRUE event and begins generating time, fraction_changed, and cycleTime events which may be routed to other nodes to drive animation or simulated behaviours. The behaviour at read time is described below. The time event sends the absolute time for a given tick of the TimeSensor node (SFTime/MFTime fields and events represent the number of seconds since midnight GMT January 1, 1970).

fraction_changed events output a floating point value in the closed interval [0, 1]. At startTime the value of fraction_changed is 0. After startTime, the value of fraction_changed in any cycle will progress through the range (0.0, 1.0]. At startTime + N × cycleInterval, for N = 1, 2, ..., ( i.e., at the end of every cycle), the value of fraction_changed is 1.

Let now represent the time at the current simulation tick. Then the time and fraction_changed output-only fields can then be computed as:

       time =    now

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

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

where fractionalPart(x) is a function that returns the fractional part, (that is, the digits to the right of the decimal point), of a nonnegative floating point number.

A TimeSensor node can be set up to be active at read time by specifying loop TRUE (not the default) and stopTime less than or equal to startTime (satisfied by the default values). The time events output absolute times for each tick of the TimeSensor node simulation. The time events shall start at the first simulation tick greater than or equal to startTime. time events end at stopTime, or at startTime + N × cycleInterval for some positive integer value of N, or loop forever depending on the values of the other fields. An active TimeSensor node shall stop at the first simulation tick when now ≥ stopTime > startTime.

No guarantees are made with respect to how frequently a TimeSensor node generates time events, but a TimeSensor node shall generate events at least at every simulation tick. TimeSensor nodes are guaranteed to generate final time and fraction_changed events. If loop is FALSE at the end of the Nth cycleInterval and was TRUE at startTime + M cycleInterval for all 0 < M < N, the final time event will be generated with a value of ( startTime + N × cycleInterval) or stopTime (if stopTime > startTime), whichever value is less. If loop is TRUE at the completion of every cycle, the final event is generated as evaluated at stopTime (if stopTime > startTime) or never.

Operation of an active TimeSensor node effectively ignores set_startTime events. Operation of an active TimeSensor node also effectively ignores set_stopTime events for values less than or equal to startTime. For example, if a set_startTime event is received while a TimeSensor node is active, that set_startTime event is ignored (the startTime field is not changed, and a startTime_changed event is not generated). If an active TimeSensor node receives a set_stopTime event that is less than the current time, and greater than startTime, it behaves as if the stopTime requested is the current time and sends the final events based on the current time (note that stopTime is set as specified in the field).

A TimeSensor read from an X3D file being loaded during run time shall generate isActive TRUE, time and fraction_changed events if the sensor is enabled and all conditions for a TimeSensor to be active are met.

Multiple TimeSensors getting loaded in the same initial scene are all effectively initiated at the same clock time. Similarly, if the original model loads Inline nodes with active TimeSensor nodes, each loaded TimeSensor is consistently synchronized in order to achieve deterministic behavior results independent of network-loading delays.

# 8.5 Support levels

The Time component provides four levels of support as specified in Table 8.2. Level 1 provides basic support for TimeSensor. Level 2 adds support for all of the fields of the TimeSensor node.

Table 8.2 — Time component support levels

Level | Prerequisites | Nodes/Features | Support
--- | --- | --- | ---
1 | Core 1 |  |
|  | X3DTimeDependentNode (abstract) | n/a
|  | TimeSensor | pauseTime optionally supported. isPaused optionally supported. resumeTime optionally supported.
2 | Core 1 |  |
|  | Level 1 supported node | All fields as supported by Level 1.
|  | TimeSensor | All fields fully supported.