<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.2//EN" "http://www.web3d.org/specifications/x3d-3.2.dtd">
<X3D profile='Immersiveversion='3.2xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation=' http://www.web3d.org/specifications/x3d-3.2.xsd '>
<head>
<meta name='titlecontent='CameraPrototypes.x3d'/>
<meta name='descriptioncontent='Camera, CameraShot and CameraMove prototypes that demonstrate storyboard capabilities and precise camera operation. This is a developmental effort for potential X3D Specification improvement.'/>
<meta name='creatorcontent='Don Brutzman and Jeff Weekley'/>
<meta name='createdcontent='16 March 2009'/>
<meta name='modifiedcontent='25 December 2010'/>
<meta name='TODOcontent='Schematron rules, backed up by initialize() checks'/>
<meta name='referencecontent='BeyondViewpointCameraNodesWeb3D2009.pdf'/>
<meta name='referencecontent=' http://www.web3d.org/x3d/specifications/ISO-IEC-FDIS-19775-1.2-X3D-AbstractSpecification/Part01/components/navigation.html '/>
<meta name='subjectcontent='Camera nodes for Viewpoint navigation control'/>
<meta name='referencecontent='CameraExamples.x3d'/>
<meta name='identifiercontent=' http://www.web3d.org/x3d/content/examples/Basic/development/CameraPrototypes.x3d '/>
<meta name='referencecontent=' http://x3d.svn.sourceforge.net/viewvc/x3d/www.web3d.org/x3d/content/examples/Basic/development/CameraPrototypes.x3d '/>
<meta name='generatorcontent='X3D-Edit 3.2, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent=' ../license.html'/>
</head>
<!-- -->
<Scene>
<!-- =============== Camera ============== -->
<ProtoDeclare name='Cameraappinfo='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='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this Camera'/>
<field name='positiontype='SFVec3fvalue='0 0 10accessType='inputOutput'
 appinfo='Camera position in local transformation frame, which is default prior to first CameraShot initialPosition getting activated'/>
<field name='orientationtype='SFRotationvalue='0 0 1 0accessType='inputOutput'
 appinfo='Camera rotation in local transformation frame, which is default prior to first CameraShot initialPosition getting activated'/>
<field name='fieldOfViewtype='SFFloatvalue='0.7854accessType='inputOutput'
 appinfo='pi/4'/>
<field name='set_fractiontype='SFFloataccessType='inputOnly'
 appinfo='input fraction drives interpolators'/>
<field name='set_bindtype='SFBoolaccessType='inputOnly'
 appinfo='input event binds or unbinds this Camera'/>
<field name='bindTimetype='SFTimeaccessType='outputOnly'
 appinfo='output event indicates when this Camera is bound'/>
<field name='isBoundtype='SFBoolaccessType='outputOnly'
 appinfo='output event indicates whether this Camera is bound or unbound'/>
<field name='nearClipPlanetype='SFFloatvalue='0.25accessType='inputOutput'
 appinfo='Vector distance to near clipping plane corresponds to NavigationInfo.avatarSize[0]'/>
<field name='farClipPlanetype='SFFloatvalue='0.0accessType='inputOutput'
 appinfo='Vector distance to far clipping plane corresponds to NavigationInfo.visibilityLimit'/>
<field name='shotstype='MFNodeaccessType='inputOutput'
 appinfo='Array of CameraShot nodes which in turn contain CameraMovement nodes'>
<!-- initialization nodes (if any) go here -->
</field>
<field name='headlighttype='SFBoolvalue='trueaccessType='inputOutput'
 appinfo='Whether camera headlight is on or off'/>
<field name='headlightColortype='SFColorvalue='1 1 1accessType='inputOutput'
 appinfo='Camera headlight color'/>
<field name='headlightIntensitytype='SFFloatvalue='1accessType='inputOutput'
 appinfo='Camera headlight intensity'/>
<field name='filterColortype='SFColorvalue='1 1 1accessType='inputOutput'
 appinfo='Camera filter color that modifies virtual lens capture'/>
<field name='filterTransparencytype='SFFloatvalue='1accessType='inputOutput'
 appinfo='Camera filter transparency that modifies virtual lens capture'/>
<field name='upVectortype='SFVec3fvalue='0 1 0accessType='inputOutput'
 appinfo='upVector changes modify camera orientation (and possibly vice versa)'/>
<field name='fStoptype='SFFloatvalue='5.6accessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='focusDistancetype='SFFloatvalue='10accessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='totalDurationtype='SFTimeaccessType='outputOnly'
 appinfo='Total duration of contained enabled CameraShot (and thus CameraMovement) move durations'/>
<field name='offlineRendertype='SFNodeaccessType='inputOutput'
 appinfo='OfflineRender node'>
<!-- initialization node (if any) goes here -->
</field>
<field name='traceEnabledtype='SFBoolvalue='falseaccessType='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='CameraViewpointretainUserOffsets='false'>
<IS>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='positionprotoField='position'/>
<connect nodeField='orientationprotoField='orientation'/>
<connect nodeField='fieldOfViewprotoField='fieldOfView'/>
<connect nodeField='set_bindprotoField='set_bind'/>
<connect nodeField='bindTimeprotoField='bindTime'/>
<connect nodeField='isBoundprotoField='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='CameraNavInfotype='"EXAMINE" "FLY" "ANY"transitionType='"ANIMATE"transitionTime='1.0'>
<IS>
<connect nodeField='set_bindprotoField='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='headlightprotoField='headlight'/>
<connect nodeField='visibilityLimitprotoField='farClipPlane'/>
</IS>
</NavigationInfo>
<!-- this DirectionalLight replaces NavigationInfo headlight in order to add color capability -->
<!-- CameraDirectionalLight ROUTE:  [from CameraScript.isActive to on ] -->
<DirectionalLight DEF='CameraDirectionalLightglobal='true'>
<!-- TODO confirm other default field values match NavigationInfo spec -->
<IS>
<connect nodeField='onprotoField='headlight'/>
<connect nodeField='colorprotoField='headlightColor'/>
<connect nodeField='intensityprotoField='headlightIntensity'/>
</IS>
</DirectionalLight>
<!-- CameraPositionInterpolator ROUTE:  [from value_changed to CameraViewpoint.position ] -->
<PositionInterpolator DEF='CameraPositionInterpolatorkey='0 1keyValue='0 0 0 0 0 0'>
<IS>
<connect nodeField='set_fractionprotoField='set_fraction'/>
</IS>
</PositionInterpolator>
<!-- CameraOrientationInterpolator ROUTE:  [from value_changed to CameraViewpoint.orientation ] -->
<OrientationInterpolator DEF='CameraOrientationInterpolatorkey='0 1keyValue='0 1 0 0 0 1 0 0'>
<IS>
<connect nodeField='set_fractionprotoField='set_fraction'/>
</IS>
</OrientationInterpolator>
<ROUTE fromNode='CameraPositionInterpolatorfromField='value_changedtoNode='CameraViewpointtoField='position'/>
<ROUTE fromNode='CameraOrientationInterpolatorfromField='value_changedtoNode='CameraViewpointtoField='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='CameraScriptdirectOutput='truemustEvaluate='true'>
<!-- binding is controlled externally, all camera operations proceed the same regardless of whether bound or not -->
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this Camera'/>
<field name='positiontype='SFVec3faccessType='inputOutput'
 appinfo='Camera position in local transformation frame'/>
<field name='orientationtype='SFRotationaccessType='inputOutput'
 appinfo='Camera rotation in local transformation frame'/>
<field name='set_fractiontype='SFFloataccessType='inputOnly'
 appinfo='input fraction drives interpolators'/>
<field name='set_bindtype='SFBoolaccessType='inputOnly'
 appinfo='input event binds or unbinds this Camera'/>
<field name='fieldOfViewtype='SFFloataccessType='inputOutput'
 appinfo='pi/4'/>
<field name='nearClipPlanetype='SFFloataccessType='inputOutput'
 appinfo='Vector distance to near clipping plane'/>
<field name='farClipPlanetype='SFFloataccessType='inputOutput'
 appinfo='Vector distance to far clipping plane'/>
<field name='shotstype='MFNodeaccessType='inputOutput'
 appinfo='Array of CameraShot nodes which in turn contain CameraMovement nodes'>
<!-- initialization nodes (if any) go here -->
</field>
<field name='filterColortype='SFColoraccessType='inputOutput'
 appinfo='Camera filter color that modifies virtual lens capture'/>
<field name='filterTransparencytype='SFFloataccessType='inputOutput'
 appinfo='Camera filter transparency that modifies virtual lens capture'/>
<field name='upVectortype='SFVec3faccessType='inputOutput'
 appinfo='upVector changes modify camera orientation (and possibly vice versa)'/>
<field name='fStoptype='SFFloataccessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='focusDistancetype='SFFloataccessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='totalDurationtype='SFTimeaccessType='outputOnly'
 appinfo='Total duration of contained enabled CameraShot (and thus CameraMovement) move durations'/>
<field name='offlineRendertype='SFNodeaccessType='inputOutput'
 appinfo='OfflineRender node'>
<!-- initialization node (if any) goes here -->
</field>
<field name='ViewpointNodetype='SFNodeaccessType='initializeOnly'
 appinfo='node reference to permit getting setting fields from within Script'>
<Viewpoint USE='CameraViewpointretainUserOffsets='false'/>
</field>
<field name='NavInfoNodetype='SFNodeaccessType='initializeOnly'
 appinfo='node reference to permit getting setting fields from within Script'>
<NavigationInfo USE='CameraNavInfotype='"EXAMINE" "ANY"transitionType='"ANIMATE"transitionTime='1.0'/>
</field>
<field name='CameraPItype='SFNodeaccessType='initializeOnly'
 appinfo='node reference to permit getting setting fields from within Script'>
<PositionInterpolator USE='CameraPositionInterpolator'/>
</field>
<field name='CameraOItype='SFNodeaccessType='initializeOnly'
 appinfo='node reference to permit getting setting fields from within Script'>
<OrientationInterpolator USE='CameraOrientationInterpolator'/>
</field>
<field name='keytype='MFFloataccessType='inputOutput'
 appinfo='key array for interpolators'/>
<field name='keyValuePositiontype='MFVec3faccessType='inputOutput'
 appinfo='keyValue array for PositionInterpolator'/>
<field name='keyValueOrientationtype='MFRotationaccessType='inputOutput'
 appinfo='keyValue array for OrientationInterpolator'/>
<field name='animatedtype='SFBoolvalue='falseaccessType='inputOutput'
 appinfo='whether internal CameraShot and CameraMove nodes are tracking or changed via ROUTE events'/>
<field name='initializedtype='SFBoolvalue='falseaccessType='initializeOnly'
 appinfo='perform checkShots() function once immediately after initialization'/>
<field name='shotCounttype='SFInt32value='0accessType='initializeOnly'
 appinfo='how many CameraShot nodes are contained in shots array'/>
<field name='movesCounttype='SFInt32value='0accessType='initializeOnly'
 appinfo='how many CameraMove nodes are contained in moves array'/>
<field name='frameCounttype='SFFloatvalue='0accessType='initializeOnly'
 appinfo='how many frames were created in current loop'/>
<field name='startTimetype='SFTimevalue='0accessType='initializeOnly'
 appinfo='holding variable'/>
<field name='priorTraceTimetype='SFTimevalue='0accessType='initializeOnly'
 appinfo='holding variable'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'
 appinfo='enable console output to trace script computations and prototype progress'/>
<IS>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='positionprotoField='position'/>
<connect nodeField='orientationprotoField='orientation'/>
<connect nodeField='set_fractionprotoField='set_fraction'/>
<connect nodeField='set_bindprotoField='set_bind'/>
<connect nodeField='fieldOfViewprotoField='fieldOfView'/>
<connect nodeField='nearClipPlaneprotoField='nearClipPlane'/>
<connect nodeField='farClipPlaneprotoField='farClipPlane'/>
<connect nodeField='shotsprotoField='shots'/>
<connect nodeField='filterColorprotoField='filterColor'/>
<connect nodeField='filterTransparencyprotoField='filterTransparency'/>
<connect nodeField='upVectorprotoField='upVector'/>
<connect nodeField='fStopprotoField='fStop'/>
<connect nodeField='focusDistanceprotoField='focusDistance'/>
<connect nodeField='isActiveprotoField='isActive'/>
<connect nodeField='totalDurationprotoField='totalDuration'/>
<connect nodeField='offlineRenderprotoField='offlineRender'/>
<connect nodeField='traceEnabledprotoField='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');
}

        
]]>
</Script>
<ROUTE fromNode='CameraScriptfromField='positiontoNode='CameraViewpointtoField='position'/>
<ROUTE fromNode='CameraScriptfromField='orientationtoNode='CameraViewpointtoField='orientation'/>
<ROUTE fromNode='CameraScriptfromField='isActivetoNode='CameraViewpointtoField='set_bind'/>
<ROUTE fromNode='CameraScriptfromField='isActivetoNode='CameraNavInfotoField='set_bind'/>
<ROUTE fromNode='CameraScriptfromField='isActivetoNode='CameraDirectionalLighttoField='on'/>
</ProtoBody>
</ProtoDeclare>
<!-- =============== CameraShot ============== -->
<ProtoDeclare name='CameraShotappinfo='CameraShot collects a specific set of CameraMovement animations that make up an individual shot'>
<ProtoInterface>
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this CameraShot'/>
<field name='enabledtype='SFBoolvalue='trueaccessType='inputOutput'
 appinfo='Whether this CameraShot can be activated'/>
<field name='movestype='MFNodeaccessType='inputOutput'
 appinfo='Set of CameraMovement nodes'>
<!-- initialization nodes (if any) go here -->
</field>
<field name='initialPositiontype='SFVec3fvalue='0 0 10accessType='inputOutput'
 appinfo='Setup to reinitialize camera position for this shot'/>
<field name='initialOrientationtype='SFRotationvalue='0 0 1 0accessType='inputOutput'
 appinfo='Setup to reinitialize camera rotation for this shot'/>
<field name='initialAimPointtype='SFVec3fvalue='0 0 0accessType='inputOutput'
 appinfo='Setup to reinitialize aimpoint (relative location for camera direction) for this shot'/>
<field name='initialFieldOfViewtype='SFFloatvalue='0.7854accessType='inputOutput'
 appinfo='pi/4'/>
<field name='initialFStoptype='SFFloatvalue='5.6accessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='initialFocusDistancetype='SFFloatvalue='10accessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='shotDurationtype='SFTimeaccessType='outputOnly'
 appinfo='Subtotal duration of contained CameraMovement move durations'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='traceEnabledtype='SFBoolvalue='falseaccessType='initializeOnly'
 appinfo='enable console output to trace script computations and prototype progress'/>
</ProtoInterface>
<ProtoBody>
<Script DEF='CameraShotScriptdirectOutput='truemustEvaluate='true'>
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this CameraShot'/>
<field name='enabledtype='SFBoolaccessType='inputOutput'
 appinfo='Whether this CameraShot can be activated'/>
<field name='movestype='MFNodeaccessType='inputOutput'
 appinfo='Set of CameraMovement nodes'>
<!-- initialization nodes (if any) go here -->
</field>
<field name='initialPositiontype='SFVec3faccessType='inputOutput'
 appinfo='Setup to reinitialize camera position for this shot'/>
<field name='initialOrientationtype='SFRotationaccessType='inputOutput'
 appinfo='Setup to reinitialize camera rotation for this shot'/>
<field name='initialAimPointtype='SFVec3faccessType='inputOutput'
 appinfo='Setup to reinitialize aimpoint (relative location for camera direction) for this shot'/>
<field name='initialFieldOfViewtype='SFFloataccessType='inputOutput'
 appinfo='pi/4'/>
<field name='initialFStoptype='SFFloataccessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='initialFocusDistancetype='SFFloataccessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='shotDurationtype='SFTimeaccessType='outputOnly'
 appinfo='Subtotal duration of contained CameraMovement move durations'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'
 appinfo='enable console output to trace script computations and prototype progress'/>
<field name='keytype='MFFloataccessType='inputOutput'
 appinfo='key array for interpolators'/>
<field name='keyValuePositiontype='MFVec3faccessType='inputOutput'
 appinfo='keyValue array for PositionInterpolator'/>
<field name='keyValueOrientationtype='MFRotationaccessType='inputOutput'
 appinfo='keyValue array for OrientationInterpolator'/>
<IS>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='enabledprotoField='enabled'/>
<connect nodeField='movesprotoField='moves'/>
<connect nodeField='initialPositionprotoField='initialPosition'/>
<connect nodeField='initialOrientationprotoField='initialOrientation'/>
<connect nodeField='initialAimPointprotoField='initialAimPoint'/>
<connect nodeField='initialFieldOfViewprotoField='initialFieldOfView'/>
<connect nodeField='initialFStopprotoField='initialFStop'/>
<connect nodeField='initialFocusDistanceprotoField='initialFocusDistance'/>
<connect nodeField='shotDurationprotoField='shotDuration'/>
<connect nodeField='isActiveprotoField='isActive'/>
<connect nodeField='traceEnabledprotoField='traceEnabled'/>
</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='CameraMovementappinfo='CameraMovement defines a single camera movement animation'>
<ProtoInterface>
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this CameraMovement'/>
<field name='enabledtype='SFBoolvalue='trueaccessType='inputOutput'
 appinfo='Whether this CameraMovement can be activated'/>
<field name='durationtype='SFFloatvalue='0accessType='inputOutput'
 appinfo='Duration in seconds for this move'/>
<field name='goalPositiontype='SFVec3fvalue='0 0 10accessType='inputOutput'
 appinfo='Goal camera position for this move'/>
<field name='goalOrientationtype='SFRotationvalue='0 0 1 0accessType='inputOutput'
 appinfo='Goal camera rotation for this move'/>
<field name='trackingtype='SFBoolvalue='falseaccessType='inputOutput'
 appinfo='Whether or not camera direction is tracking towards the aimPoint'/>
<field name='goalAimPointtype='SFVec3fvalue='0 0 0accessType='inputOutput'
 appinfo='Goal aimPoint for this move, ignored if tracking=false'/>
<field name='goalFieldOfViewtype='SFFloatvalue='0.7854accessType='inputOutput'
 appinfo='Goal fieldOfView for this move'/>
<field name='goalFStoptype='SFFloatvalue='5.6accessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='goalFocusDistancetype='SFFloatvalue='10accessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='traceEnabledtype='SFBoolvalue='falseaccessType='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='CameraMovementScriptdirectOutput='truemustEvaluate='true'>
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this CameraMovement'/>
<field name='enabledtype='SFBoolaccessType='inputOutput'
 appinfo='Whether this CameraMovement can be activated'/>
<field name='durationtype='SFFloataccessType='inputOutput'
 appinfo='Duration in seconds for this move'/>
<field name='goalPositiontype='SFVec3faccessType='inputOutput'
 appinfo='Goal camera position for this move'/>
<field name='goalOrientationtype='SFRotationaccessType='inputOutput'
 appinfo='Goal camera rotation for this move'/>
<field name='trackingtype='SFBoolaccessType='inputOutput'
 appinfo='Whether or not camera direction is tracking towards the aimPoint'/>
<field name='goalAimPointtype='SFVec3faccessType='inputOutput'
 appinfo='Goal aimPoint for this move, ignored if tracking=false'/>
<field name='goalFieldOfViewtype='SFFloataccessType='inputOutput'
 appinfo='Goal fieldOfView for this move'/>
<field name='goalFStoptype='SFFloataccessType='inputOutput'
 appinfo='Focal length divided effective aperture diameter indicating width of focal plane'/>
<field name='goalFocusDistancetype='SFFloataccessType='inputOutput'
 appinfo='Distance to focal plane of sharpest focus'/>
<field name='isActivetype='SFBoolaccessType='outputOnly'
 appinfo='Mark start/stop with true/false output respectively useful to trigger external animations'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'
 appinfo='enable console output to trace script computations and prototype progress'/>
<IS>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='enabledprotoField='enabled'/>
<connect nodeField='durationprotoField='duration'/>
<connect nodeField='goalPositionprotoField='goalPosition'/>
<connect nodeField='goalOrientationprotoField='goalOrientation'/>
<connect nodeField='trackingprotoField='tracking'/>
<connect nodeField='goalAimPointprotoField='goalAimPoint'/>
<connect nodeField='goalFieldOfViewprotoField='goalFieldOfView'/>
<connect nodeField='goalFStopprotoField='goalFStop'/>
<connect nodeField='goalFocusDistanceprotoField='goalFocusDistance'/>
<connect nodeField='isActiveprotoField='isActive'/>
<connect nodeField='traceEnabledprotoField='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='OfflineRenderappinfo='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='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this OfflineRender'/>
<field name='enabledtype='SFBoolvalue='trueaccessType='inputOutput'
 appinfo='Whether this OfflineRender can be activated'/>
<field name='frameRatetype='SFFloatvalue='30accessType='inputOutput'
 appinfo='Frames per second recorded for this rendering'/>
<field name='frameSizetype='SFVec2fvalue='640 480accessType='inputOutput'
 appinfo='Size of frame in number of pixels width and height'/>
<field name='pixelAspectRatiotype='SFFloatvalue='1.33accessType='inputOutput'
 appinfo='Relative dimensions of pixel height/width typically 1.33 or 1'/>
<field name='set_startTimetype='SFTimeaccessType='inputOnly'
 appinfo='Begin render operation'/>
<field name='progresstype='SFFloataccessType='outputOnly'
 appinfo='Progress performing render operation (0..1)'/>
<field name='renderCompleteTimetype='SFTimeaccessType='outputOnly'
 appinfo='Render operation complete'/>
<field name='movieFormattype='MFStringvalue='mpegaccessType='initializeOnly'
 appinfo='Format of rendered output movie (mpeg mp4 etc.), use first supported format'/>
<field name='imageFormattype='MFStringvalue='pngaccessType='initializeOnly'
 appinfo='Format of rendered output images (png jpeg gif tiff etc.) use first supported format'/>
<field name='traceEnabledtype='SFBoolvalue='falseaccessType='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='OfflineRenderScriptdirectOutput='truemustEvaluate='true'>
<field name='descriptiontype='SFStringaccessType='inputOutput'
 appinfo='Text description to be displayed for this OfflineRender'/>
<field name='enabledtype='SFBoolaccessType='inputOutput'
 appinfo='Whether this OfflineRender can be activated'/>
<field name='frameRatetype='SFFloataccessType='inputOutput'
 appinfo='Frames per second recorded for this rendering'/>
<field name='frameSizetype='SFVec2faccessType='inputOutput'
 appinfo='Size of frame in number of pixels width and height'/>
<field name='pixelAspectRatiotype='SFFloataccessType='inputOutput'
 appinfo='Relative dimensions of pixel height/width typically 1.33 or 1'/>
<field name='set_startTimetype='SFTimeaccessType='inputOnly'
 appinfo='Begin render operation'/>
<field name='progresstype='SFFloataccessType='outputOnly'
 appinfo='Progress performing render operation (0..1)'/>
<field name='renderCompleteTimetype='SFTimeaccessType='outputOnly'
 appinfo='Render operation complete'/>
<field name='movieFormattype='MFStringaccessType='initializeOnly'
 appinfo='Format of rendered output movie (mpeg mp4 etc.)'/>
<field name='imageFormattype='MFStringaccessType='initializeOnly'
 appinfo='Format of rendered output images (png jpeg gif tiff etc.)'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'
 appinfo='enable console output to trace script computations and prototype progress'/>
<IS>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='enabledprotoField='enabled'/>
<connect nodeField='frameRateprotoField='frameRate'/>
<connect nodeField='frameSizeprotoField='frameSize'/>
<connect nodeField='pixelAspectRatioprotoField='pixelAspectRatio'/>
<connect nodeField='set_startTimeprotoField='set_startTime'/>
<connect nodeField='progressprotoField='progress'/>
<connect nodeField='renderCompleteTimeprotoField='renderCompleteTime'/>
<connect nodeField='movieFormatprotoField='movieFormat'/>
<connect nodeField='imageFormatprotoField='imageFormat'/>
<connect nodeField='traceEnabledprotoField='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');
}

        
]]>
</Script>
<!-- Add any ROUTEs here, going from Script to other nodes within ProtoBody -->
</ProtoBody>
</ProtoDeclare>
<!-- =============== Launch Prototype Example ============== -->
<Background skyColor='0.282353 0.380392 0.470588transparency='0'/>
<Anchor description='launch CameraExample scene'
  url=' "CameraExamples.x3d" "http://www.web3d.org/x3d/content/examples/Basic/development/CameraExamples.x3d" "CameraExamples.wrl" "http://www.web3d.org/x3d/content/examples/Basic/development/CameraExamples.wrl" '>
<Transform>
<Shape>
<Text string='"CameraPrototypes.x3d" "defines multiple prototype nodes" "" "Click on this text to see" "CameraExamples.x3d scene"solid='false'>
<FontStyle justify='"MIDDLE" "MIDDLE"'/>
</Text>
<Appearance>
<Material diffuseColor='1 1 0.2'/>
</Appearance>
</Shape>
</Transform>
</Anchor>
</Scene>
</X3D>
<!--

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
-->

<!-- Color key: <X3dNode DEF='idName' field='value'/> matches <XmlElement DEF='idName' attribute='value'/>     <Prototype name='ProtoName'> <field name='fieldName'/> </Prototype> -->