Creating New Node Types
Motivation
You can create new node types that encapsulate:
- Shapes
- Sensors
- Interpolators
- Scripts
- anything else …
This creates high-level nodes:
- Robots, menus, new shapes, etc.
Syntax: PROTO
A PROTO statement declares a new node type (a prototype):
- name - the new node type name
- fields, inputs, and outputs - interface to the prototype
XML Encoding
1
2
3
4
5
6
7
8
9
<ProtoDeclare name='BouncingBall'>
  <ProtoInterface>
    <field accessType='inputOutput' type='SFTime' name='cycleInterval' value='1'/>
    <field accessType='initializeOnly' type='SFFloat' name='bounceHeight' value='1'/>
  </ProtoInterface>
  <ProtoBody>
    <!-- ... -->
  </ProtoBody>
</ProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
PROTO BouncingBall [
  inputOutput    SFTime  cycleInterval 1.0
  initializeOnly SFFloat bounceHeight  1.0
]
{
  ...
}
Defining prototype bodies
PROTO defines:
- body - nodes and routes for the new node type
XML Encoding
1
2
3
4
5
6
7
8
9
10
11
<ProtoDeclare name='BouncingBall'>
  <ProtoInterface>
    <!-- ... -->
  </ProtoInterface>
  <ProtoBody>
    <Transform>
      <!-- children ... -->
    </Transform>
    <ROUTE ... />
  </ProtoBody>
</ProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
8
9
PROTO BouncingBall [
  ...
]
{
  Transform {
    children [ ... ]
  }
  ROUTE ...
}
Syntax: IS
The IS syntax connects a prototype interface field, input, or output to the body:
- Like an assignment statement
- Assigns interface field or input to body
- Assigns body outputs to interface
Interface items connected by IS need not have the same name as an item in the body, but often do:
XML Encoding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ProtoDeclare name='BouncingBall'>
  <ProtoInterface>
    <field accessType='inputOutput' type='SFTime' name='cycleInterval' value='1'/>
    <field accessType='initializeOnly' type='SFFloat' name='bounceHeight' value='1'/>
  </ProtoInterface>
  <ProtoBody>
    <!-- ... -->
    <TimeSensor DEF='Clock' ... >
      <IS>
        <connect nodeField='cycleInterval' protoField='cycleInterval'/>
        <!-- ... -->
      </IS>
    </TimeSensor>
    <!-- ... -->
  </ProtoBody>
</ProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
8
9
10
11
12
PROTO BouncingBall [
  inputOutput    SFTime  cycleInterval 1.0
  initializeOnly SFFloat bounceHeight  1.0
]
{
  ...
  DEF Clock TimeSensor {
    cycleInterval IS cycleInterval
    ...
  }
  ...
}
Using IS
May IS to …
| Interface | initializeOnly | inputOnly | outputOnly | inputOutput | 
|---|---|---|---|---|
| initializeOnly | yes | no | no | yes | 
| inputOnly | no | yes | no | yes | 
| outputOnly | no | no | yes | yes | 
| inputOutput | no | no | no | yes | 
Using prototyped nodes
The new node type can be used like any other type.
XML Encoding
1
2
3
4
5
6
7
8
9
<!-- Official Syntax -->
<ProtoInstance name='BouncingBall'>
  <fieldValue name='cycleInterval' value='2'/>
  <fieldValue name='bounceHeight' value='3'/>
</ProtoInstance>
<!-- Short Syntax -->
<BouncingBall
    cycleInterval='2'
    bounceHeight='3'/>
Classic VRML Encoding
1
2
3
4
BouncingBall {
  cycleInterval 2.0
  bounceHeight  3.0
}
Example
 
 Controlling usage rules
Recall that node use must be appropriate for the context:
- A Shape node specifies shape, not color
- A Material node specifies color, not shape
- A Box node specifies geometry, not shape or color
The context for a new node type depends upon the first node in the PROTO body.
For example, if the first node is a geometry node:
- The prototype creates a new geometry node type
The new node type can be used wherever the first node of the prototype body can be used.
- In XML the default value of the »containerField« attribute of a ProtoInstance element is »children«. Change this attribute to whatever value you need.
XML Encoding
1
2
3
4
5
6
7
8
9
10
<Shape>
  <!-- Official Syntax -->
  <ProtoInstance name='Torus' containerField='geometry'>
    <!-- ... -->
  </ProtoInstance>
</Shape>
<Shape>
  <!-- Short Syntax -->
  <Torus containerField='geometry' .../>
</Shape>
A sample prototype use
Create a BouncingBall node type that:
- Builds a beachball- Creates an animation clock
- Using a PROTO field to select the cycle interval
 
- Bounces the beachball- Using the bouncing ball program script
- Using a PROTO field to select the bounce height
 
Fields needed:
- Bounce height
- Cycle interval
XML Encoding
1
2
3
4
5
6
7
8
9
<ProtoDeclare name='BouncingBall'>
  <ProtoInterface>
    <field accessType='inputOutput' type='SFTime' name='cycleInterval' value='1'/>
    <field accessType='initializeOnly' type='SFFloat' name='bounceHeight' value='1'/>
  </ProtoInterface>
  <ProtoBody>
    <!-- ... -->
  </ProtoBody>
</ProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
PROTO BouncingBall [
  inputOutput    SFTime  cycleInterval 1.0
  initializeOnly SFFloat bounceHeight 1.0
]
{
  ...
}
Inputs and outputs needed:
- None - a TimeSensor node is built in to the new node
Body needed:
- A ball shape inside a transform
- An animation clock
- A bouncing ball program script
- Routes connecting it all together
XML Encoding
1
2
3
4
5
6
7
8
9
10
11
12
13
<ProtoDeclare name='BouncingBall'>
  <ProtoInterface>
    <!-- ... -->
  </ProtoInterface>
  <ProtoBody>
    <Transform DEF='Ball'>
      <Shape><!-- ... --></Shape>
    </Transform>
    <TimeSensor DEF='Clock' ... />
    <Script DEF='Bouncer' ... />
    <ROUTE ... />
  </ProtoBody>
</ProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
8
9
10
11
12
13
PROTO BouncingBall [
  ...
]
{
  DEF Ball Transform {
    children [
      Shape { ... }
    ]
  }
  DEF Clock   TimeSensor { ... }
  DEF Bouncer Script { ... }
  ROUTE ...
}
Changing a prototype
If you change a prototype, all uses of that prototype change as well
- Prototypes enable world modularity
- Large worlds make heavy use of prototypes
For the BouncingBall prototype, adding a shadow to the prototype makes all balls have a shadow.
Syntax: EXTERNPROTO
Prototypes are typically in a separate external file, referenced by an EXTERNPROTO
- name, fields, events - as from PROTO, minus initial values
- url - the URL of the prototype file
- #name - name of PROTO in file
XML Encoding
1
2
3
4
<ExternProtoDeclare name='BouncingBall' url='"bounce.x3dv#BouncingBall", "bounce.x3d#BouncingBall"'>
  <field accessType='inputOutput' type='SFTime' name='cycleInterval'/>
  <field accessType='initializeOnly' type='SFFloat' name='bounceHeight'/>
</ExternProtoDeclare>
Classic VRML Encoding
1
2
3
4
5
6
7
8
EXTERNPROTO BouncingBall [
  inputOutput    SFTime  cycleInterval
  initializeOnly SFFloat bounceHeight
]
[
  "bounce.x3dv#BouncingBall",
  "bounce.x3d#BouncingBall"
]
Example
 
 Summary
- PROTO declares a new node type and defines its node body
- EXTERNPROTO declares a new node type, specified by URL