instantreality 1.0

Creating custom nodes with Prototypes

Keywords:
PROTO, Prototypes, Nodes, Extension
Author(s): Jens Keil
Date: 2009-11-11

Summary: This tutorials shows how to structure X3D files, how to create custom node types with special functionality and how to make those nodes reusable for other projects.

Introduction

In the following it is assumed that the reader is already familiar with the basic X3D structure and node types and knows, how to create X3D content.

A common and known issue when creating X3D content is the fact, that the X3D file might become very large, since one has to describe not only the 3D world's content, but also the behavior and logic. In result, the file appears somehow clattered and unstructured. On the other hand, sometimes it is necessary to give a node or parts of the scene some special behavior, that might be (re)used a couple of times. For example, the transparency field of an ImageTexture node, that shall be increased or decreased, whenever it is touched. In all of this cases, it is possible to create an own new node prototype, which enholds the declaration, thus separating it from your main file. Prototypes can help you structuring your files or make code snippes reusable again very easily. It is also possible to somehow extend existing nodes with own, special behavior. For example, imagine a special Appearance node that lets any given Texture appear to pulse or to glow. Prototyped nodes behave like an OOP class definitions, where you once declare a Proto node, that can be instanciated within (anohter) X3D file then.

Structure

Prototypes or PROTOs have a special structure, that is mandatory. Like any X3D file, prototypes are wrapped inside an X3D and Scene node. A Prototype begins with a ProtoDeclare, wich is is more or less the inital declaration of its name. After that, node fields have to be described inside the ProtoInterface. Those fields can be accessed form outside later on. The final content is then implemented inside the ProtoBody node. Via the IS/connect statement, nodes and fields from the proto interface are connected and linked to those in the proto body.

Code: Basic Proto structure


<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D version='3.0'>
    <Scene>
        <ProtoDeclaration name="MyNewNode">
            <ProtoInterface>
                <field name="myNewField" accessType="inputOutput" value="" />
            </ProtoInterface>
            <ProtoBody>
                <!-- Some content implementation here -->
            </ProtoBody>
        </ProtoDeclaration>
    </Scene>
</X3D>

Note, that only the declared fields inside the ProtoInterface can be accessed from outside. Those fields can be considered as public attributes of a class file.

Warning: In order to have any visible geometry after instantiating a proto node, you first have to declare the visible parts after beginning with the ProtoBody.

This is due to the fact, that your proto node more or less is derrived from the node that is declared first. Imagine, there is a Sphere node (within a Transform and Shape node) and a Script node described within the ProtoBody. Since a Script node has no visible gemoetry at all, you have to describe the Sphere first. Otherwise you won't see any visible geometry after instantiating.

Declaration and instantiation

It is legal to describe more than one Prototype per file. As mentioned above, each new Prototype is defined in the ProtoDeclare statement, which consists of the ProtoDeclare element, a name attribute, an optional ProtoInterface containing the interface field declarations, and a ProtoBody containing the Prototype body definition. If a Prototype shall be used within the file where it is declared, it can be instantiated by the ProtoInstance node, where the name field corresponds to the name of the Protoype defined in the proto declaration (e.g. <ProtoInstance name="MyNewNode">).

If the proto is declared inside an external file, you first have to refer to it by using the ExternProtoDeclare statement. This statement contains a name attribute which references the Prototype, and a url of one or more addresses pointing to the file that contains the Prototype definition. At each filename (or address) in a url value should be appended a # symbol, followed by the name of the Prototype. Furthermore, the ExternProtoDeclare comprises zero or more field definitions (depending on the number of fields defined in the Prototype itself), which provide the interface for the prototype.

Code: ExternProtoDeclare and proto instantiation


<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D version='3.0'>
    <Scene>
        <!-- link to externally declared proto -->
        <ExternProtoDeclare name="MyNewNode" url="MyNewNode_PROTO.x3D#MyNewNode" />
                <field name="myNewField" accessType="inputOutput" />
        </ExternProtoDeclare>
        
        <!-- instantiation of the proto -->
        <ProtoInstance name="MyNewNode">
            <fieldValue name="myNewField" value="" />
        </ProtoInstance>
    </Scene>
</X3D>

IS and connect statements

The real magic is done by connecting the proto fields with corresponding fields inside the ProtoBody. Imagine, the translation, rotation and scale of aTransform node shall be be accessible from outside: First describe the three fields inside the ProtoInterface and then connect it with the Transform node declaration insinde the ProtoBody.

Code: Connecting fields


<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D version='3.0'>
    <Scene>
        <ProtoDeclaration name="MyNewNode">
            <ProtoInterface>
                <field name="translation" accessType="SFVec3f" value="0 0 0" />
                <field name="rotation" accessType="SFRotation" value="0 0 0 1" />
                <field name="scale" accessType="SFVec3f" value="0 0 0" />
            </ProtoInterface>
            <ProtoBody>
                <Transform>
                    <IS>
                        <connect protoField="translation" nodeField="translation" />
                        <connect protoField="rotation" nodeField="rotation" />
                        <connect protoField="scale" nodeField="scale" />
                    </IS>
                    <!-- some geometry here -->
                </Transform>
            </ProtoBody>
        </ProtoDeclaration>
    </Scene>
</X3D>

Because of its connection translation, rotation and scale can be directly manipulated and be accessed from outside. The ProtoInterface field's name doesn't have to match the standard one's of the Transform node. In fact, it can have any distiguishable, accurate XML valid name you like. Here, the names are identical, because nodeField and protoField names may be the same or, more general, they may be also overloaded as well; i.e., these two names may be identical since each is part of a different namespace.

Conclusion

This tutorial showed, how to create custom nodes with special functionality and how to make those nodes reusable for other projects. The interface and the structure for those Prototypes has been explained. Finally, check out the example files of this tutorial.

Image: Proto example

Please note: This tutorial only covered the XML syntax of X3D. For VRML syntax please refer to The Annotated VRML 97 Reference, chapter 2.8 and The Annotated VRML 97 Reference, chapter 2.9. However, the next little code snippet shows how to use a PROTO (in this case a custom material node) in VRML syntax.

Code: Simple Proto in VRML syntax

PROTO Gold [
	exposedField SFColor color 0.9 0.8 0.2
]
{
	Material { 
		diffuseColor IS color
	}
}

Shape {
	appearance Appearance {
		material Gold {}
	}
	geometry Sphere {}
}

Files:  

Comments

This tutorial has no comments.


Add a new comment

Due to excessive spamming we have disabled the comment functionality for tutorials. Please use our forum to post any questions.