Post

Controlling Shading on Coordinate-Based Geometry

Motivation

  • When shaded, the faces on a shape are obvious
  • To create a smooth shape you can use a large number of small faces
    • Requires lots of faces, disk space, memory, and drawing time
  • Instead, use smooth shading to create the illusion of a smooth shape, but with a small number of faces

Controlling shading using the crease angle

By default, faces are drawn with faceted shading.

You can enable smooth shading using the creaseAngle field for:

Selecting crease angles

A crease angle is a threshold angle between two faces:

  • If face angle >= crease angle, use facet shading
  • If face angle < crease angle, use smooth shading

Using normals

A normal vector indicates the direction a face is facing

  • If it faces a light, the face is shaded bright

By default, normals are automatically generated by the X3D browser:

  • You can specify your own normals with a Normal node
  • Usually automatically generated normals are good enough

Syntax: Normal

A Normal node contains a list of normal vectors that override use of a crease angle.

XML Encoding

1
2
<Normal
    vector='0.0 1.0 0.0, ...'/>

Classic Encoding

1
2
3
Normal {
  vector [ 0.0 1.0 0.0, ... ]
}

Normals can be given for IndexedFaceSet and ElevationGrid nodes.

Syntax: IndexedFaceSet

An IndexedFaceSet geometry node creates geometry out of faces:

  • normal - list of normals
  • normalIndex - selects normals from list
  • normalPerVertex - control normal binding

XML Encoding

1
2
3
4
5
6
7
8
9
10
<Shape>
  <Appearance><!-- ... --><Appearance>
  <IndexedFaceSet
      normalPerVertex='true'
      normalIndex='...'
      coordIndex='...'>
    <Normal ... />
    <Coordinate ... />
  </IndexedFaceSet>
</Shape>

Classic Encoding

1
2
3
4
5
6
7
8
9
10
Shape {
  appearance Appearance { ... }
  geometry IndexedFaceSet {
    normalPerVertex TRUE
    normalIndex [ ... ]
    coordIndex [ ... ]
    normal Normal { ... }
    coord Coordinate { ... }
  }
}

Controlling normal binding for face sets

The normalPerVertex field controls how normal indexes are used

  • FALSE: one normal index to each face (ending at -1 coordinate indexes)
  • TRUE: one normal index to each coordinate index of each face (including -1 coordinate indexes)

Syntax: ElevationGrid

An ElevationGrid geometry node creates terrains:

  • normal - list of normals
  • normalPerVertex - control normal binding
  • Always binds one normal to each grid point or square, in order

XML Encoding

1
2
3
4
5
6
7
8
<Shape>
  <Appearance><!-- ... --><Appearance>
  <ElevationGrid
      normalPerVertex='true'
      height='...'>
    <Normal ... />
  </ElevationGrid>
</Shape>

Classic Encoding

1
2
3
4
5
6
7
8
Shape {
  appearance Appearance { ... }
  geometry ElevationGrid {
    normalPerVertex TRUE
    normal Normal { ... }
    height [ ... ]
  }
}

Controlling normal binding for elevation grids

The normalPerVertex field controls how normal indexes are used (similar to face sets):

  • FALSE: one normal to each grid square
  • TRUE: one normal to each height for each grid square

Syntax: NormalInterpolator

A NormalInterpolator node describes a normal set:

  • keys - key fractions
  • keyValues - key normal lists (X,Y,Z lists)
  • Interpolates lists of normals, similar to the CoordinateInterpolator

XML Encoding

1
2
3
<NormalInterpolator
    key='0.0, ...'
    keyValue='0.0 1.0 1.0, ...'/>

Classic Encoding

1
2
3
4
NormalInterpolator {
  key [ 0.0, ... ]
  keyValue [ 0.0 1.0 1.0, ... ]
}

Typically route into a Normal node’s set_vector input.

Summary

  • The creaseAngle field controls faceted or smooth shading
  • The Normal node lists normal vectors to use for parts of a shape
    • Used as the value of the normal field
    • Normal indexes select normals to use
  • Normals override creaseAngle value
  • The normalPerVertex field selects normal per face/grid square or normal per coordinate
  • The NormalInterpolator node converts times to normals
This post is licensed under CC BY 4.0 by the author.