                                                                                                   
                                                                                                   
THE EDGEMESH MACRO (v. 0.1): HOW-TO

//author : Thibaut Jonckheere
//date : May 2006
//coypright : you can use and modify this file for any use 
//            as long as credit to the original work is given
//
// For questions, remarks, suggestions, etc. you can contact me at
// tuabihtucl -at- yahoo.fr
-------------------------------------------------------------------
-------------------------------------------------------------------
            

SUMMARY  
   1) Introduction - General remarks 
   2) The principle of the macro
   3) Using the edgemesh.inc macro
   4) Getting the edge-structure file  

------------------------------------------------------------------- 

1) Introduction - General remarks
+++++++++++++++++++++++++++++++++

This small how-to explains how to use my edgemesh macro, which allows to compute the edges of 
a given mesh object. Those edges are usefull to get a cartoon/cel-shaded look for your images
with povray (but other uses are possible). Note that it works only with mesh object (declared
with the mesh2 syntax in povray), and not with primitives, csg, isosurfaces, height-fields, etc.

Note that this macro will certainly evolve (if time permits), as its use is a bit cumbersome in the
current version.  The main weakness at the moment is due to my poor skills at programming efficient parsing
of files. So the use of the macro implies some copy-pasting from the original mesh file to get files
that my pov code or my perl script can read, and this could be avoided with a better coding of the macro
 and of the perl script. 
 
A final remark: don't be impressed by the length of this file, it is long because it is detailled ! Once the 
steps needed to have the macro work are understood, it is quite easy to use.

------------------------------------------------------------------- 

2) The principle of the macro
+++++++++++++++++++++++++++++

The idea behind the macro is quite common, and can be found on the internet. Two different
kinds of edges are computed. The first type is the "silhouette edge", which gives the outline of the
object. This edge is precisely the frontier between the part of the object
that is visible and the part that is hidden. So, if we have a mesh object (an ensemble of
vertices, joined by edges, forming triangualr faces), it is easy to see if a given edge joining
two vertices belongs to the silhouette contour or not: just look at the two faces sharing this edge,
and if one is visible while the other is hidden, then this edge belongs to the silhouette contour.
The visibility of a given face can be checked easily by looking at its normal vector (it is visible
if the normal vector is pointing towards the camera). The silhouette depends of course on the relative
position of the camera and the mesh object.

The second kind of edges are "crease edges", which show the abrupt changes of orientation of faces.
To see if a given edge, joining two vertices, is a "crease edge" , just compare
the orientation of the normals of the two faces sharing this edge, and if the difference
of orientations is larger than a given threshold, then the edge is a "creased  edge"

Note that, in order to test whether a given edge belongs to the silhouette, or is a crease edge,
one need to know the "edge structure" of the mesh, which tells for example that edge number x1,
joining vertices x2 and x3, is shared by faces y1 and y2 (x1,x2,x3,y1,y2 are arbitrary numbers).
This information is not included in the mesh description that povray uses, and has thus to be 
computed first. As the processing of this "edge structure" takes too much time when done with
pov SDL, I have written a small perl script that does the trick, and output the result to a file.
In order to draw the edges of a given mesh object in a scene, one needs first to compute the
"edge structure", and then use the macro which uses the infos of this file. The details are
explained in the next sections.
 

                             
   
------------------------------------------------------------------- 
            
3) Using the edgemesh.inc macro
+++++++++++++++++++++++++++++++

Using the macro is relatively straitghforward. An example of the syntax (here for the Arch of the logo in the demo scene) 
is the following:
EdgeMesh01(MeshFile,EdgeFile,LogoArchEdge,LogoArchNormEdge,Normthresh,Cylrad,Cylrad2,Cyltex,PdV1)
with the paramaters:
  
   - Meshfile : the ascii file containing the mesh description of the object (in this case,
     it is logo2_arch_mesh.inc, look at this file for an example). To get this file, from the mesh2 file that
     defines the object (e.g. logo2.inc), keep only the 4 very long lines (or group of lines): vertex_vectors,
     normal_vectors, face_indices and normal_indices, and remove for each of this line the label (e.g. "vertex_vectors")
     and the opening curly bracket. (Compare the example files logo2.inc (for the arch object) and logo2_arch_mesh.inc
     if this is not clear)
     
   - Edgefile : the ascii file containing the edge struscture of the mesh (in this case, it is logo2_arch_edge_perl.inc). 
     This file has to be computed first before using the macro, and the method is explained in the next section.
     
   - LocoArchEdge : this gives, on output, the object containing the silhouette edge (it is an union of cylinders, one 
     for each edge of the mesh forming the silhouette). On input, it is declared as a basic object (e.g. sphere{0,1}).
     
   - LocoArchNormEdge : this gives, on output, the object containing the crease edges (it is an union of cylinders, one 
     for each edge of the mesh forming crease edges).  On input, it is declared as a basic object (e.g. sphere{0,1}).
     
   - Normthresh : this is the threshold for the scalar product of the normals of adjacent faces: when the scalar
     product of the normals of two adjacent faces is below this threshold, the edge shared by the two faces is a crease edge.
     Values in the range 0.5-0.8 usually give correct result. Using 0 (or lower) results in no crease edge, and 
     using 1 (or higher) means all edges are crease edges, and this gives a wirefame of the mesh object. 
     
   - Cylrad : the radius of the cylinder used for the silhouette edge (correct value depends on the scale of the scene, and on 
     the desired width of the contour of course).
   
   - Cylrad2 : the radius of the cylinder used for the creased edge.
   
   - Cyltex : the texture used for both kind of cylinders. It is usually a good idea to have "no_shadow" in the texture
     to avoid unwanted shadows being casted by the edge objects. (Note that the macro could easily be adapted to have
     different textures for silhouette edges and crease edges, but I have not seen the utility of this so far).
     
   - PdV1 : the point of vue used to compute the silhouette edge. When the mesh object is not translated-scaled-rotated,
     this is simply the position of the camera (called PdV in the example scene). However, when transformations are
     applied to the mesh object, PdV1 has to be  the vector obtained by appying the *inverse* transformation to the camera location
     (this avoids to perform the transformation on all the vertices/normals of the mesh: just do the inverse transform on the
     point of vue, and you get the correct silhouette). One point to be careful with : when several transformations are 
     applied to the mesh object (e.g. a rotation then a translation), the inverse transformation is obtained by 
     applying *in reverse order* each inverse transformation (e.g. here the inverse translation then the inverse rotation). 
     See the example scene for some transformations applied to get PdV1.    
     
     
-------------------------------------------------------------------      
     
4) Getting the edge-structure file
++++++++++++++++++++++++++++++++++

In order to use the Edgemesh macro for a given mesh object, we need first to compute the "edge-structure" of this
mesh. This process is the most "annoying" part of the macro, and is certainly the one that would benefit the most
of improvement of the coding. There is however a good news: the process has to be done only *once* for a given
mesh object. Once you have the file describing the edge-structure, you can try different width, textures, threshold,
etc. for your contour, place several copies of your mesh object in the scene, etc. simply using the Edgemesh macro
described above. It is only if you change your mesh object that you need to recalculate the edge-structure file.

The perl script that computes the edge-structure is called Edgemeshscript01.pl . As input, it uses the face info
of the mesh object (in a "extra-simple-to-parse" form), computed by the pov code "outface.pov", which uses as
input the Meshfile of the object (the same one as in the Edgemesh macro). This edge-structure file is in fact a list
of the edges of the mesh, giving for each edge: the two vertices which are joined by this edge, and the two faces
which share this edge.  

I guess a practical example is simpler to understand, so here are the steps needed to get this file - 
I have used as an example the arched part of the logo (the filenames I use are of course a matter of choice):
        - Get the meshfile of your mesh object. As explained above, this means keeping only the vertex_vectors, normal_vectors,
         face_indices and normal_indices info, and removing the labels (like "face_indice") and the opening curly brakcet. In
         our example, this file is called logo2_arch_mesh.inc
        - In the pov-file "outface.pov", replace the mesh data filename by logo2_arch_mesh.inc, and replace 
         the output filename by the same name with "_mesh" replaced by "_face" (so, in our example, logo2_arch_face.inc),
         and then run outface.pov.
        - In the perl script "Edgemeshscript01.pl", use for the input filename the name of the file you have just created
          (logo2_arch_face.inc in our example), and run the perl script. The output file you get is the edge-structure file
          (in the example, I have called it logo2_arch_perl_edge.inc)
        - That's it. The file you have obtained is the one needed by the Edgemesh macro. The output file of outface.pov
          is just an intermediate file, it can now be deleted.    
                 
Note that it is possible to use the pov SDL to perform what the perl script does, but it is then way too slow !
With the perl script, I have reasonnable time (a few minutes, up to 10 maybe) for a mesh file up to ~25.000 edges.                         