<head>
</head>
<!--
<!--
Event Graph ROUTE Table
shows event connections
-->
<!--
Index for DEF nodes:
CameraDirectionalLight,
CameraMovementScript,
CameraNavInfo,
CameraOrientationInterpolator,
CameraPositionInterpolator,
CameraScript,
CameraShotScript,
CameraViewpoint,
OfflineRenderScript
Index for Viewpoint nodes:
Viewpoint_1,
CameraViewpoint
Index for ProtoDeclare definitions:
Camera,
CameraMovement,
CameraShot,
OfflineRender
-->
<Scene>
<!-- =============== Camera ============== -->
<WorldInfo title='CameraPrototypes.x3d'/>
<ProtoDeclare name='Camera' appinfo='Camera node provides direct control of scene view to enable cinematic camera animation shot by shot and move by move along with still digital-photography settings for offline rendering of camera images.'
>
<!-- Viewpoint-related fields, NavigationInfo-related fields and Camera-unique fields -->
<ProtoInterface>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this Camera'
/>
<field name='position' type='SFVec3f' value='0 0 10' accessType='inputOutput'
appinfo='Camera position in local transformation frame, which is default prior to first CameraShot initialPosition getting activated'
/>
<field name='orientation' type='SFRotation' value='0 0 1 0' accessType='inputOutput'
appinfo='Camera rotation in local transformation frame, which is default prior to first CameraShot initialPosition getting activated'
/>
<field name='fieldOfView' type='SFFloat' value='0.7854' accessType='inputOutput'
appinfo='pi/4'
/>
<field name='set_fraction' type='SFFloat' accessType='inputOnly'
appinfo='input fraction drives interpolators'
/>
<field name='set_bind' type='SFBool' accessType='inputOnly'
appinfo='input event binds or unbinds this Camera'
/>
<field name='bindTime' type='SFTime' accessType='outputOnly'
appinfo='output event indicates when this Camera is bound'
/>
<field name='isBound' type='SFBool' accessType='outputOnly'
appinfo='output event indicates whether this Camera is bound or unbound'
/>
<field name='nearClipPlane' type='SFFloat' value='0.25' accessType='inputOutput'
appinfo='Vector distance to near clipping plane corresponds to NavigationInfo.avatarSize[0]'
/>
<field name='farClipPlane' type='SFFloat' value='0.0' accessType='inputOutput'
appinfo='Vector distance to far clipping plane corresponds to NavigationInfo.visibilityLimit'
/>
<field name='shots' type='MFNode' accessType='inputOutput'
appinfo='Array of CameraShot nodes which in turn contain CameraMovement nodes'
>
<!-- initialization nodes (if any) go here -->
</field>
<field name='headlight' type='SFBool' value='true' accessType='inputOutput'
appinfo='Whether camera headlight is on or off'
/>
<field name='headlightColor' type='SFColor' value='1 1 1' accessType='inputOutput'
appinfo='Camera headlight color'
/>
<field name='headlightIntensity' type='SFFloat' value='1' accessType='inputOutput'
appinfo='Camera headlight intensity'
/>
<field name='filterColor' type='SFColor' value='1 1 1' accessType='inputOutput'
appinfo='Camera filter color that modifies virtual lens capture'
/>
<field name='filterTransparency' type='SFFloat' value='1' accessType='inputOutput'
appinfo='Camera filter transparency that modifies virtual lens capture'
/>
<field name='upVector' type='SFVec3f' value='0 1 0' accessType='inputOutput'
appinfo='upVector changes modify camera orientation (and possibly vice versa)'
/>
<field name='fStop' type='SFFloat' value='5.6' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='focusDistance' type='SFFloat' value='10' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='totalDuration' type='SFTime' accessType='outputOnly'
appinfo='Total duration of contained enabled CameraShot (and thus CameraMovement) move durations'
/>
<field name='offlineRender' type='SFNode' accessType='inputOutput'
appinfo='OfflineRender node'
>
<!-- initialization node (if any) goes here -->
</field>
<field name='traceEnabled' type='SFBool' value='false' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
</ProtoInterface>
<ProtoBody>
<IS>
<connect nodeField='description' protoField='description'/>
<connect nodeField='position' protoField='position'/>
<connect nodeField='orientation' protoField='orientation'/>
<connect nodeField='fieldOfView' protoField='fieldOfView'/>
<connect nodeField='set_bind' protoField='set_bind'/>
<connect nodeField='bindTime' protoField='bindTime'/>
<connect nodeField='isBound' protoField='isBound'/>
</IS>
</Viewpoint>
<!-- NavInfo EXAMINE used since some browsers (InstantReality) try to lock view to vertical when flying to avoid disorientation -->
<IS>
<connect nodeField='set_bind' protoField='set_bind'/>
<!-- No need to bind outputs bindTime, isBound from NavigationInfo since Viewpoint outputs will suffice. TODO inform BitManagement that bindTime field is missing. -->
<connect nodeField='headlight' protoField='headlight'/>
<connect nodeField='visibilityLimit' protoField='farClipPlane'/>
</IS>
</NavigationInfo>
<!-- this DirectionalLight replaces NavigationInfo headlight in order to add color capability -->
<IS>
</IS>
<!-- TODO confirm other default field values match NavigationInfo spec -->
</DirectionalLight>
<IS>
<connect nodeField='set_fraction' protoField='set_fraction'/>
</IS>
</PositionInterpolator>
<IS>
<connect nodeField='set_fraction' protoField='set_fraction'/>
</IS>
</OrientationInterpolator>
<
ROUTE
fromNode='
CameraPositionInterpolator' fromField='value_changed' toNode='
CameraViewpoint' toField='position'/>
<
ROUTE
fromNode='
CameraOrientationInterpolator' fromField='value_changed' toNode='
CameraViewpoint' toField='orientation'/>
<!-- binding is controlled externally, all camera operations proceed the same regardless of whether bound or not -->
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this Camera'
/>
<field name='position' type='SFVec3f' accessType='inputOutput'
appinfo='Camera position in local transformation frame'
/>
<field name='orientation' type='SFRotation' accessType='inputOutput'
appinfo='Camera rotation in local transformation frame'
/>
<field name='set_fraction' type='SFFloat' accessType='inputOnly'
appinfo='input fraction drives interpolators'
/>
<field name='set_bind' type='SFBool' accessType='inputOnly'
appinfo='input event binds or unbinds this Camera'
/>
<field name='fieldOfView' type='SFFloat' accessType='inputOutput'
appinfo='pi/4'
/>
<field name='nearClipPlane' type='SFFloat' accessType='inputOutput'
appinfo='Vector distance to near clipping plane'
/>
<field name='farClipPlane' type='SFFloat' accessType='inputOutput'
appinfo='Vector distance to far clipping plane'
/>
<field name='shots' type='MFNode' accessType='inputOutput'
appinfo='Array of CameraShot nodes which in turn contain CameraMovement nodes'
>
<!-- initialization nodes (if any) go here -->
</field>
<field name='filterColor' type='SFColor' accessType='inputOutput'
appinfo='Camera filter color that modifies virtual lens capture'
/>
<field name='filterTransparency' type='SFFloat' accessType='inputOutput'
appinfo='Camera filter transparency that modifies virtual lens capture'
/>
<field name='upVector' type='SFVec3f' accessType='inputOutput'
appinfo='upVector changes modify camera orientation (and possibly vice versa)'
/>
<field name='fStop' type='SFFloat' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='focusDistance' type='SFFloat' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='totalDuration' type='SFTime' accessType='outputOnly'
appinfo='Total duration of contained enabled CameraShot (and thus CameraMovement) move durations'
/>
<field name='offlineRender' type='SFNode' accessType='inputOutput'
appinfo='OfflineRender node'
>
<!-- initialization node (if any) goes here -->
</field>
<field name='ViewpointNode' type='SFNode' accessType='initializeOnly'
appinfo='node reference to permit getting setting fields from within Script'
>
</field>
<field name='NavInfoNode' type='SFNode' accessType='initializeOnly'
appinfo='node reference to permit getting setting fields from within Script'
>
</field>
<field name='CameraPI' type='SFNode' accessType='initializeOnly'
appinfo='node reference to permit getting setting fields from within Script'
>
</field>
<field name='CameraOI' type='SFNode' accessType='initializeOnly'
appinfo='node reference to permit getting setting fields from within Script'
>
</field>
<field name='key' type='MFFloat' accessType='inputOutput'
appinfo='key array for interpolators'
/>
<field name='keyValuePosition' type='MFVec3f' accessType='inputOutput'
appinfo='keyValue array for PositionInterpolator'
/>
<field name='keyValueOrientation' type='MFRotation' accessType='inputOutput'
appinfo='keyValue array for OrientationInterpolator'
/>
<field name='animated' type='SFBool' value='false' accessType='inputOutput'
appinfo='whether internal CameraShot and CameraMove nodes are tracking or changed via ROUTE events'
/>
<field name='initialized' type='SFBool' value='false' accessType='initializeOnly'
appinfo='perform checkShots() function once immediately after initialization'
/>
<field name='shotCount' type='SFInt32' value='0' accessType='initializeOnly'
appinfo='how many CameraShot nodes are contained in shots array'
/>
<field name='movesCount' type='SFInt32' value='0' accessType='initializeOnly'
appinfo='how many CameraMove nodes are contained in moves array'
/>
<field name='frameCount' type='SFFloat' value='0' accessType='initializeOnly'
appinfo='how many frames were created in current loop'
/>
<field name='startTime' type='SFTime' value='0' accessType='initializeOnly'
appinfo='holding variable'
/>
<field name='priorTraceTime' type='SFTime' value='0' accessType='initializeOnly'
appinfo='holding variable'
/>
<field name='traceEnabled' type='SFBool' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
<IS>
<connect nodeField='description' protoField='description'/>
<connect nodeField='position' protoField='position'/>
<connect nodeField='orientation' protoField='orientation'/>
<connect nodeField='set_fraction' protoField='set_fraction'/>
<connect nodeField='set_bind' protoField='set_bind'/>
<connect nodeField='fieldOfView' protoField='fieldOfView'/>
<connect nodeField='nearClipPlane' protoField='nearClipPlane'/>
<connect nodeField='farClipPlane' protoField='farClipPlane'/>
<connect nodeField='shots' protoField='shots'/>
<connect nodeField='filterColor' protoField='filterColor'/>
<connect nodeField='filterTransparency' protoField='filterTransparency'/>
<connect nodeField='upVector' protoField='upVector'/>
<connect nodeField='fStop' protoField='fStop'/>
<connect nodeField='focusDistance' protoField='focusDistance'/>
<connect nodeField='isActive' protoField='isActive'/>
<connect nodeField='totalDuration' protoField='totalDuration'/>
<connect nodeField='offlineRender' protoField='offlineRender'/>
<connect nodeField='traceEnabled' protoField='traceEnabled'/>
</IS>
<![CDATA[
ecmascript:
function initialize () // CameraScript
{
// tracePrint ('initialize start...');
NavInfoNode.avatarSize[0] = nearClipPlane;
// remaining setups deferred to invocation of checkShots() method
// thanks to Yvonne Jung Fraunhofer for diagnosing better approach to function initialization
alwaysPrint ('initialize complete');
}
function checkShots (eventValue)
{
tracePrint ('checkShots() method should only occur after initialize() methods in all other Scripts are complete');
// compute totalDuration by summing durations from contained CameraShot and CameraMovement nodes
totalDuration= 0;
shotCount = shots.length;
movesCount = 0;
for (i = 0; i < shotCount; i++) // shots index
{
tracePrint ('shots[' + i + '].moves.length=' + shots[i].moves.length);
movesCount += shots[i].moves.length;
totalDuration = totalDuration + shots[i].shotDuration;
if (shots[i].moves.length == 0)
{
alwaysPrint ('warning: CameraShot[' + i + '][' + shots[i].description + '] has no contained CameraMove nodes');
}
}
// size checks before proceeding
if (shotCount == 0)
{
alwaysPrint ('warning: no CameraShot nodes found for the shots, nothing to do!');
return;
}
else if (movesCount == 0)
{
alwaysPrint ('warning: no CameraMove nodes found for the shots, nothing to do!');
return;
}
else if (totalDuration == 0)
{
alwaysPrint ('warning: totalDuration = 0 seconds, nothing to do!');
return;
}
tracePrint ('number of contained CameraShot nodes=' + shotCount);
tracePrint ('number of contained CameraMove nodes=' + movesCount);
tracePrint ('totalDuration=' + totalDuration + ' seconds for all shots and moves');
// compute interpolators
var k = 0; // index for latest key, keyValuePosition, keyValueOrientation
for (i = 0; i < shotCount; i++) // shots index
{
if (i==0) // initial entries
{
key[0] = 0.0; // no previous move
keyValuePosition[0] = shots[i].initialPosition;
keyValueOrientation[0] = shots[i].initialOrientation;
}
else // new shot repositions, reorients camera as clean break from preceding shot/move
{
key[k+1] = key[k]; // start from end from previous move
keyValuePosition[k+1] = shots[i].initialPosition;
keyValueOrientation[k+1] = shots[i].initialOrientation;
k++;
}
tracePrint (shots[i].description);
tracePrint ('shots[i].moves.length=' + shots[i].moves.length);
for (j = 0; j < shots[i].moves.length; j++) // moves index
{
var durationFloat = shots[i].moves[j].duration; // implicit type conversion from SFTime
// durationFloat = new SFFloat (shots[i].moves[j].duration); // explicit type conversion from SFTime
// tracePrint ('durationFloat=' + durationFloat);
key[k+1] = key[k] + (durationFloat / totalDuration);
keyValuePosition[k+1] = shots[i].moves[j].goalPosition;
if (!animated)
{
keyValueOrientation[k+1] = shots[i].moves[j].goalOrientation;
}
else
{
// using constructor SFRotation (SFVec3f fromVector, SFVec3f toVector)
// see X3D ECMAScript binding Table 7.18 — SFRotation instance creation functions
// test if difference vector is zero, if so maintain previous rotation
var shotVector = ViewpointNode.position.subtract(shots[i].moves[j].goalAimPoint).normalize();
if (shotVector.length() >= 0)
{
// default view direction is along -Z axis
shots[i].moves[j].goalOrientation = new SFRotation (new SFVec3f (0, 0, 1), shotVector);
keyValueOrientation[k+1] = shots[i].moves[j].goalOrientation;
}
else // note (k > 0)
{
keyValueOrientation[k+1] = keyValueOrientation[k]; // no change
}
tracePrint ('shots[' + i + '].moves[' + j + '].goalAimPoint=' + shots[i].moves[j].goalAimPoint.toString());
tracePrint (' ViewpointNode.position=' + ViewpointNode.position.toString());
tracePrint (' shotVector delta=' + ViewpointNode.position.subtract(shots[i].moves[j].goalAimPoint).toString());
tracePrint (' shotVector normalize=' + ViewpointNode.position.subtract(shots[i].moves[j].goalAimPoint).normalize().toString());
tracePrint (' goalOrientation=' + shots[i].moves[j].goalOrientation.toString());
tracePrint (' keyValueOrientation[k+1]=' + keyValueOrientation[k+1].toString());
}
k++; // update index to match latest key, keyValuePosition, keyValueOrientation
// check animated parameter: set true if any of moves are tracking moves
if (!animated) animated = shots[i].moves[j].tracking; // once true, remains true
// tracePrint ('shots[' + i + '].moves[' + j + '].tracking=' + shots[i].moves[j].tracking + ', animated=' + animated);
// intermediate trace
tracePrint (' key=' + key);
tracePrint (' keyValuePosition=' + keyValuePosition);
tracePrint ('keyValueOrientation=' + keyValueOrientation);
tracePrint ('- ' + shots[i].moves[j].description);
}
}
tracePrint (' key=' + key);
tracePrint (' keyValuePosition=' + keyValuePosition);
tracePrint ('keyValueOrientation=' + keyValueOrientation);
if (key.length != keyValuePosition.length)
{
alwaysPrint ('warning: internal error during array construction, ' +
'key.length=' + key.length + ' must equal ' +
'keyValuePosition.length=' + keyValuePosition.length);
}
if (key.length != keyValueOrientation.length)
{
alwaysPrint ('warning: internal error during array construction, ' +
'key.length=' + key.length + ' must equal ' +
'keyValueOrientation.length=' + keyValueOrientation.length);
}
if (key.length != (shotCount + movesCount))
{
alwaysPrint ('warning: internal error during array construction, ' +
'key.length=' + key.length + ' must equal ' +
'(shotCount + movesCount)=' + (shotCount + movesCount));
}
tracePrint (' animated=' + animated);
// set node values
CameraPI.key = key;
CameraOI.key = key;
CameraPI.keyValue = keyValuePosition;
CameraOI.keyValue = keyValueOrientation;
if (!animated) // output results
{
tracePrint ('<PositionInterpolator DEF=\'CameraPositionInterpolator\' key=\'' + stripBrackets(CameraPI.key) + '\' keyValue=\'' + stripBrackets(CameraPI.keyValue) + '\'/>');
tracePrint ('<OrientationInterpolator DEF=\'CameraOrientationInterpolator\' key=\'' + stripBrackets(CameraOI.key) + '\' keyValue=\'' + stripBrackets(CameraOI.keyValue) + '\'/>');
}
tracePrint ('checkShots() complete');
}
function stripBrackets (fieldArray)
{
// some browsers add brackets to array output strings, this function strips them
outputString = '';
for (i = 0; i < fieldArray.length; i++)
{
outputString += fieldArray[i].toString();
if (i < fieldArray.length - 1) outputString += ' ';
}
return outputString;
}
function set_fraction (eventValue, timestamp) // input event received for inputOnly field
{
// traceEnabled = false; // for testing purposes
// if Camera is being animated, immediately recompute interpolator settings
if (animated) checkShots (true);
// trace progress on console with reduced output frequency
if (frameCount == 0)
{
alwaysPrint ('Animation loop commencing, timestamp=' + timestamp);
startTime = timestamp;
priorTraceTime = timestamp;
alwaysPrint ('shotClock=' + (timestamp - startTime) + ' seconds, frameCount=' + frameCount + ', fraction=' + eventValue + ', position=' + ViewpointNode.position.toString() + ', orientation=' + ViewpointNode.orientation.toString());
if (animated) // output results
{
// TODO how to report or speed up response? alwaysPrint (' aimPoint=' + aimPoint.toString());
tracePrint (' <PositionInterpolator DEF=\'CameraPositionInterpolator\' key=\'' + stripBrackets(CameraPI.key) + '\' keyValue=\'' + stripBrackets(CameraPI.keyValue) + '\'/>');
tracePrint (' <OrientationInterpolator DEF=\'CameraOrientationInterpolator\' key=\'' + stripBrackets(CameraOI.key) + '\' keyValue=\'' + stripBrackets(CameraOI.keyValue) + '\'/>');
}
}
else if ((timestamp - priorTraceTime) >= 1.0) // 1 second trace interval
{
alwaysPrint ('shotClock=' + (timestamp - startTime) + ' seconds, frameCount=' + frameCount + ', fraction=' + eventValue + ', position=' + ViewpointNode.position.toString() + ', orientation=' + ViewpointNode.orientation.toString());
priorTraceTime = timestamp;
if (animated) // output results
{
// TODO how to report or speed up response? alwaysPrint (' aimPoint=' + aimPoint.toString());
tracePrint (' <PositionInterpolator DEF=\'CameraPositionInterpolator\' key=\'' + stripBrackets(CameraPI.key) + '\' keyValue=\'' + stripBrackets(CameraPI.keyValue) + '\'/>');
alwaysPrint (' <OrientationInterpolator DEF=\'CameraOrientationInterpolator\' key=\'' + stripBrackets(CameraOI.key) + '\' keyValue=\'' + stripBrackets(CameraOI.keyValue) + '\'/>');
}
}
if (eventValue == 0)
{
// note that zero value is not necessarily sent first by TimeSensor, so otherwise ignored
frameCount++;
}
else if (eventValue == 1)
{
alwaysPrint ('shotClock=' + (timestamp - startTime) + ', frameCount=' + frameCount + ', fraction=' + eventValue + ', position=' + ViewpointNode.position.toString() + ', orientation=' + ViewpointNode.orientation.toString());
if (animated) // output results
{
// TODO how to report or speed up response? alwaysPrint (' aimPoint=' + aimPoint.toString());
}
alwaysPrint ('Animation loop complete.');
// do not unbind the Viewpoint and NavigationInfo nodes, let that be controlled externally
}
else
{
frameCount++;
}
}
function set_bind (eventValue) // input event received for inputOnly field
{
// need to ensure CameraShot nodes are properly initialized
if (initialized == false)
{
checkShots (true);
initialized = true;
}
if (eventValue)
{
tracePrint ('Camera has been bound');
}
else
{
tracePrint ('Camera has been unbound');
}
}
function set_description (eventValue) // input event received for inputOutput field
{
description = eventValue;
}
function set_position (eventValue) // input event received for inputOutput field
{
position = eventValue;
}
function set_orientation (eventValue) // input event received for inputOutput field
{
orientation = eventValue;
}
function set_fieldOfView (eventValue) // input event received for inputOutput field
{
fieldOfView = eventValue;
}
function set_nearClipPlane (eventValue) // input event received for inputOutput field
{
nearClipPlane = eventValue;
}
function set_farClipPlane (eventValue) // input event received for inputOutput field
{
farClipPlane = eventValue;
}
function set_shots (eventValue) // input event received for inputOutput field
{
shots = eventValue;
}
function set_filterColor (eventValue) // input event received for inputOutput field
{
filterColor = eventValue;
}
function set_filterTransparency (eventValue) // input event received for inputOutput field
{
filterTransparency = eventValue;
}
function set_upVector (eventValue) // input event received for inputOutput field
{
upVector = eventValue;
}
function set_fStop (eventValue) // input event received for inputOutput field
{
fStop = eventValue;
}
function set_focusDistance (eventValue) // input event received for inputOutput field
{
focusDistance = eventValue;
}
function set_offlineRender (eventValue) // input event received for inputOutput field
{
offlineRender = eventValue;
}
function set_key (eventValue) // input event received for inputOutput field
{
key = eventValue;
}
function set_keyValuePosition (eventValue) // input event received for inputOutput field
{
keyValuePosition = eventValue;
}
function set_keyValueOrientation (eventValue) // input event received for inputOutput field
{
keyValueOrientation = eventValue;
}
function set_animated (eventValue) // input event received for inputOutput field
{
animated = eventValue;
}
function tracePrint (outputValue)
{
if (traceEnabled) alwaysPrint (outputValue);
}
function alwaysPrint (outputValue)
{
// try to ensure outputValue is converted to string despite Browser.println idiosyncracies
var outputString = outputValue.toString(); // utility function according to spec
if (outputString == null) outputString = outputValue; // direct cast
if (description.length > 0)
Browser.println ('[Camera: ' + description + '] ' + outputString);
else
Browser.println ('[Camera] ' + outputString);
}
]]>
</ProtoDeclare>
<!-- =============== CameraShot ============== -->
<ProtoDeclare name='CameraShot' appinfo='CameraShot collects a specific set of CameraMovement animations that make up an individual shot.'
>
<ProtoInterface>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this CameraShot'
/>
<field name='enabled' type='SFBool' value='true' accessType='inputOutput'
appinfo='Whether this CameraShot can be activated'
/>
<field name='moves' type='MFNode' accessType='inputOutput'
appinfo='Set of CameraMovement nodes'
>
<!-- initializing CameraMovement nodes are inserted here by scene author using ProtoInstance -->
</field>
<field name='initialPosition' type='SFVec3f' value='0 0 10' accessType='inputOutput'
appinfo='Setup to reinitialize camera position for this shot'
/>
<field name='initialOrientation' type='SFRotation' value='0 0 1 0' accessType='inputOutput'
appinfo='Setup to reinitialize camera rotation for this shot'
/>
<field name='initialAimPoint' type='SFVec3f' value='0 0 0' accessType='inputOutput'
appinfo='Setup to reinitialize aimpoint (relative location for camera direction) for this shot'
/>
<field name='initialFieldOfView' type='SFFloat' value='0.7854' accessType='inputOutput'
appinfo='pi/4'
/>
<field name='initialFStop' type='SFFloat' value='5.6' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='initialFocusDistance' type='SFFloat' value='10' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='shotDuration' type='SFTime' accessType='outputOnly'
appinfo='Subtotal duration of contained CameraMovement move durations'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='traceEnabled' type='SFBool' value='false' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
</ProtoInterface>
<ProtoBody>
<Script DEF='CameraShotScript' directOutput='true' mustEvaluate='true'>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this CameraShot'
/>
<field name='enabled' type='SFBool' accessType='inputOutput'
appinfo='Whether this CameraShot can be activated'
/>
<field name='moves' type='MFNode' accessType='inputOutput'
appinfo='Set of CameraMovement nodes'
>
<!-- initialization nodes (if any) go here -->
</field>
<field name='initialPosition' type='SFVec3f' accessType='inputOutput'
appinfo='Setup to reinitialize camera position for this shot'
/>
<field name='initialOrientation' type='SFRotation' accessType='inputOutput'
appinfo='Setup to reinitialize camera rotation for this shot'
/>
<field name='initialAimPoint' type='SFVec3f' accessType='inputOutput'
appinfo='Setup to reinitialize aimpoint (relative location for camera direction) for this shot'
/>
<field name='initialFieldOfView' type='SFFloat' accessType='inputOutput'
appinfo='pi/4'
/>
<field name='initialFStop' type='SFFloat' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='initialFocusDistance' type='SFFloat' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='shotDuration' type='SFTime' accessType='outputOnly'
appinfo='Subtotal duration of contained CameraMovement move durations'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='traceEnabled' type='SFBool' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
<field name='key' type='MFFloat' accessType='inputOutput'
appinfo='key array for interpolators'
/>
<field name='keyValuePosition' type='MFVec3f' accessType='inputOutput'
appinfo='keyValue array for PositionInterpolator'
/>
<field name='keyValueOrientation' type='MFRotation' accessType='inputOutput'
appinfo='keyValue array for OrientationInterpolator'
/>
<IS>
</IS>
<![CDATA[
ecmascript:
function initialize () // CameraShotScript
{
// tracePrint ('initialize start...');
// compute shotDuration by summing durations from contained CameraMovement nodes
shotDuration = 0;
for (i = 0; i < moves.length; i++)
{
shotDuration = shotDuration + moves[i].duration;
}
alwaysPrint ('number of contained CameraMove nodes=' + moves.length + ', shotDuration=' + shotDuration + ' seconds');
// tracePrint ('... initialize() complete');
}
function set_description (eventValue) // input event received for inputOutput field
{
description = eventValue;
}
function set_enabled (eventValue) // input event received for inputOutput field
{
enabled = eventValue;
}
function set_moves (eventValue) // input event received for inputOutput field
{
moves = eventValue;
}
function set_initialPosition (eventValue) // input event received for inputOutput field
{
initialPosition = eventValue;
}
function set_initialOrientation (eventValue) // input event received for inputOutput field
{
initialOrientation = eventValue;
}
function set_initialAimPoint (eventValue) // input event received for inputOutput field
{
initialAimPoint = eventValue;
}
function set_initialFieldOfView (eventValue) // input event received for inputOutput field
{
initialFieldOfView = eventValue;
}
function set_initialFStop (eventValue) // input event received for inputOutput field
{
initialFStop = eventValue;
}
function set_initialFocusDistance (eventValue) // input event received for inputOutput field
{
initialFocusDistance = eventValue;
}
function set_key (eventValue) // input event received for inputOutput field
{
key = eventValue;
}
function set_keyValuePosition (eventValue) // input event received for inputOutput field
{
keyValuePosition = eventValue;
}
function set_keyValueOrientation (eventValue) // input event received for inputOutput field
{
keyValueOrientation = eventValue;
}
// TODO consider method set_active for constructed Camera node BooleanSequencer to send isActive
function tracePrint (outputValue)
{
if (traceEnabled) alwaysPrint (outputValue);
}
function alwaysPrint (outputValue)
{
// try to ensure outputValue is converted to string despite browser idiosyncracies
var outputString = outputValue.toString(); // utility function according to spec
if (outputString == null) outputString = outputValue; // direct cast
if (description.length > 0)
Browser.println ('[CameraShot: ' + description + '] ' + outputString);
else
Browser.println ('[CameraShot] ' + outputString);
}
]]>
</Script>
<!-- Add any ROUTEs here, going from Script to other nodes within ProtoBody -->
</ProtoBody>
</ProtoDeclare>
<!-- =============== CameraMovement ============== -->
<ProtoDeclare name='CameraMovement' appinfo='CameraMovement node defines a single camera movement animation including goalPosition, goalOrientation, goalAimPoint and goalFieldOfView.'
>
<ProtoInterface>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this CameraMovement'
/>
<field name='enabled' type='SFBool' value='true' accessType='inputOutput'
appinfo='Whether this CameraMovement can be activated'
/>
<field name='duration' type='SFFloat' value='0' accessType='inputOutput'
appinfo='Duration in seconds for this move'
/>
<field name='goalPosition' type='SFVec3f' value='0 0 10' accessType='inputOutput'
appinfo='Goal camera position for this move'
/>
<field name='goalOrientation' type='SFRotation' value='0 0 1 0' accessType='inputOutput'
appinfo='Goal camera rotation for this move'
/>
<field name='tracking' type='SFBool' value='false' accessType='inputOutput'
appinfo='Whether or not camera direction is tracking towards the aimPoint'
/>
<field name='goalAimPoint' type='SFVec3f' value='0 0 0' accessType='inputOutput'
appinfo='Goal aimPoint for this move, ignored if tracking=false'
/>
<field name='goalFieldOfView' type='SFFloat' value='0.7854' accessType='inputOutput'
appinfo='Goal fieldOfView for this move'
/>
<field name='goalFStop' type='SFFloat' value='5.6' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='goalFocusDistance' type='SFFloat' value='10' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='traceEnabled' type='SFBool' value='false' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
</ProtoInterface>
<ProtoBody>
<!-- First node determines node type of this prototype -->
<!-- Subsequent nodes do not render, but still must be a valid X3D subgraph -->
<!-- Script holds CameraMovement initialization values for query by parent CameraShot, and also permits changing values via events -->
<Script DEF='CameraMovementScript' directOutput='true' mustEvaluate='true'>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this CameraMovement'
/>
<field name='enabled' type='SFBool' accessType='inputOutput'
appinfo='Whether this CameraMovement can be activated'
/>
<field name='duration' type='SFFloat' accessType='inputOutput'
appinfo='Duration in seconds for this move'
/>
<field name='goalPosition' type='SFVec3f' accessType='inputOutput'
appinfo='Goal camera position for this move'
/>
<field name='goalOrientation' type='SFRotation' accessType='inputOutput'
appinfo='Goal camera rotation for this move'
/>
<field name='tracking' type='SFBool' accessType='inputOutput'
appinfo='Whether or not camera direction is tracking towards the aimPoint'
/>
<field name='goalAimPoint' type='SFVec3f' accessType='inputOutput'
appinfo='Goal aimPoint for this move, ignored if tracking=false'
/>
<field name='goalFieldOfView' type='SFFloat' accessType='inputOutput'
appinfo='Goal fieldOfView for this move'
/>
<field name='goalFStop' type='SFFloat' accessType='inputOutput'
appinfo='Focal length divided effective aperture diameter indicating width of focal plane'
/>
<field name='goalFocusDistance' type='SFFloat' accessType='inputOutput'
appinfo='Distance to focal plane of sharpest focus'
/>
<field name='isActive' type='SFBool' accessType='outputOnly'
appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'
/>
<field name='traceEnabled' type='SFBool' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
<IS>
<connect nodeField='description' protoField='description'/>
<connect nodeField='enabled' protoField='enabled'/>
<connect nodeField='duration' protoField='duration'/>
<connect nodeField='goalPosition' protoField='goalPosition'/>
<connect nodeField='goalOrientation' protoField='goalOrientation'/>
<connect nodeField='tracking' protoField='tracking'/>
<connect nodeField='goalAimPoint' protoField='goalAimPoint'/>
<connect nodeField='goalFieldOfView' protoField='goalFieldOfView'/>
<connect nodeField='goalFStop' protoField='goalFStop'/>
<connect nodeField='goalFocusDistance' protoField='goalFocusDistance'/>
<connect nodeField='isActive' protoField='isActive'/>
<connect nodeField='traceEnabled' protoField='traceEnabled'/>
</IS>
<![CDATA[
ecmascript:
function initialize () // CameraMovementScript
{
// tracePrint ('initialize start...');
alwaysPrint ('initialize goalPosition=' + goalPosition.toString() + ', goalOrientation=' + goalOrientation.toString() +
', goalAimPoint=' + goalAimPoint.toString() // + ', tracking=' + tracking.toString()
);
if (duration < 0)
{
alwaysPrint ('error: negative duration=' + duration + ', reset to 0 and ignored');
duration = 0;
}
else if (duration == 0)
{
alwaysPrint ('warning: duration=0, nothing to do!');
}
tracePrint ('... initialize complete');
}
function set_goalAimPoint (eventValue) // input event received for inputOutput field
{
goalAimPoint_changed = eventValue;
tracePrint ('goalAimPoint=' + goalAimPoint.toString());
// updated goalOrientation tracking is handled by Camera recomputing the OrientationInterpolator
}
function set_description (eventValue) // input event received for inputOutput field
{
description = eventValue;
}
function set_enabled (eventValue) // input event received for inputOutput field
{
enabled = eventValue;
}
function set_duration (eventValue) // input event received for inputOutput field
{
duration = eventValue;
}
function set_goalPosition (eventValue) // input event received for inputOutput field
{
goalPosition = eventValue;
}
function set_goalOrientation (eventValue) // input event received for inputOutput field
{
goalOrientation = eventValue;
}
function set_tracking (eventValue) // input event received for inputOutput field
{
tracking = eventValue;
}
function set_goalFieldOfView (eventValue) // input event received for inputOutput field
{
goalFieldOfView = eventValue;
}
function set_goalFStop (eventValue) // input event received for inputOutput field
{
goalFStop = eventValue;
}
function set_goalFocusDistance (eventValue) // input event received for inputOutput field
{
goalFocusDistance = eventValue;
}
// TODO consider method set_active for constructed Camera node BooleanSequencer to send isActive
function tracePrint (outputValue)
{
if (traceEnabled) alwaysPrint (outputValue);
}
function alwaysPrint (outputValue)
{
// try to ensure outputValue is converted to string despite browser idiosyncracies
var outputString = outputValue.toString(); // utility function according to spec
if (outputString == null) outputString = outputValue; // direct cast
if (description.length > 0)
Browser.println ('[CameraMovement: ' + description + '] ' + outputString);
else
Browser.println ('[CameraMovement] ' + outputString);
}
]]>
</Script>
<!-- Add any ROUTEs here, going from Script to other nodes within ProtoBody -->
</ProtoBody>
</ProtoDeclare>
<!-- =============== OfflineRender ============== -->
<ProtoDeclare name='OfflineRender' appinfo='OfflineRender defines a parameters for offline rendering of Camera animation output to a movie file (or possibly a still shot).'
>
<ProtoInterface>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this OfflineRender'
/>
<field name='enabled' type='SFBool' value='true' accessType='inputOutput'
appinfo='Whether this OfflineRender can be activated'
/>
<field name='frameRate' type='SFFloat' value='30' accessType='inputOutput'
appinfo='Frames per second recorded for this rendering'
/>
<field name='frameSize' type='SFVec2f' value='640 480' accessType='inputOutput'
appinfo='Size of frame in number of pixels width and height'
/>
<field name='pixelAspectRatio' type='SFFloat' value='1.33' accessType='inputOutput'
appinfo='Relative dimensions of pixel height/width typically 1.33 or 1'
/>
<field name='set_startTime' type='SFTime' accessType='inputOnly'
appinfo='Begin render operation'
/>
<field name='progress' type='SFFloat' accessType='outputOnly'
appinfo='Progress performing render operation (0..1)'
/>
<field name='renderCompleteTime' type='SFTime' accessType='outputOnly'
appinfo='Render operation complete'
/>
<field name='movieFormat' type='MFString' value='"mpeg"' accessType='initializeOnly'
appinfo='Format of rendered output movie (mpeg mp4 etc.), use first supported format'
/>
<field name='imageFormat' type='MFString' value='"png"' accessType='initializeOnly'
appinfo='Format of rendered output images (png jpeg gif tiff etc.) use first supported format'
/>
<field name='traceEnabled' type='SFBool' value='false' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
<!-- TODO non-photorealistic rendering (NPR) parameters -->
</ProtoInterface>
<ProtoBody>
<!-- First node determines node type of this prototype -->
<!-- Subsequent nodes do not render, but still must be a valid X3D subgraph -->
<Script DEF='OfflineRenderScript' mustEvaluate='true'>
<field name='description' type='SFString' accessType='inputOutput'
appinfo='Text description to be displayed for this OfflineRender'
/>
<field name='enabled' type='SFBool' accessType='inputOutput'
appinfo='Whether this OfflineRender can be activated'
/>
<field name='frameRate' type='SFFloat' accessType='inputOutput'
appinfo='Frames per second recorded for this rendering'
/>
<field name='frameSize' type='SFVec2f' accessType='inputOutput'
appinfo='Size of frame in number of pixels width and height'
/>
<field name='pixelAspectRatio' type='SFFloat' accessType='inputOutput'
appinfo='Relative dimensions of pixel height/width typically 1.33 or 1'
/>
<field name='set_startTime' type='SFTime' accessType='inputOnly'
appinfo='Begin render operation'
/>
<field name='progress' type='SFFloat' accessType='outputOnly'
appinfo='Progress performing render operation (0..1)'
/>
<field name='renderCompleteTime' type='SFTime' accessType='outputOnly'
appinfo='Render operation complete'
/>
<field name='movieFormat' type='MFString' accessType='initializeOnly'
appinfo='Format of rendered output movie (mpeg mp4 etc.)'
/>
<field name='imageFormat' type='MFString' accessType='initializeOnly'
appinfo='Format of rendered output images (png jpeg gif tiff etc.)'
/>
<field name='traceEnabled' type='SFBool' accessType='initializeOnly'
appinfo='enable console output to trace script computations and prototype progress'
/>
<IS>
<connect nodeField='description' protoField='description'/>
<connect nodeField='enabled' protoField='enabled'/>
<connect nodeField='frameRate' protoField='frameRate'/>
<connect nodeField='frameSize' protoField='frameSize'/>
<connect nodeField='pixelAspectRatio' protoField='pixelAspectRatio'/>
<connect nodeField='set_startTime' protoField='set_startTime'/>
<connect nodeField='progress' protoField='progress'/>
<connect nodeField='renderCompleteTime' protoField='renderCompleteTime'/>
<connect nodeField='movieFormat' protoField='movieFormat'/>
<connect nodeField='imageFormat' protoField='imageFormat'/>
<connect nodeField='traceEnabled' protoField='traceEnabled'/>
</IS>
<![CDATA[
ecmascript:
function initialize () // OfflineRenderScript
{
// tracePrint ('initialize start...');
tracePrint ('... initialize complete');
}
function set_description (eventValue) // input event received for inputOutput field
{
description = eventValue;
}
function set_enabled (eventValue) // input event received for inputOutput field
{
enabled = eventValue;
}
function set_frameRate (eventValue) // input event received for inputOutput field
{
frameRate = eventValue;
}
function set_frameSize (eventValue) // input event received for inputOutput field
{
frameSize = eventValue;
}
function set_pixelAspectRatio (eventValue) // input event received for inputOutput field
{
pixelAspectRatio = eventValue;
}
function set_startTime (eventValue) // input event received for inputOnly field
{
// do something with input eventValue;
}
function tracePrint (outputValue)
{
if (traceEnabled) alwaysPrint (outputValue);
}
function alwaysPrint (outputValue)
{
// try to ensure outputValue is converted to string despite browser idiosyncracies
var outputString = outputValue.toString(); // utility function according to spec
if (outputString == null) outputString = outputValue; // direct cast
if (description.length > 0)
Browser.println ('[OfflineRender: ' + description + '] ' + outputString);
else
Browser.println ('[OfflineRender] ' + outputString);
}
]]>
</Scene>