| 6491 and 7491 PROJECTS Alexander Powell |
|
Surface FairingCS6491: Computer GraphicsAlexander Powell - [ alex at powelltown dot com ] September 25, 2003 This project is an implementation of Taubin's surface fairing algorithm. I implemented the project on top of the TMesh class in my group's Project 1 source. The particular method which performs the surface fairing is as follows:
void TMesh::fairSurface(GLfloat lm, WeightType wt)
{
int ii;
deque<Vector> newVertices(numVertices);
deque<bool> tagged(numVertices);
for (ii = 0; ii < numVertices; ii++)
tagged[ii] = false;
// We loop through each corner
for(unsigned int a = 0; a < numTriangles * 3; a++)
{
if(!tagged[cornerTable[a]])
{
// Create lists to keep track of our neighbors and their weights
deque<Vector> neighborhood;
deque<GLfloat> weights;
// Visit the neighbors to calculate their weights
int start = n(a);
int current = start;
do {
// Add this vertex to our neighborhood list
neighborhood.push_back(vt[cornerTable[current]]);
// Calculate the weight for this edge
GLfloat curWeight;
if (wt == DISTANCE)
curWeight = ((vt[cornerTable[a]] - vt[cornerTable[current]]).length());
else
{
Vector v1 = vt[cornerTable[a]] - vt[cornerTable[n(a)]];
Vector v2 = vt[cornerTable[a]] - vt[cornerTable[p(a)]];
Vector v3 = vt[cornerTable[o(n(current))]] - vt[cornerTable[n(o(n(current)))]];
Vector v4 = vt[cornerTable[o(n(current))]] - vt[cornerTable[p(o(n(current)))]];
curWeight = (v1.cross(v2).length() + v3.cross(v4).length());
}
weights.push_back(curWeight);
current = o(n(current));
} while (current != start);
// Normalize weights
GLfloat totalWeight = 0.0;
for (ii = 0; ii < weights.size(); ii++)
totalWeight += weights[ii];
for (ii = 0; ii < weights.size(); ii++)
weights[ii] = weights[ii] / totalWeight;
// Compute new vertex position based on the Gaussian smoothing step in Eq. 4
Vector dx;
for (ii = 0; ii < neighborhood.size(); ii++)
dx += weights[ii] * (neighborhood[ii] - vt[cornerTable[a]]);
newVertices[cornerTable[a]] = vt[cornerTable[a]] + dx * lm;
// Tag this vertex so we don't recompute its location
tagged[cornerTable[a]] = true;
}
}
//replace old vertices
for(unsigned int a = 0; a < newVertices.size(); a++)
vt[a] = newVertices[a];
}
}
This method performs a gaussian smoothing, and therefore must be called once with a positive "lambda" value, and a second time with the negative "mu" value in order to preserve the size of the meshes. A typical method call would be like so:
GLfloat lambda = 0.4;
GLfloat Kpb = 0.01;
GLfloat mu = 1.0 / (Kpb - (1.0 / lambda));
for (int ii = 0; ii < 100; ii++)
{
tmesh->fairSurface(lambda, AREA);
tmesh->fairSurface(mu, AREA);
}
tmesh->calculateNormals();
The full source can be retrieved here: P2.tar.gz PicturesClick on a picture for a bigger (but likely of worse quality) version.
dresser.csg - From left to right: Original isosurface :: 20 iterations (mu=0.2, Kpa=0.1) :: 50 iterations :: 50 iterations with wireframe.
box.csg - From left to right: Original isosurface :: isosurface with wireframe :: 20 iterations (mu=0.6307, Kpa=0.1) :: 20 iterations with wireframe :: 50 iterations :: 50 iterations with wireframe :: 200 iterations :: 200 iterations with wireframe.
spheres.csg - From left to right: Original isosurface :: 10 iterations (mu=0.6307, Kpa=0.1) :: 50 iterations :: 50 iterations smooth shaded.
twospheres.csg - From left to right: Voxel grid :: isosurface :: 200 iterations (mu=0.6307, Kpa=0.01) :: comparison between voxel grid and smoothed surface.
random.csg - From left to right: Voxel grid :: isosurface :: 200 iterations (mu=0.6307, Kpa=0.001) :: some ridiculous amount of iterations.
chair.csg - From left to right: Original isosurface :: 100 iterations (mu=0.6307, Kpa=0.001) :: 200 iterations :: 400 iterations :: a fatter chair, lots of iterations. Note: The asymmetry is the result of the particular triangulation of the isosurface.
squares.csg - From left to right: Voxel grid :: isosurface :: isosurface smooth shaded :: 200 iterations (mu=0.4, Kpa=0.01) :: 500 iterations :: different view, to demonstrate slight asymmetry.
twospheres.csg - From left to right: Smoothed mesh, 2000 iterations :: same, but with wireframe :: surface smoothed with "distance" weighting, not "area" weighting :: distance weighting example, without wireframe. Note: There is very little difference between the "distance" and "area" methods for calculating weights in our isosurface meshes, because they contain fairly consistently sized triangles. I usually prefer area calculations over edge sizes because the surface is much better represented by solid triangles than simple edges. Also, the size difference in the images is not intentional-- the second image is not supposed to be bigger than the third. |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||