Rev 39 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#pragma warning(disable: 4786) // disable warning C4786: symbol greater than 255
#include <stack>
#include "TriMeshBuilder.h"
using namespace std;
using namespace CGLA;
namespace IMesh
{
namespace
{
/** Neighbours is a simple class which overloads ().
Given an instance nbrs of this class nbrs(a,b) will
return true if a and b share an edge. */
class Neighbours
{
const TriMeshBuilder* const bldr;
public:
Neighbours(const TriMeshBuilder* const _bldr):
bldr(_bldr)
{}
bool operator()(int a, int b)
{
Vec3i fa = bldr->face(a);
Vec3i fb = bldr->face(b);
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
if(fa[i]==fb[j] && fa[(i+1)%3]==fb[(j+2)%3])
return true;
return false;
}
};
}
void compute_face_normals(TriMeshBuilder& bldr, bool do_flip)
{
bldr.register_face_normals();
for(int i=0;i<bldr.no_faces(); ++i)
{
Vec3f p0 = bldr.vpos(i,0);
Vec3f p1 = bldr.vpos(i,1);
Vec3f p2 = bldr.vpos(i,2);
Vec3f norm = cross(p1-p0,p2-p0);
float len = norm.length();
if(len > 0)
norm /= len;
if(do_flip)
bldr.add_fnorm(-norm);
else
bldr.add_fnorm(norm);
}
}
void compute_vertex_normals(TriMeshBuilder& bldr)
{
AttrHandle<CGLA::Vec3f> norm_handle;
if(!bldr.get_vattr_handle("VA_NORM", norm_handle))
{
bldr.register_vertex_normals();
for(int i=0;i<bldr.no_vertices(); ++i)
bldr.add_vnorm(Vec3f(0));
}
for(int face_idx=0; face_idx<bldr.no_faces(); ++face_idx)
{
int i;
Vec3f p[3];
for(i=0;i<3;++i)
p[i] = bldr.vpos(face_idx,i);
Vec3f v10 = p[1]-p[0];
Vec3f v20 = p[2]-p[0];
Vec3f v21 = p[2]-p[1];
Vec3f v01 = p[0]-p[1];
float l10 = v10.length();
float l20 = v20.length();
float l21 = v21.length();
float l01 = v01.length();
v10 = (l10>0.0f) ? v10 / l10 : Vec3f(0);
v20 = (l20>0.0f) ? v20 / l20 : Vec3f(0);
v21 = (l21>0.0f) ? v21 / l21 : Vec3f(0);
v01 = (l01>0.0f) ? v01 / l01 : Vec3f(0);
float a[3];
a[0] = acos(dot(v10, v20));
a[1] = acos(dot(v21,v01));
a[2] = M_PI - a[0] - a[1];
Vec3f fn = bldr.fnorm(face_idx);
for(i=0;i<3;++i)
bldr.vnorm(face_idx,i) += fn * a[i];
}
for(int norm_idx=0;norm_idx<bldr.no_vnorm();++norm_idx)
bldr.vnorm(norm_idx).normalize();
}
void compute_vertex_normals(TriMeshBuilder& bldr,
AttrHandle<int> smooth_group_attr)
{
int face_set = bldr.register_face_set();
bldr.register_vertex_normals(face_set);
vector<vector<int> > per_vertex_face_vec(bldr.no_vertices());
for(int face_idx=0; face_idx < bldr.no_faces(); ++face_idx)
{
Vec3i face = bldr.face(face_idx);
per_vertex_face_vec[face[0]].push_back(face_idx);
per_vertex_face_vec[face[1]].push_back(face_idx);
per_vertex_face_vec[face[2]].push_back(face_idx);
}
Neighbours nbrs(&bldr);
for(int vert_idx=0; vert_idx<bldr.no_vertices(); ++vert_idx)
{
int n_faces = per_vertex_face_vec[vert_idx].size();
vector<int> N(n_faces, -1);
for(int i=0;i<n_faces;++i)
{
if(N[i] == -1)
{
N[i] = bldr.add_vnorm(Vec3f(0));
stack<int> q;
q.push(i);
while(!q.empty())
{
int l = q.top();
q.pop();
int idx_l = per_vertex_face_vec[vert_idx][l];
int sg_l = bldr.fattr(smooth_group_attr, idx_l);
for(int j=i+1;j<n_faces;++j)
{
int idx_j = per_vertex_face_vec[vert_idx][j];
int sg_j = bldr.fattr(smooth_group_attr, idx_j);
if((N[j] == -1) &&
nbrs(idx_j,idx_l) &&
((sg_j&sg_l) != 0))
{
N[j] = N[l];
q.push(j);
}
}
}
}
}
for(int k=0;k<n_faces; ++k)
{
assert(N[k] != -1);
int face_idx = per_vertex_face_vec[vert_idx][k];
Vec3i face = bldr.face(face_idx);
Vec3i norm_face = bldr.face(face_idx, face_set);
for(int j=0;j<3;++j)
if(face[j] == vert_idx)
norm_face[j] = N[k];
bldr.face(face_idx, face_set) = norm_face;
}
}
compute_vertex_normals(bldr);
}
void compute_vertex_normals(TriMeshBuilder& bldr, float cos_ang)
{
int face_set = bldr.register_face_set();
bldr.register_vertex_normals(face_set);
vector<vector<int> > per_vertex_face_vec(bldr.no_vertices());
for(int face_idx=0; face_idx < bldr.no_faces(); ++face_idx)
{
Vec3i face = bldr.face(face_idx);
per_vertex_face_vec[face[0]].push_back(face_idx);
per_vertex_face_vec[face[1]].push_back(face_idx);
per_vertex_face_vec[face[2]].push_back(face_idx);
}
Neighbours nbrs(&bldr);
for(int vert_idx=0; vert_idx<bldr.no_vertices(); ++vert_idx)
{
int n_faces = per_vertex_face_vec[vert_idx].size();
vector<int> N(n_faces, -1);
for(int i=0;i<n_faces;++i)
{
if(N[i] == -1)
{
N[i] = bldr.add_vnorm(Vec3f(0));
stack<int> q;
q.push(i);
while(!q.empty())
{
int l = q.top();
q.pop();
int idx_l = per_vertex_face_vec[vert_idx][l];
Vec3f norm_l = bldr.fnorm(idx_l);
for(int j=i+1;j<n_faces;++j)
{
int idx_j = per_vertex_face_vec[vert_idx][j];
Vec3f norm_j = bldr.fnorm(idx_j);
if((N[j] == -1) &&
nbrs(idx_j,idx_l) &&
(dot(norm_l, norm_j)>cos_ang))
{
N[j] = N[l];
q.push(j);
}
}
}
}
}
for(int k=0;k<n_faces; ++k)
{
assert(N[k] != -1);
int face_idx = per_vertex_face_vec[vert_idx][k];
Vec3i face = bldr.face(face_idx);
Vec3i norm_face = bldr.face(face_idx, face_set);
for(int j=0;j<3;++j)
if(face[j] == vert_idx)
norm_face[j] = N[k];
bldr.face(face_idx, face_set) = norm_face;
}
}
compute_vertex_normals(bldr);
}
}