diffuse.h
来自「RBF平台」· C头文件 代码 · 共 249 行
H
249 行
/*Szymon RusinkiewiczPrinceton Universitydiffuse.ccSmoothing of meshes and per-vertex fields*/#include <stdio.h>#include "TriMesh.h"#include "vec.h"#include "timestamp.h"#include <cmath>using namespace std;// Functor classes for adding vector or tensor fields on the surfacestruct AccumVec { const vector<vec> &field; AccumVec(const vector<vec> &field_) : field(field_) {}
void operator() (const TriMesh *themesh, int v0, vec &f, float w, int v) { f += w * field[v]; }};struct AccumCurv {
//the following two lines are no use, but if no, one error occurs;
const vector<vec> &temp;
AccumCurv(const vector<vec> &temp_) : temp(temp_) {}
void operator() (const TriMesh *themesh, int v0, vec &c, float w, int v) { vec ncurv; proj_curv(themesh->pdir1[v], themesh->pdir2[v], themesh->curv1[v], 0, themesh->curv2[v], themesh->pdir1[v0], themesh->pdir2[v0], ncurv[0], ncurv[1], ncurv[2]); c += w * ncurv; }};struct AccumDCurv { void operator() (const TriMesh *themesh, int v0, Vec<4> &d, float w, int v) { Vec<4> ndcurv; proj_dcurv(themesh->pdir1[v], themesh->pdir2[v], themesh->dcurv[v], themesh->pdir1[v0], themesh->pdir2[v0], ndcurv); d += w * ndcurv; }};
// Approximation to Gaussian... Used in filtering
static inline float wt(const TriMesh *themesh, int v1, int v2, float invsigma2)
{
float d2 = invsigma2 * dist2(themesh->vertices[v1],
themesh->vertices[v2]);
return (d2 >= 9.0f) ? 0.0f : exp(-0.5f*d2);
//return (d2 >= 25.0f) ? 0.0f : exp(-0.5f*d2);
}
// Diffuse a vector field at 1 vertex, weighted by
// a Gaussian of width 1/sqrt(invsigma2)
template<class ACCUM, class T>
static void diffuse_vert_field(TriMesh *themesh, ACCUM accum,
int v, float invsigma2, T &flt)
{
flt = T();
accum(themesh, v, flt, themesh->pointareas[v], v);
float sum_w = themesh->pointareas[v];
const vec &nv = themesh->normals[v];
unsigned &flag = themesh->flag_curr;
flag++;
themesh->flags[v] = flag;
vector<int> boundary = themesh->neighbors[v];
while (!boundary.empty()) {
int n = boundary.back();
boundary.pop_back();
if (themesh->flags[n] == flag)
continue;
themesh->flags[n] = flag;
if ((nv DOT themesh->normals[n]) <= 0.0f)
continue;
// Gaussian weight
float w = wt(themesh, n, v, invsigma2);
if (w == 0.0f)
continue;
// Downweight things pointing in different directions
w *= nv DOT themesh->normals[n];
// Surface area "belonging" to each point
w *= themesh->pointareas[n];
// Accumulate weight times field at neighbor
accum(themesh, v, flt, w, n);
sum_w += w;
for (int i = 0; i < themesh->neighbors[n].size(); i++) {
int nn = themesh->neighbors[n][i];
if (themesh->flags[nn] == flag)
continue;
boundary.push_back(nn);
}
}
flt /= sum_w;
}
class MeshDiffuse{
public:
// Diffuse the normals across the mesh
void diffuse_normals(TriMesh *themesh, float sigma)
{
themesh->need_normals();
themesh->need_pointareas();
themesh->need_neighbors();
int nv = themesh->vertices.size();
if (themesh->flags.size() != nv)
themesh->flags.resize(nv);
//TriMesh::dprintf("\rSmoothing normals... ");
//timestamp t = now();
float invsigma2 = 1.0f / sqr(sigma);
vector<vec> nflt(nv);
for (int i = 0; i < nv; i++) {
diffuse_vert_field(themesh, AccumVec(themesh->normals),
i, invsigma2, nflt[i]);
normalize(nflt[i]);
}
themesh->normals = nflt;
//TriMesh::dprintf("Done. Filtering took %f sec.\n", now() - t);
}
// Smooth the mesh geometry. // XXX - this is perhaps not a great way to do this, // but it seems to work better than most other things I've tried... void smooth_mesh(TriMesh *themesh, float sigma) { themesh->need_faces(); diffuse_normals(themesh, 0.5f * sigma); int nv = themesh->vertices.size(); TriMesh::dprintf("\rSmoothing... "); timestamp t = now(); float invsigma2 = 1.0f / sqr(sigma); vector<point> dflt(nv); for (int i = 0; i < nv; i++) { diffuse_vert_field(themesh, AccumVec(themesh->vertices), i, invsigma2, dflt[i]); // Just keep the displacement dflt[i] -= themesh->vertices[i]; } // Slightly better small-neighborhood approximation
int k; int nf = themesh->faces.size(); for (i = 0; i < nf; i++) { point c = themesh->vertices[themesh->faces[i][0]] + themesh->vertices[themesh->faces[i][1]] + themesh->vertices[themesh->faces[i][2]]; c /= 3.0f; for (int j = 0; j < 3; j++) { int v = themesh->faces[i][j]; vec d = 0.5f * (c - themesh->vertices[v]);
double expv = exp(-0.5f * invsigma2 * len2(d));
for(k = 0; k < 3; k++)
dflt[v][k] += themesh->cornerareas[i][j] / themesh->pointareas[themesh->faces[i][j]] * expv * d[k]; } } // Filter displacement field vector<point> dflt2(nv); for (i = 0; i < nv; i++) { diffuse_vert_field(themesh, AccumVec(dflt), i, invsigma2, dflt2[i]); } // Update vertex positions for (i = 0; i < nv; i++) themesh->vertices[i] += dflt[i] - dflt2[i]; // second Laplacian //TriMesh::dprintf("Done. Filtering took %f sec.\n", now() - t); } // Diffuse the curvatures across the mesh void diffuse_curv(TriMesh *themesh, float sigma) { themesh->need_normals(); themesh->need_pointareas(); themesh->need_curvatures(); themesh->need_neighbors(); int nv = themesh->vertices.size(); if (themesh->flags.size() != nv) themesh->flags.resize(nv); //TriMesh::dprintf("\rSmoothing curvatures... "); timestamp t = now(); float invsigma2 = 1.0f / sqr(sigma);
vector<vec> nouse; vector< vec > cflt(nv); for (int i = 0; i < nv; i++) diffuse_vert_field(themesh, AccumCurv(nouse), i, invsigma2, cflt[i]);
for (i = 0; i < nv; i++) diagonalize_curv(themesh->pdir1[i], themesh->pdir2[i], cflt[i][0], cflt[i][1], cflt[i][2], themesh->normals[i], themesh->pdir1[i], themesh->pdir2[i], themesh->curv1[i], themesh->curv2[i]); //TriMesh::dprintf("Done. Filtering took %f sec.\n", now() - t); } // Diffuse the curvature derivatives across the mesh void diffuse_dcurv(TriMesh *themesh, float sigma) { themesh->need_normals(); themesh->need_pointareas(); themesh->need_curvatures(); themesh->need_dcurv(); themesh->need_neighbors(); int nv = themesh->vertices.size(); if (themesh->flags.size() != nv) themesh->flags.resize(nv); //TriMesh::dprintf("\rSmoothing curvature derivatives... "); timestamp t = now(); float invsigma2 = 1.0f / sqr(sigma); vector< Vec<4> > dflt(nv);
for (int i = 0; i < nv; i++) diffuse_vert_field(themesh, AccumDCurv(), i, invsigma2, dflt[i]); themesh->dcurv = dflt; //TriMesh::dprintf("Done. Filtering took %f sec.\n", now() - t); }};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?