next up previous contents index
Next: Extensions Up: Advanced Topics Previous: Advanced Topics   Contents   Index

Hidden Object Removal

ePiX writes the output file in the same order that objects appear in the input. The order is significant because PostScript builds a figure in layers: Objects are drawn over objects that come earlier in the file. Shaded polygons can be used to obtain surprisingly effective hidden object removal in surface meshes. The techniques are still provisional, however; this section describes a method that works for the author, though is not sufficiently refined for inclusion in the source code.

The basic idea is to create a shaded quadrilateral class that knows its distance to the camera. To draw parametrized surfaces, quadrilaterals are written in any convenient order to a C++ vector, then sorted by distance to the camera and printed to the output file in decreasing order of distance. The gray density of a mesh element depends on the cosine of the angle between the normal vector and the vector from the camera to the element. The method works acceptably well in practice: Several surfaces can be drawn, and the effect is fairly realistic. If the surface meshes are fine enough, intersections are accurate and not jagged. However, the output file tends to be enormous, and is not effectively human-readable.

The quadrilateral class might look like this:

class mesh_quad
{
private:
  P pt1, pt2, pt3, pt4;
  double distance;

public:
  mesh_quad() 
  {
    pt1=pt2=pt3=pt4=P();
    distance=camera.get_range();
  }

  mesh_quad(P f(double u, double v), double u0, double v0)
  {
    pt1=f(u0+EPS,v0+EPS);       // EPS = "shrinkage"
    pt2=f(u0+du-EPS,v0+EPS);
    pt3=f(u0+du-EPS,v0+dv-EPS);
    pt4=f(u0+EPS,v0+dv-EPS);
    
    P center = 0.25*(pt1 + pt2 + pt3 + pt4);
    distance = norm(center-camera.get_viewpt());
  }

  double how_far() const { return distance; }

  void draw() 
  { 
    P normal = (pt2 - pt1)*(pt4 - pt1);
    normal *= 1/norm(normal);

    double dens  = 0.75*(1-pow(normal|LIGHT, 2)/(LIGHT|LIGHT));
    gray(dens); 
    quad(pt1, pt2, pt3, pt4); 
  }
};
To utilize C++'s sorting algorithm, a class is defined to measure the distance to a mesh element:
class by_distance {
public:
  bool operator() (const mesh_quad& arg1, const mesh_quad& arg2)
  { return arg1.how_far() > arg2.how_far(); }
};
Assuming f1 and f2 are parametric surface maps, the class above can be used as follows in the body of the figure:
  std::vector<mesh_quad> mesh(0); // list of mesh_quads

  for (int i=0; i<N1; ++i)
    for (int j=0; j<N2; ++j)
      {
        mesh.push_back(mesh_quad(f1, -1+du*i, -1+dv*j));
        mesh.push_back(mesh_quad(f2, -1+du*i, -1+dv*j));
      }

  sort(mesh.begin(), mesh.end(), by_distance());

  for (unsigned int i=0; i<mesh.size(); ++i)
    mesh.at(i).draw();
For a complete file, please see samples/extras/tori.xp.


next up previous contents index
Next: Extensions Up: Advanced Topics Previous: Advanced Topics   Contents   Index
Andrew D. Hwang 2004-09-04