The New and Improved Surface Subdivision Suite

    Many moons ago, a computer graphics specialist by the name of Charles Loop devised the Loop scheme for subdivision surfaces; if I recall correctly, it was the basis for his masters thesis. Seeing the potential for use with the Persistence of Vision Ray Tracer, I developed a set of macros to implement Loop subdivision surfaces within POV-Ray, and released the macros under the title of the Surface Subdivision Suite (SSS).
    After trying to use the SSS once for an IRTC entry, and not getting the results I wanted, I decided to improve it by adding the following features:

  • Proper border support: The old SSS didn't calculate border points correctly, causing the subdivided meshes to shrink from their edges. I modified the subdivision code to handle the borders properly.
  • Crease support: The old SSS only supported smooth edges. Sharp edges (called creases) are now supported. This makes it easier to make things like swords, for instance.
  • Individual texturing of faces: The old SSS didn't support this. The new one does.
  • UV-mapping: Now that POV-Ray provides support for uv-mapping in meshes, so does the SSS.
  • Quadrilateral faces: Faces can be four-sided, which reduces the user-level data requirements and solves some texturing problems.

    The Files

    Download this zip file and unzip it into your POV-Ray include directory. To use the macros, put this line of code somewhere in your scene code:

       #include "nsss.inc"
    
    The macro files are named differently so that scripts which use the old version of the SSS will still work.

    The Data

    The SSS makes use of several variables, all of which begin with sss. They are all built and accessed through the macros (which are described farther down).

  • ssscV holds the number of vertices defined for the current mesh.
  • ssscE holds the number of edges defined for the current mesh.
  • ssscF holds the number of faces defined for the current mesh.
  • sssaV[ ] holds the vertex data.
  • sssaEF[ ][ ] holds the edge-face cross-reference data.
  • sssaEV[ ][ ] holds the edge-vertex cross-reference data.
  • sssaEV[ ][ ] holds the sharpness value of each edge.
  • sssaFE[ ][ ] holds the face-edge cross-reference data.
  • sssaFV[ ][ ] holds the face-vertex cross-reference data.
  • sssaFT[ ] holds the index of the textures assigned to each face (if you made any such assignments).
  • sssaFM[ ][ ] holds the uv-mapping for each face (if you've defined any).
  • sssfProgressReports allows you to turn off the progress reports that the SSS generates. Set it to false to turn the messages off.

    The Macros

    SSS_ImportBasicMesh(arrayV,arrayF)
    This is primary macro for getting your mesh into the SSS. This macro takes the two input arrays and builds the data structures required for the SSS to work. arrayV is a one-dimensional array of vectors which specify the vertices of the original polygon mesh. arrayF is a two-dimensional array of indexes to the vertex array. arrayF[n][0] contains the index to the first vertex of the face, arrayF[n][1] contains the index to the second vertex of the face, arrayF[n][2] contains the index to the third vertex of the face, and arrayF[n][3] contains the index to the fourth vertex of the face (or -1 if the face is triangular).

    After you have called the macro, the array you pass is no longer needed, and can be #undefed. Please note that this macro completely overwrites the internal SSS data structures.

    SSS_ImportSharpData(arrayS)
    This macro allows you to define sharp edges. arrayS is a two-dimensional array of the form array[n][3]. arrayS[n][0] is the vertex at the start of an edge to be sharpened, arrayS[n][1] is the vertex at the end of an edge to be sharpened, and arrayS[n][2] specifies the number of subdivision levels for which smoothing is not done. Specifying a sharpness of -1 causes smoothing to be skipped for all levels of subdivision. Border edges (that is, edges which have only one side bordering on them) are always sharpened, and any effort to smooth them will be ignored.

    SSS_AssignTextures(arrayT)
    This is the macro used for assigning textures to faces. arrayT is a one-dimensional array of indices. Each member is set to the index of the texture to be applied to the corresponding face; for instance, setting arrayT[3] equal to 7 will cause the fourth face (zero-based indexing) to receive the eighth texture. A value of -1 specifies no individual texturing for that face. If the number of members in arrayT is less than the number of defined faces, the first faces in line get the specified textures, and the remainder are tagged with -1.

    Please note that the SSS does not support texture interpolation.

    SSS_AddUVMapping(arrayM)
    This is the macro used for assinging uv-mapping to the mesh. arrayM is a two-dimensional array of the form array[n][3] or array[n][4], containing uv-vectors specifying the uv-mapping of each of the points of the mesh. If n is less than the number of faces passed to SSS_ImportBasicMesh( ), the first n faces will receive the specified uv-mapping, and the rest will receive the default texture mapping (<0,0>, <0,1>, and <1,0> for triangles, and <0,0>, <0,1>, <1,1>, and <1,0> for quadrilaterals).

    SSS_Subdivide( )
    This is the macro which takes the defined mesh and performs one level of subdivision. Each triangular face is divided into four smaller triangles, and each quadrilateral face is divided into four smaller quadrilaterals. Since each call increases the number of faces by a factor of four, don't go hog-wild.

    SSS_BuildFlatMesh( )
    This macro is useful if you actually want to build flat meshes; you may have an artistic reason for this. Note that the SSS implements quad faces by splitting them into a pair of triangles, and although the SSS tries to make them look like a single flat face, if the four vertices do not lie in a plane, an over-eager optimization in POV-Ray causes them to be rendered as ordinary flat triangles.

    SSS_BuildSmoothMesh( )
    This macro builds a mesh of smooth triangles, but applies no texturing.

    SSS_BuildTexturedSmoothMesh(arrayT)
    This macro builds a mesh of smooth triangles, and applies all of the texturing and uv-mapping (if any) that were specified with the model. arrayT should be an array of textures. If you make use of uv-mapping, the textures that need to be mapped should have the uv_mapping keyword in their definition.

    SSS_Roughen(Seed, Amount)
    This macro perturbs the surface of the mesh. Good for making rocks. Seed specifies the random-number seed to use, and Amount specifies the amount of roughening.

    The following macros are used internally by the SSS as needed, but do not need to be called by the user:

    SSS_DefaultSharpData( )
    This macro implements the default sharpening, in case the user doesn't supply any.

    SSS_BuildNormals( )
    This is the macro which calculates the normals for the mesh.

    SSS_OrientFaces( )
    This macro manipulates some of the internal data to ensure that normals are calculated correctly.

    SSS_EdgeDir( )
    This macro is used by the SSS_OrientFaces( ) macro.

    SSS_OtherSide( )
    This macro is also used by the SSS_OrientFaces( ) macro.

    Coming Attractions

  • Bug fixes: I don't think they're needed, yet, but...
  • File support: This was in the old SSS, so I'll be adding this sometime. I don't know when. I'll probably make a macro which generates complete .INC files (using mesh2 { } statements, and perhaps .OBJ files as well.
  • Quad support: If POV-Ray is modified to support quadrilateral faces in the mesh { }, I'll modify the SSS to take advantage of it.