subdiv.h

来自「RBF平台」· C头文件 代码 · 共 397 行

H
397
字号
/*Szymon RusinkiewiczPrinceton Universitysubdiv.hPerform subdivision on a mesh.*/#include <stdio.h>#include "TriMesh.h"#include "TriMesh_algo.h"// i+1 and i-1 modulo 3// This way of computing it tends to be faster than using %#define NEXT(i) ((i)<2 ? (i)+1 : (i)-2)#define PREV(i) ((i)>0 ? (i)-1 : (i)+2)// Compute the ordinary Loop edge stencilstatic point loop(TriMesh *mesh, int f1, int f2,		  int v0, int v1, int v2, int v3){	return 0.125f * (mesh->vertices[v0] + mesh->vertices[v3]) +	       0.375f * (mesh->vertices[v1] + mesh->vertices[v2]);}// The point at the opposite quadrilateral corner.// If it doesn't exist, reflect the given point across the edge.static point opposite(TriMesh *mesh, int f, int v){	int ind = mesh->faces[f].indexof(v);	int ae = mesh->across_edge[f][ind];	if (ae) {		int j = mesh->faces[ae].indexof(mesh->faces[f][NEXT(ind)]);		return mesh->vertices[mesh->faces[ae][NEXT(j)]];	}	return mesh->vertices[mesh->faces[f][NEXT(ind)]] +	       mesh->vertices[mesh->faces[f][PREV(ind)]] -	       mesh->vertices[v];}// Compute the butterfly stencilstatic point butterfly(TriMesh *mesh, int f1, int f2,		       int v0, int v1, int v2, int v3){	point p = 0.5f * (mesh->vertices[v1] + mesh->vertices[v2]) +	          0.125f * (mesh->vertices[v0] + mesh->vertices[v3]);	p -= 0.0625f * (opposite(mesh, f1, v1) + opposite(mesh, f1, v2) +			opposite(mesh, f2, v1) + opposite(mesh, f2, v2));	return p;}// Compute Loop's new edge mask for an extraordinary vertex for SUBDIV_LOOP_NEWstatic point new_loop_edge(TriMesh *mesh, int f1, int f2,			   int v0, int v1, int v2, int v3){	static const float wts[6][5] = {		{ 0, 0, 0, 0, 0 },		{ 0, 0, 0, 0, 0 },		{ 0, 0, 0, 0, 0 },		{ 0, 0, 0, 0, 0 },		{ 0.3828125f, 0.125f, 0.0078125f, 0.125f, 0 },		{ 0.3945288f, 0.1215267f, 0.01074729f, 0.01074729f, 0.1215267f }, 	};	int n = mesh->adjacentfaces[v1].size();	if (n <= 3)		return loop(mesh, f1, f2, v0, v1, v2, v3);	point p;	float sumwts = 0.0f;	int f = f1;	float s1 = 1.0f / n;	float s2 = 2.0f * M_PI * s1;	float l = 0.375f + 0.25f * cos(s2);	float a = (2.0f * l*l*l) / ((1.0f - l) * n);	float b = (1.0f / l) - 1.5f;	for (int i = 0; i < n; i++) {		int ind = mesh->faces[f].indexof(v1);		if (ind == -1)			return loop(mesh, f1, f2, v0, v1, v2, v3);		ind = NEXT(ind);		int v = mesh->faces[f][ind];		float wt;		if (n < 6) {			wt = wts[n][i];		} else {			float c = cos(s2 * i);			wt = a * (1.0f + c) * sqr(b + c);		}		p += wt * mesh->vertices[v];		sumwts += wt;		f = mesh->across_edge[f][ind];		if (f == -1)			return loop(mesh, f1, f2, v0, v1, v2, v3);	}	if (f != f1)		return loop(mesh, f1, f2, v0, v1, v2, v3);	return p + (1.0f - sumwts) * mesh->vertices[v1];}// Compute Zorin's edge mask for an extraordinary vertex for// SUBDIV_BUTTERFLY_MODIFIEDstatic point zorin_edge(TriMesh *mesh, int f1, int f2,			int v0, int v1, int v2, int v3){	static const float wts[6][5] = {		{ 0, 0, 0, 0, 0 },		{ 0, 0, 0, 0, 0 },		{ 0, 0, 0, 0, 0 },		{ 0.4166667f, -0.08333333f, -0.08333333f, 0, 0 },		{ 0.375f, 0, -0.125f, 0, 0 },		{ 0.35f, 0.0309017f, -0.0809017f, -0.0809017f, 0.0309017f },	};	int n = mesh->adjacentfaces[v1].size();	if (n < 3)		return butterfly(mesh, f1, f2, v0, v1, v2, v3);	point p;	float sumwts = 0.0f;	int f = f1;	float s1 = 1.0f / n;	float s2 = 2.0f * M_PI * s1;	for (int i = 0; i < n; i++) {		int ind = mesh->faces[f].indexof(v1);		if (ind == -1)			return butterfly(mesh, f1, f2, v0, v1, v2, v3);		ind = NEXT(ind);		int v = mesh->faces[f][ind];		float wt;		if (n < 6) {			wt = wts[n][i];		} else {			float c = cos(s2 * i);			wt = s1 * (c*c + c - 0.25f);		}		p += wt * mesh->vertices[v];		sumwts += wt;		f = mesh->across_edge[f][ind];		if (f == -1)			return butterfly(mesh, f1, f2, v0, v1, v2, v3);	}	if (f != f1)		return butterfly(mesh, f1, f2, v0, v1, v2, v3);	return p + (1.0f - sumwts) * mesh->vertices[v1];}// Average position of all boundary vertices on triangles adjacent to vstatic point avg_bdy(TriMesh *mesh, int v){	point p;	int n = 0;	const vector<int> &a = mesh->adjacentfaces[v];	for (int i = 0; i < a.size(); i++) {		int f = a[i];		for (int j = 0; j < 3; j++) {			if (mesh->across_edge[f][j] == -1) {				p += mesh->vertices[mesh->faces[f][NEXT(j)]];				p += mesh->vertices[mesh->faces[f][PREV(j)]];				n += 2;			}		}	}	return p * (1.0f / n);}// Compute the weight on the central vertex used in updating original// vertices in Loop subdivisionstatic float loop_update_alpha(int scheme, int n){	if (scheme == SUBDIV_LOOP) {		if (n == 3)	  return 0.3438f;		else if (n == 4)  return 0.4625f;		else if (n == 5)  return 0.5625f;		return 0.625f;	} else if (scheme == SUBDIV_LOOP_ORIG) {		if (n == 3)	  return 0.4375f;		else if (n == 4)  return 0.515625f;		else if (n == 5)  return 0.5795339f;		else if (n == 6)  return 0.625f;		return 0.375f + sqr(0.375f + 0.25f * cos(2.0f * M_PI / n));	}	// SUBDIV_LOOP_NEW	if (n == 3)	  return 0.4375f;	else if (n == 4)  return 0.5f;	else if (n == 5)  return 0.545466f;	else if (n == 6)  return 0.625f;	float l = 0.375f + 0.25f * cos(2.0f * M_PI / n);	float beta = l * (4.0f + l * (5.0f * l - 8.0f)) / (2.0f * (1.0f - l));	return 1.0f - beta + l * l;}// Insert a new vertexstatic void insert_vert(TriMesh *mesh, int scheme, int f, int e){	int v1 = mesh->faces[f][NEXT(e)], v2 = mesh->faces[f][PREV(e)];	if (scheme == SUBDIV_PLANAR) {		point p = 0.5f * (mesh->vertices[v1] +				  mesh->vertices[v2]);		mesh->vertices.push_back(p);		return;	}	int ae = mesh->across_edge[f][e];	if (ae == -1) {		// Boundary		point p = 0.5f * (mesh->vertices[v1] +				  mesh->vertices[v2]);		if (scheme == SUBDIV_BUTTERFLY ||		    scheme == SUBDIV_BUTTERFLY_MODIFIED) {			p *= 1.5f;			p -= 0.25f * (avg_bdy(mesh, v1) + avg_bdy(mesh, v2));		}		mesh->vertices.push_back(p);		return;	}	int v0 = mesh->faces[f][e];	const TriMesh::Face &aef = mesh->faces[ae];	int v3 = aef[NEXT(aef.indexof(v1))];	point p;	if (scheme == SUBDIV_LOOP || scheme == SUBDIV_LOOP_ORIG) {		p = loop(mesh, f, ae, v0, v1, v2, v3);	} else if (scheme == SUBDIV_LOOP_NEW) {		bool e1 = (mesh->adjacentfaces[v1].size() != 6);		bool e2 = (mesh->adjacentfaces[v2].size() != 6);		if (e1 && e2)			p = 0.5f * (new_loop_edge(mesh, f, ae, v0, v1, v2, v3) +				    new_loop_edge(mesh, ae, f, v3, v2, v1, v0));		else if (e1)			p = new_loop_edge(mesh, f, ae, v0, v1, v2, v3);		else if (e2)			p = new_loop_edge(mesh, ae, f, v3, v2, v1, v0);		else			p = loop(mesh, f, ae, v0, v1, v2, v3);	} else if (scheme == SUBDIV_BUTTERFLY) {		p = butterfly(mesh, f, ae, v0, v1, v2, v3);	} else if (scheme == SUBDIV_BUTTERFLY_MODIFIED) {		bool e1 = (mesh->adjacentfaces[v1].size() != 6);		bool e2 = (mesh->adjacentfaces[v2].size() != 6);		if (e1 && e2)			p = 0.5f * (zorin_edge(mesh, f, ae, v0, v1, v2, v3) +				    zorin_edge(mesh, ae, f, v3, v2, v1, v0));		else if (e1)			p = zorin_edge(mesh, f, ae, v0, v1, v2, v3);		else if (e2)			p = zorin_edge(mesh, ae, f, v3, v2, v1, v0);		else			p = butterfly(mesh, f, ae, v0, v1, v2, v3);	}	mesh->vertices.push_back(p);}// Subdivide a meshvoid subdiv(TriMesh *mesh, int scheme /* = SUBDIV_LOOP */){	bool have_col = !mesh->colors.empty();	bool have_conf = !mesh->confidences.empty();	mesh->flags.clear();	mesh->normals.clear();	mesh->pdir1.clear(); mesh->pdir2.clear();	mesh->curv1.clear(); mesh->curv2.clear();	mesh->dcurv.clear();	mesh->cornerareas.clear(); mesh->pointareas.clear();	mesh->bsphere.valid = false;	mesh->need_faces(); mesh->tstrips.clear();	mesh->neighbors.clear();	mesh->need_across_edge(); mesh->need_adjacentfaces();	TriMesh::dprintf("Subdividing mesh... ");	// Introduce new vertices	int nf = mesh->faces.size();	vector<TriMesh::Face> newverts(nf, TriMesh::Face(-1,-1,-1));	int old_nv = mesh->vertices.size();	mesh->vertices.reserve(4 * old_nv);	vector<int> newvert_count(old_nv + 3*nf);	if (have_col)		mesh->colors.reserve(4 * old_nv);	if (have_conf)		mesh->confidences.reserve(4 * old_nv);	for (int i = 0; i < nf; i++) {		for (int j = 0; j < 3; j++) {			if (newverts[i][j] != -1)				continue;			int ae = mesh->across_edge[i][j];			if (ae != -1) {				if (mesh->across_edge[ae][0] == i)					newverts[i][j] = newverts[ae][0];				else if (mesh->across_edge[ae][1] == i)					newverts[i][j] = newverts[ae][1];				else if (mesh->across_edge[ae][2] == i)					newverts[i][j] = newverts[ae][2];			}			if (newverts[i][j] != -1)				continue;			insert_vert(mesh, scheme, i, j);			newverts[i][j] = mesh->vertices.size() - 1;			if (ae != -1) {				if (mesh->across_edge[ae][0] == i)					newverts[ae][0] = newverts[i][j];				else if (mesh->across_edge[ae][1] == i)					newverts[ae][1] = newverts[i][j];				else if (mesh->across_edge[ae][2] == i)					newverts[ae][2] = newverts[i][j];			}			const TriMesh::Face &v = mesh->faces[i];			if (have_col) {				unsigned char *c1 = mesh->colors[v[NEXT(j)]];				unsigned char *c2 = mesh->colors[v[PREV(j)]];				mesh->colors.push_back(Color((c1[0]+c2[0])/2,							     (c1[1]+c2[1])/2,							     (c1[2]+c2[2])/2));			}			if (have_conf)				mesh->confidences.push_back(0.5f *					mesh->confidences[v[NEXT(j)]] +					mesh->confidences[v[PREV(j)]]);		}	}	// Update old vertices	if (scheme == SUBDIV_LOOP ||	    scheme == SUBDIV_LOOP_ORIG ||	    scheme == SUBDIV_LOOP_NEW) {		for (int i = 0; i < old_nv; i++) {			point bdyavg, nbdyavg;			int nbdy = 0, nnbdy = 0;			int naf = mesh->adjacentfaces[i].size();			if (!naf)				continue;			for (int j = 0; j < naf; j++) {				int af = mesh->adjacentfaces[i][j];				int afi = mesh->faces[af].indexof(i);				int n1 = NEXT(afi);				int n2 = PREV(afi);				if (mesh->across_edge[af][n1] == -1) {					bdyavg += mesh->vertices[mesh->faces[af][n2]];					nbdy++;				} else {					nbdyavg += mesh->vertices[mesh->faces[af][n2]];					nnbdy++;				}				if (mesh->across_edge[af][n2] == -1) {					bdyavg += mesh->vertices[mesh->faces[af][n1]];					nbdy++;				} else {					nbdyavg += mesh->vertices[mesh->faces[af][n1]];					nnbdy++;				}			}			float alpha;			point newpt;			if (nbdy) {				newpt = bdyavg / (float) nbdy;				alpha = 0.75f;			} else if (nnbdy) {				newpt = nbdyavg / (float) nnbdy;				alpha = loop_update_alpha(scheme, nnbdy/2);			} else {				continue;			}			mesh->vertices[i] *= alpha;			mesh->vertices[i] += (1.0f - alpha) * newpt;		}	}	// Insert new faces	mesh->adjacentfaces.clear(); mesh->across_edge.clear();	mesh->faces.reserve(4*nf);	for (int i = 0; i < nf; i++) {		TriMesh::Face &v = mesh->faces[i];		TriMesh::Face &n = newverts[i];		mesh->faces.push_back(TriMesh::Face(v[0], n[2], n[1]));		mesh->faces.push_back(TriMesh::Face(v[1], n[0], n[2]));		mesh->faces.push_back(TriMesh::Face(v[2], n[1], n[0]));		v = n;	}	TriMesh::dprintf("Done.\n");}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?