Here is how to convert the raw triangles into welded vertices, face normals and vertex normals. It is a small code, and it works well:
void get_vertices_and_normals_from_triangles(vector<triangle> &t, vector<vertex_3> &fn, vector<vertex_3> &v, vector<vertex_3> &vn)
{
fn.clear();
v.clear();
vn.clear();
if(0 == t.size())
return;
cout << "Triangles: " << t.size() << endl;
cout << "Welding vertices" << endl;
// Insert unique vertices into set.
set<vertex_3> vertex_set;
for(vector<triangle>::const_iterator i = t.begin(); i != t.end(); i++)
{
vertex_set.insert(i->vertex[0]);
vertex_set.insert(i->vertex[1]);
vertex_set.insert(i->vertex[2]);
}
cout << "Vertices: " << vertex_set.size() << endl;
cout << "Generating vertex indices" << endl;
// Add indices to the vertices.
for(set<vertex_3>::const_iterator i = vertex_set.begin(); i != vertex_set.end(); i++)
{
size_t index = v.size();
v.push_back(*i);
v[index].index = index;
}
vertex_set.clear();
// Re-insert modifies vertices into set.
for(vector<vertex_3>::const_iterator i = v.begin(); i != v.end(); i++)
vertex_set.insert(*i);
cout << "Assigning vertex indices to triangles" << endl;
// Find the three vertices for each triangle, by index.
set<vertex_3>::iterator find_iter;
for(vector<triangle>::iterator i = t.begin(); i != t.end(); i++)
{
find_iter = vertex_set.find(i->vertex[0]);
i->vertex[0].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[1]);
i->vertex[1].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[2]);
i->vertex[2].index = find_iter->index;
}
vertex_set.clear();
cout << "Calculating normals" << endl;
fn.resize(t.size());
vn.resize(v.size());
for(size_t i = 0; i < t.size(); i++)
{
vertex_3 v0 = t[i].vertex[1] - t[i].vertex[0];
vertex_3 v1 = t[i].vertex[2] - t[i].vertex[0];
fn[i] = v0.cross(v1);
fn[i].normalize();
vn[t[i].vertex[0].index] = vn[t[i].vertex[0].index] + fn[i];
vn[t[i].vertex[1].index] = vn[t[i].vertex[1].index] + fn[i];
vn[t[i].vertex[2].index] = vn[t[i].vertex[2].index] + fn[i];
}
for(size_t i = 0; i < vn.size(); i++)
vn[i].normalize();
}
Where the less-than operator is implemented as:
inline bool operator<(const vertex_3 &right) const
{
if(right.x > x)
return true;
else if(right.x < x)
return false;
if(right.y > y)
return true;
else if(right.y < y)
return false;
if(right.z > z)
return true;
else if(right.z < z)
return false;
return false;
}
Also, make sure that you sort the vertices before interpolation, if you're using floats instead of doubles. This is because cracks can form in the mesh if the vertices aren't sorted.
vertex_3 marching_cubes::vertex_interp(const float isovalue, vertex_3 p1, vertex_3 p2, float valp1, float valp2)
{
// Sort the vertices so that cracks don't mess up the water-tightness of the mesh.
// Note: the cracks don't appear if you use doubles instead of floats.
if (p2 < p1)
{
vertex_3 tempv = p2;
p2 = p1;
p1 = tempv;
float tempf = valp2;
valp2 = valp1;
valp1 = tempf;
}
const float epsilon = 1e-10f;
if(fabs(isovalue - valp1) < epsilon)
return(p1);
if(fabs(isovalue - valp2) < epsilon)
return(p2);
if(fabs(valp1 - valp2) < epsilon)
return(p1);
float mu = (isovalue - valp1) / (valp2 - valp1);
return p1 + (p2 - p1)*mu;
}
The full codes are at:
https://github.com/sjhalayka/marching_cubes
https://github.com/sjhalayka/opengl1_stlview