5. Creating complex geometry

Sometimes you would like to create more complex shapes than primitives to create more sophisticated worlds. (You can easily imagine objects which would be very hard to create using primitives.) In this chapter you will see how to create complex geometry

5.1 Building Shapes out of Points, Lines, and Faces

Instead of building complex objects from a lot of tiny primitives, you can create objects using points, lines, and faces; it seems difficult for the first glance, but you will feel the flexibility this approach can give you: a more flexible way to describe shapes...

To build objects using lines, points and faces you will have to describe geometry in two steps:

You can define the location of dots (points) using Coordinate node (as you see each point is described by 3 coordinates):
Coordinate {
         point [
             2.0 1.0 3.0,
             4.0 2.5 5.3,
             . . .
         ]
     }
Second you connect the locations described by the immaterial/invisible dots by using one of the 3 nodes that have a coord field which accepts a Coordinate node(used to create geometry by connecting the dots):

5.1.1 The PointSet node

The PointSet node specifies a set of 3D points in the local coordinate system, with associated colours at each point(but with no control over the sizes of the dots). The PointSet node and the default values are:

PointSet { 
	color      NULL
	coord      NULL
}

The coord field specifies a Coordinate node (or instance of a Coordinate node): the specified coordinates are used in order by the PointSet node. If the coord field is NULL(as it is default), the point set is considered empty.
Since the size of the points are implementation-dependent, the only thing what you can specify is the color of each point in order(you should specify the same number of colors than the number of values in the Coordinate node). If the color field is NULL and there is a Material node defined for the Appearance node affecting this PointSet node, the emissiveColor of the Material node shall be used to draw the points.
In the following exampe there are 3 points(red, green and blue):

Show the PointSet example (The size of the dots are implementation-dependent: it can happen that you don't see too much in the world: although the points are there, it's difficult to notice them)
#VRML V2.0 utf8
#PointSet example

Shape {
	geometry PointSet {
		coord Coordinate {
                    point [
				-1.0 -1.0 0.0,
				1.0 1.0 0.0,
				0.0 0.0 0.0,
                    ]
                }
                color Color {
                    color [
                        1.0 0.0 0.0,
				0.0 1.0 0.0,
                        0.0 0.0 1.0,
                    ]
                }
            }
        }

5.1.2 The IndexedLineSet node

With IndexedLineSet you can "draw" straight lines in the 3D space between the vertices specified in the coord field. The node and the default values for the fields are:

IndexedLineSet { 
	color             NULL
	coord             NULL
	colorIndex        []
	coordIndex        []
}
You have to set up the vertices to be connected the same way like in the PointSet node. To specify the polyline, you have to specify the order of connecting the vertices in the coordIndex field: a value of -1 indicates the polyline's and, after -1 you can start with a new one.
IndexedLineSet {
         coord Coordinate {
             point [  . . .  ]
         }
         coordIndex [
             1, 0, 3, -1, . . .
         ]
     }

The width of lines is implementation dependent, therefore you can only specify the color of the line segments. In the following example 3 points are connected with 3 different color lines:

Show the IndexedLineSet example
#VRML V2.0 utf8
#IndexedLineSet example
Shape {
	geometry IndexedLineSet {
		coord Coordinate {
                    point [
				-1.0 -1.0 0.0,	#vertex 0
				1.0 1.0 0.0,	#vertex 1
				1.0 -1.0 0.0,	#vertex 2
                    ]
                }
		color Color {
                    color [
                        1.0 0.0 0.0,	#red
				0.0 1.0 0.0,	#green
                        0.0 0.0 1.0,	#blue
                    ]
            }
		coordIndex [
			#red line
			 0, 1, -1,
			#green line
			 1, 2, -1,
			#blue line
			 2, 0, -1
			]
		colorIndex [
			0, 1, 2
			]
			
	}
}

5.3 The IndexedFaceSet node

With this node you can create surfaces by "drawing" faces within the perimeter of points. The IndexedFaceSet node represents a 3D shape formed by constructing faces (polygons) from vertices listed in the coord field. The node and the default values for the fields are:

IndexedFaceSet {
         coord Coordinate {
             point [  . . .  ]
         }
         coordIndex [
             1, 0, 3, -1, . . .
         ]
     }

The coord field contains a Coordinate node that defines the 3D vertices referenced by the coordIndex field (like the Pointset and IndexedLineSet node's coordIndex field). IndexedFaceSet uses the indices in its coordIndex field to specify the polygonal faces by indexing into the coordinates in the Coordinate node. An index of "-1" indicates that the current face has ended and the next one begins(just like the IndexedLineSet node...).
In the following example you can examine a simple red pyramid created using IndexedFaceSet:

Show the IndexedFaceSet example
#VRML V2.0 utf8
#IndexedFaceSet example: a pyramid
Shape {
	appearance Appearance{
		material Material { 
			diffuseColor     1 0 0 #simple red
			}
		}
	geometry IndexedFaceSet {
		coord Coordinate {
                    point [
				# bottom 
				-1.0 -1.0 1.0,	#vertex 0
				1.0 -1.0 1.0,	#vertex 1
				1.0 -1.0 -1.0,	#vertex 2
				-1.0 -1.0 -1.0,	#vertex 3
				# top
				0.0 1.0 0.0		#vertex 4
                    ]
                }
		coordIndex [
			#bottom square
			 0, 3, 2, 1, 0, -1,
			#side1
			 0, 1, 4, -1,
			#side2
			 1, 2, 4, -1,
			#side3
			 2, 3, 4, -1,
			#side4
			 3, 0, 4, -1,
			]
			
	}
}

Some nodes of IndexedFaceSet - related to textures and normals - are discussed later.

5.2 Building Elevation Grids

Using elevation grids you can define a shape by a grid of heights: for example it provides a compact way to represent ground that varies in height over an area. The node specifies a rectangular grid and the height of the ground at each intersection in that grid. The node and the default values for the fields are:

ElevationGrid { 
	color             NULL
	normal            NULL
	texCoord          NULL
	height            []      # (-,)
	ccw               TRUE
	colorPerVertex    TRUE
	creaseAngle       0       # [0,]
	normalPerVertex   TRUE
	solid             TRUE
	xDimension        0       # [0,)
	xSpacing          1.0     # (0,)
	zDimension        0       # [0,)
	zSpacing          1.0     # (0,)
}

The xDimension and zDimension fields specify the number of grid points in the x and z directions, respectively, defining a grid of zDimension by xDimension lines in the xz plane. The xSpacing and zSpacing fields indicates the distance between vertices in the X and Z directions. The height field is an xDimension by zDimension array of scalar values representing the height above the grid for each vertex.

ElevationGrid {
    xDimension 3
    xSpacing 1.0
    zDimension 2
    zSpacing 1.0
    height [
        0.0, -0.5, 0.0,
        0.2,  4.0, 0.0
    ]
}

In the following example you can examine a (red) 9x6 dimension elevationgrid with 2.1 xspacing and 2 z spacing resulting a 18.9x12 object. The object is translated to the center of your initial view(about).

Show the ElevationGrid example
#VRML V2.0 utf8
#ElevationGrid example:
Transform {
translation -9 -2.0 -10.0
children [
	Shape {
		appearance Appearance{
			material Material { 
				diffuseColor     1 0 0 #simple red
				}
			}
		geometry ElevationGrid {
		xDimension  9
		zDimension  6
		xSpacing    2.1
		zSpacing    2
		height [
			0, 0,    0.2,  0,    0,   0,    0,    0,   0, # row 0
			0, 0.8,  0.4,  0.2, -0.2, 0.2,  0.4,  0.2, 0, # row 1
			0, 1,    0.6,  0.4,  0.2, 0.4,  0.2, -0.2, 0, # row 2
			0, 0.8,  0,    0.4, -0.2, 0.2, -0.4,  0.1, 0, # row 3
			0, 0.2, -0.4, -0.2,  0,   0.4,  0.2,  0.4, 0, # row 4
			0, 0,    0,    0,    0,   0,    0,    0,   0  # row 5
			]
		}
	}
  ]
}

Some nodes of ElevationGrid - related to textures and normals - are discussed later.

5.3 Extrusions

Extrusion Node has the capability of creating geometry by defining a 2D Cross-section and a 3D spine and sweeping the cross-section along the spine resulting an object as a "trace of the extrusion". The cross-section can be scaled and rotated at each spine point to produce a wide variety of shapes.
The crossSection and spine paths are both piecewise linear; that is, they're composed of straight line segments. You specify each of them as a series of vertices to be connected in order. To produce a cylinder or other shape with a curved cross-section using an Extrusion node, you have to specify many points spaced close together to approximate a curve. The node and the default values for the fields are:

Extrusion { 
	beginCap         TRUE
	ccw              TRUE
	convex           TRUE
	creaseAngle      0                # [0,)
	crossSection     [ 1 1, 1 -1, -1 -1,
				-1 1, 1  1 ]    # (-,)
	endCap           TRUE
	orientation      0 0 1 0          # [-1,1],(-,)
	scale            1 1              # (0,)
	solid            TRUE
	spine            [ 0 0 0, 0 1 0 ] # (-,)
}

The basic Extrusion Node syntax is:

Extrusion {
    crossSection [
        1.0 0.0, . . .
    ]
    spine [
        10.0 0.0 0.0, . . .
    ]
}

An Extrusion node is defined by:

In the following example you can study a basic extrusion with 4 scaled cross-sections:

Show the Extrusion example(not for its beauty)
#VRML V2.0 utf8
#extrusion example
Shape {
  appearance  Appearance { material  Material { } }
  geometry  Extrusion {
    crossSection [	
      1  0,  .71 -.71,
      0 -1,  -.71 -.71,
     -1  0,  -.71  .71,
      0  1,   .71  .71,   1 0
    ]
    spine	[ -2 0 0, -2 0 -4, 2 0 -4, 2 0 0]
    scale	[ 1 1 , 0.5 0.5 , 0.5 0.5 , 1 1 ]
    beginCap  FALSE
    endCap    FALSE
    solid     FALSE
  }
}

Some nodes - related to textures and normals - are discussed later.

5.4 Binding Colors to Coordinate-based Geometry

You can have better color control for IndexedFaceSet, IndexedLineSet, PointSet, and ElevationGrid nodes for example you can specify colors per-face or per-vertex.
Let's recall that the Color node is used as the color field value of IndexedFaceSet, IndexedLineSet, PointSet and ElevationGrid nodes. The Color node contains a list of RGB values:

IndexedFaceSet {
    coord Coordinate { . . . }
    coordIndex [ . . . ]
    color Color {
        color [ 1.0 0.0 0.0, . . . ]
    }
    colorIndex [ 3, 0, 1, . . . ]
    colorPerVertex TRUE
}

If the color field is not NULL, it must contain a Color node whose colours are applied to the vertices or faces of the IndexedFaceSet depending on the colorPerVertex and colorIndex fields:

If colorPerVertex is FALSE, colours are applied to each face, depending on colorIndex. If the colorIndex field is empty, then the colours of the Color node are applied to each face of the IndexedFaceSet in order. (There must be at least as many colours in the Color node as there are faces.) In the colorIndex field you can specify the order of colors instead of the default order: this can be very useful if you define a color-set (for example with the DEF keyword) and use the same colors on different objects.

Show the example
#VRML V2.0 utf8
#Color example: a pyramid
Shape {
	appearance Appearance{
		material Material { }
		}
	geometry IndexedFaceSet {
		coord Coordinate {
                    point [
				# bottom 
				-1.0 -1.0 1.0,	#vertex 0
				1.0 -1.0 1.0,	#vertex 1
				1.0 -1.0 -1.0,	#vertex 2
				-1.0 -1.0 -1.0,	#vertex 3
				# top
				0.0 1.0 0.0		#vertex 4
                    ]
                }
	colorPerVertex FALSE #so each face will have one of the colors
	color Color {
                    color [
                        1.0 0.0 0.0,#color 0
                        0.0 1.0 0.0,#color 1
                        0.0 0.0 1.0,#color 2
                        1.0 1.0 0.0,#color 3
                        0.0 1.0 1.0,#color 4
                    ]
                }
	colorIndex [ 2 3 4 0 0 ] #the first face will have color 2, the 2nd color3...
		coordIndex [
			#bottom square
			 0, 3, 2, 1, 0, -1,
			#side1
			 0, 1, 4, -1,
			#side2
			 1, 2, 4, -1,
			#side3
			 2, 3, 4, -1,
			#side1
			 3, 0, 4, -1,
			]
			
	}
}

There is not too much difference between IndexedFaceSet and IndexedLineSet nodes in context of using colors. When colorPerVertex is TRUE, specify one color index per coordinate index, if it is false, specify one color index per face or line.
The ElevationGrid node has no coordinate indexes or color indexes, so when colorPerVertex is TRUE, specify at least (xDimension*zDimension) colors, when it's FALSE, specify at least (xDimension-1)*(zDimension-1) colors