<
head>
</
head>
<!--
Index for ProtoDeclare definitions:
Camera,
CameraShot,
CameraMovement,
OfflineRender
Index for DEF nodes:
CameraDirectionalLight,
CameraMovementScript,
CameraNavInfo,
CameraOrientationInterpolator,
CameraPositionInterpolator,
CameraScript,
CameraShotScript,
CameraViewpoint,
OfflineRenderScript
Index for Viewpoint images:
CameraViewpoint,
Viewpoint_2
-->
<
Scene>
<!-- =============== Camera ============== -->
<
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'>
<
ProtoInterface>
<!-- Viewpoint-related fields, NavigationInfo-related fields and Camera-unique fields -->
<
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>
<!--
CameraViewpoint ROUTEs:
[
from CameraPositionInterpolator.value_changed to position
]
[
from CameraOrientationInterpolator.value_changed to orientation
]
[
from CameraScript.position to position
]
[
from CameraScript.orientation to orientation
]
[
from CameraScript.isActive to set_bind
]
-->
<
Viewpoint DEF='
CameraViewpoint'
retainUserOffsets='
false'>
<
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 -->
<!--
CameraNavInfo ROUTE:
[
from CameraScript.isActive to set_bind
]
-->
<
NavigationInfo DEF='
CameraNavInfo'
type='
"EXAMINE" "FLY" "ANY"'
transitionType='
"ANIMATE"'
transitionTime='
1.0'>
<
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 -->
<!--
CameraDirectionalLight ROUTE:
[
from CameraScript.isActive to on
]
-->
<
DirectionalLight DEF='
CameraDirectionalLight'
global='
true'>
<!-- TODO confirm other default field values match NavigationInfo spec -->
<
IS>
</
IS>
</
DirectionalLight>
<!--
CameraPositionInterpolator ROUTE:
[
from value_changed to CameraViewpoint.position
]
-->
<
PositionInterpolator DEF='
CameraPositionInterpolator'
key='
0 1'
keyValue='
0 0 0 0 0 0'>
<
IS>
<
connect nodeField='
set_fraction'
protoField='
set_fraction'/>
</
IS>
</
PositionInterpolator>
<!--
CameraOrientationInterpolator ROUTE:
[
from value_changed to CameraViewpoint.orientation
]
-->
<
OrientationInterpolator DEF='
CameraOrientationInterpolator'
key='
0 1'
keyValue='
0 1 0 0 0 1 0 0'>
<
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'/>
<!--
CameraScript ROUTEs:
[
from position to CameraViewpoint.position
]
[
from orientation to CameraViewpoint.orientation
]
[
from isActive to CameraViewpoint.set_bind
]
[
from isActive to CameraNavInfo.set_bind
]
[
from isActive to CameraDirectionalLight.on
]
-->
<
Script DEF='
CameraScript'
directOutput='
true'
mustEvaluate='
true'>
<!-- 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'>
<
NavigationInfo USE='
CameraNavInfo'
type='
"EXAMINE" "ANY"'
transitionType='
"ANIMATE"'
transitionTime='
1.0'/>
</
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() + '\n');
}
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.print ('[Camera: ' + description + '] ' + outputString + '\n');
else
Browser.print ('[Camera] ' + outputString + '\n');
}
]]>
</
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'>
<!-- initialization nodes (if any) go here -->
</
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.print ('[CameraShot: ' + description + '] ' + outputString + '\n');
else
Browser.print ('[CameraShot] ' + outputString + '\n');
}
]]>
</
Script>
<!-- Add any ROUTEs here, going from Script to other nodes within ProtoBody -->
</
ProtoBody>
</
ProtoDeclare>
<!-- =============== CameraMovement ============== -->
<
ProtoDeclare name='
CameraMovement'
appinfo='
CameraMovement defines a single camera movement animation'>
<
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.print ('[CameraMovement: ' + description + '] ' + outputString + '\n');
else
Browser.print ('[CameraMovement] ' + outputString + '\n');
}
]]>
</
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>
<!-- TODO non-photorealistic rendering (NPR) parameters -->
<
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'/>
</
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'
directOutput='
true'
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.print ('[OfflineRender: ' + description + '] ' + outputString + '\n');
else
Browser.print ('[OfflineRender] ' + outputString + '\n');
}
]]>
</
Scene>