VRML Tubing Extension Proposal

This page describes a proposed extension to VRML to handle extruded surfaces. An extruded surface is a surface that is generated by moving a 2D curve along a 3D path. Surfaces of revolution, sweeps, and polycylinders are all examples of extruded surfaces. The pictures below show examples of extrusions.

Extrusions are interesting because they potentially provide for a compact representation of surface data. A swept surface of m points by n points requires O(m x n) bytes of data to represent it as a quadrilateral mesh. The same surface requires only O(m + n) bytes when represented as a sweep.

Extrusions are also interesting because they allow a designer to specify complex shapes in a simple manner.

This proposal is based on the API provided through the freely available tubing and extrusion library. The tubing and extrusion library is a C language API that renders extrusions through OpenGL. It automatically generates the surface, normals for lighting, and texture coordinates.

The Proposal

Below follows the proposal. It is preliminary. Alternate suggestions are welcome. You may find this spec to be "under-specified". For immediate questions, consult the tubing/extrusion API documentation and examples. The spec will be updated in time.

(Warning ... this spec is or may soon be superceeded by a similar but different spec in the Moving Worlds proposal. If in doubt, code to the Moving Worlds spec.)

Basically, I cannot make this spec official; only the Moving Worlds folks have the power to write the official spec.

The Extrusion Node

The Extrusion node defines the basic extrusion. The other nodes defined below are either special cases of the extrusion node, or generalizations.
PROTO Extrusion [             # indicates that this is an extrusion node
   field MFVec2f crssSection  # polyline cross-section to be extruded
   field MFVec2f normals      # normals to the contour
   field MFVec3f spine        # 3D polyline extrusion path / spine
   field MFVec3f pathColors   # colors to be applied along the path.
   field MFVec3f pathXforms   # list of 2 by 3 affine matrices
   field SFVec3f up [0 1 0]   # y-axis of contour in 3-space
   field SFVec3f frontCap     # perpendicular to the front cap.
   field SFVec3f backCap      # perpendicular to the back cap.
   field SFEnum joinstyle  [ANGLE]  # the join style
   field SFBool drawCap    [TRUE]   # if true, draw the end caps
   field SFEnum normStyle  [PATH_EDGE] # how normals are used.
   field SFEnum texGen     [OFF]    # texture coordinate generation style
}
The contour field defines a 2D polyline that represents the cross-section of the extrusion. The contour will be swept along the 3D polyline path (spine) to define the surface. The contour field must be present, otherwise, an extrusion cannot be drawn.

The contourNormals field defines an array of 2D normals to the contour. The 2D normals will be extruded along the polyline path to generate the 3D normals needed for lighting. If the contourNormals field is not present, then facet normals will be computed and used.

The path defines the 3D polyline path (spine) along which the polyline is extruded. The path field MUST be present, otherwise, an extrusion cannot be drawn.

The pathColors field defines colors which will be used to color the vertices along the path. The colors will be used as the diffuse component of the material. If this field is missing, the current material will be used.

The pathXforms field defines a series of 2 by 3 affine matrices that are to be applied to the contour at each path vertex. If this field is missing, then unit matrices are assumed.

The up field defines the orientation of the contour's y-axis in 3D space. That is, the contour is interpreted in a 2D coordinate system whose y-axis is "up", and whose x-axis is defined as the cross product of up and the first segment of path. If this field is missing, the value is taken to be [0 1 0].

The frontCap field defines the orientation of the front end-cap of the extrusion. It is used, in conjunction with the join style, to define how the end of the extrusion should be trimmed. If this field is missing, then the frontCap vector is taken to be parallel to the first segment of the path. That is, the front cap is drawn perpendicular to the first segment of the "path".

The backCap field defines the orientation of the back end-cap of the extrusion. It is used, in conjunction with the join style, to define how the end of the extrusion should be trimmed. If this field is missing, then the backCap vector is taken to be parallel to the last segment of the path. That is, the back cap is drawn perpendicular to the last segment of the "path".

The joinstyle node defines how segments are to be joined. There are four possible values:

RAW       # ends are perpendicular to segments
ANGLE     # segments join together.
CUT       # joins are trimmed.
ROUND     # joins are rounded.

The drawCap field indicates whether the end caps should be drawn.

The normStyle field indicates how normals should be handled. It can take on one of four values:

FACET          # one normal per facet
CONTOUR_FACET  # normals along the edge of the path.
PATH_FACET     # normals along the edge of the contour
EDGE           # normals along the edge of both contour and path.

The texGen field indicates whether and how texture coordinates are generated for the extrusion It can take on one of 13 values:

OFF                 # texture generation disabled.
VERTEX_FLAT         # See API documentation
NORMAL_FLAT
VERTEX_CYL
NORMAL_CYL
VERTEX_SPH
NORMAL_SPH
MODEL_VERTEX_FLAT
MODEL_NORMAL_FLAT
MODEL_VERTEX_CYL
MODEL_NORMAL_CYL
MODEL_VERTEX_SPH
MODEL_NORMAL_SPH


PolyCylinder

The PolyCylinder is a special case of the extrusion, where the extruded contour is a circle.
PROTO PolyCylinder {                # indicates that this is a polycylinder
   field MFVec3f path               # 3D polyline extrusion path
   field MFVec3f pathColors         # colors to be applied along the path.
   field MFVec3f pathXforms         # list of 2 by 3 affine matrices
   field SFVec3f frontCap           # orientation of the front cap.
   field SFVec3f backCap            # orientation of the back cap.
   field SFEnum joinstyle ANGLE     # the join style
   field SFBool drawCap   TRUE      # if true, draw the end cap
   field SFEnum normStyle PATH_EDGE # how normals are used.
   field SFEnum texGen    OFF       # texture coordinate generation
}

PolyCone

The PolyCone is a special case of the PolyCylinder, where all of the transforms specify a radius. That is, all of the affine transforms are of the form
r  0  0
0  r  0
That is, the contour is scaled uniformly by the radius at each vertex.
PROTO PolyCone {             # indicates that this is an extrusion node
   field MFVec3f path               # 3D polyline extrusion path
   field MFVec3f pathColors         # colors to be applied along the path.
   field MFFloat radii              # radius at each vertex
   field SFVec3f frontCap           # orientation of the front cap.
   field SFVec3f backCap            # orientation of the back cap.
   field SFEnum joinstyle ANGLE     # the join style
   field SFBool drawCap   TRUE      # if true, draw the end cap
   field SFEnum normStyle PATH_EDGE # how normals are used.
   field SFEnum texGen    OFF       # texture coordinate generation
}

That's all for now, although clearly some of the other API routines might be interesting ...

Competing Proposals

The current Moving Worlds Specification proposal for VRML 2.0 contains a similar node, called the GeneralCylinder. Below, we provide a brief glossary relating that proposal to this.
spine
We call this the path. We do not define a default, although if we had, it would follow the GL conventions: [0 0 0 0 0 -1], that is, the cross section x and y are screen-aligned, and the extrusion path lies along the negative z-axis, pointing into the screen. This is the canonic system used in the implementation.

crossSection
We call this the contour. Same concept, fewer letters. Our 2D contours live in a 2D x-y space, which, by default, is parallel to the 3D x-y plane. For the GeneralCylinder proposal, the 2D x-y plane is parallel to the 3D X-Z plane.

sides
In our proposal, the sides are always drawn.

beginCap, endCap
In our proposal, these two have been merged into one flag -- either both caps are drawn, or both are not. Our proposal could be generalized in this way ... not a problem, if this is perceived as important.

ccw, solid, convex
The Moving Worlds proposal lacks detail in this area.

creaseAngle
Our proposal does not contain this, primarily because the sample implementation does not support this. Adding this could add some complexity to the implementation. Furthermore, there are really two crease angles: that in the contour (cross-section), and that in the path (spine). These two should be logically kept separates becomes clear if one thinks of how surfaces of revolution are generated.

The effect of crease angles can be emulated by drawing the extrusion in parts, with different normal-generation styles for each part.

width, twist
This is a slightly less general version of our pathXforms field. If I have read the specification correctly, then our 2D affine xform equals
         |   width*cos(twist)     -width*sin(twist)     0   |
         |   width*sin(twist)      width*cos(twist)     0   |
We have found the full form useful when defining screw-shapes, that is, surfaces of revolution that are offset as they are swept. The third fields (0 in the above), are critical for achieving the shearing motion when sweeping the curve.

The affine-matrix form is admittedly confusing to the general public. Therefore, it might make sense to define a node of the form

PROTO GeneralCylinder {             # indicates that this is an extrusion node
   field MFVec3f path               # 3D polyline extrusion path
   field MFVec3f pathColors         # colors to be applied along the path.
   field MFFloat width              # scale cross section
   field MFFloat twist              # rotate cross section
   field MFFloat tx              # translate cross section in x direction
   field MFFloat ty              # translate cross section in y direction
   field SFVec3f frontCap           # orientation of the front cap.
   field SFVec3f backCap            # orientation of the back cap.
   field SFEnum joinstyle ANGLE     # the join style
   field SFBool drawCap   TRUE      # if true, draw the end cap
   field SFEnum normStyle PATH_EDGE # how normals are used.
   field SFEnum texGen    OFF       # texture coordinate generation
}
where the affine is given by
         |   width*cos(twist)     -width*sin(twist)     tx   |
         |   width*sin(twist)      width*cos(twist)     ty   |
It is not clear that this less-general form easier or better than the fully general form.

First Draft, Linas Vepstas February 1996