Beispiel #1
0
static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
{
	MDefBoundIsect *isect;
	float rhs, weight, totweight;
	int i, a, acenter;

	acenter= meshdeform_index(mdb, x, y, z, 0);
	if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
		return;

	totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
	for(i=1; i<=6; i++) {
		a= meshdeform_index(mdb, x, y, z, i);
		if(a == -1)
			continue;

		isect= mdb->boundisect[acenter][i-1];

		if (isect) {
			weight= (1.0f/isect->len)/totweight;
			rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert);
			nlRightHandSideAdd(0, mdb->varidx[acenter], rhs);
		}
	}
}
Beispiel #2
0
void laplacian_add_right_hand_side(LaplacianSystem *UNUSED(sys), int v, float value)
{
	nlRightHandSideAdd(0, v, value);
}
static void laplaciansmoothModifier_do(
        LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	LaplacianSystem *sys;
	MDeformVert *dvert = NULL;
	MDeformVert *dv = NULL;
	float w, wpaint;
	int i, iter;
	int defgrp_index;

	DM_ensure_tessface(dm);

	sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumTessFaces(dm), numVerts);
	if (!sys) {
		return;
	}

	sys->mfaces = dm->getTessFaceArray(dm);
	sys->medges = dm->getEdgeArray(dm);
	sys->vertexCos = vertexCos;
	sys->min_area = 0.00001f;
	modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);

	sys->vert_centroid[0] = 0.0f;
	sys->vert_centroid[1] = 0.0f;
	sys->vert_centroid[2] = 0.0f;
	for (iter = 0; iter < smd->repeat; iter++) {
		memset_laplacian_system(sys, 0);
		nlNewContext();
		sys->context = nlGetCurrent();
		nlSolverParameteri(NL_NB_VARIABLES, numVerts);
		nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
		nlSolverParameteri(NL_NB_ROWS, numVerts);
		nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);

		init_laplacian_matrix(sys);

		nlBegin(NL_SYSTEM);
		for (i = 0; i < numVerts; i++) {
			nlSetVariable(0, i, vertexCos[i][0]);
			nlSetVariable(1, i, vertexCos[i][1]);
			nlSetVariable(2, i, vertexCos[i][2]);
			if (iter == 0) {
				add_v3_v3(sys->vert_centroid, vertexCos[i]);
			}
		}
		if (iter == 0 && numVerts > 0) {
			mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts);
		}

		nlBegin(NL_MATRIX);
		dv = dvert;
		for (i = 0; i < numVerts; i++) {
			nlRightHandSideAdd(0, i, vertexCos[i][0]);
			nlRightHandSideAdd(1, i, vertexCos[i][1]);
			nlRightHandSideAdd(2, i, vertexCos[i][2]);
			if (dv) {
				wpaint = defvert_find_weight(dv, defgrp_index);
				dv++;
			}
			else {
				wpaint = 1.0f;
			}

			if (sys->zerola[i] == 0) {
				if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) {
					w = sys->vweights[i];
					sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w;
					w = sys->vlengths[i];
					sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
					if (sys->numNeEd[i] == sys->numNeFa[i]) {
						nlMatrixAdd(i, i,  1.0f + fabsf(smd->lambda) * wpaint);
					}
					else {
						nlMatrixAdd(i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
					}
				}
				else {
					w = sys->vweights[i] * sys->ring_areas[i];
					sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w);
					w = sys->vlengths[i];
					sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;

					if (sys->numNeEd[i] == sys->numNeFa[i]) {
						nlMatrixAdd(i, i,  1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
					}
					else {
						nlMatrixAdd(i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
					}
				}
			}
			else {
				nlMatrixAdd(i, i, 1.0f);
			}
		}

		fill_laplacian_matrix(sys);

		nlEnd(NL_MATRIX);
		nlEnd(NL_SYSTEM);

		if (nlSolveAdvanced(NULL, NL_TRUE)) {
			validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
		}
		nlDeleteContext(sys->context);
		sys->context = NULL;
	}
	delete_laplacian_system(sys);

}
/**
 * This method computes the Laplacian Matrix and Differential Coordinates for all vertex in the mesh.
 * The Linear system is LV = d
 * Where L is Laplacian Matrix, V as the vertexes in Mesh, d is the differential coordinates
 * The Laplacian Matrix is computes as a
 * Lij = sum(Wij) (if i == j)
 * Lij = Wij (if i != j)
 * Wij is weight between vertex Vi and vertex Vj, we use cotangent weight
 *
 * The Differential Coordinate is computes as a
 * di = Vi * sum(Wij) - sum(Wij * Vj)
 * Where :
 * di is the Differential Coordinate i
 * sum (Wij) is the sum of all weights between vertex Vi and its vertexes neighbors (Vj)
 * sum (Wij * Vj) is the sum of the product between vertex neighbor Vj and weight Wij for all neighborhood.
 *
 * This Laplacian Matrix is described in the paper:
 * Desbrun M. et.al, Implicit fairing of irregular meshes using diffusion and curvature flow, SIGGRAPH '99, pag 317-324,
 * New York, USA
 *
 * The computation of Laplace Beltrami operator on Hybrid Triangle/Quad Meshes is described in the paper:
 * Pinzon A., Romero E., Shape Inflation With an Adapted Laplacian Operator For Hybrid Quad/Triangle Meshes,
 * Conference on Graphics Patterns and Images, SIBGRAPI, 2013
 *
 * The computation of Differential Coordinates is described in the paper:
 * Sorkine, O. Laplacian Surface Editing. Proceedings of the EUROGRAPHICS/ACM SIGGRAPH Symposium on Geometry Processing,
 * 2004. p. 179-188.
 */
static void initLaplacianMatrix(LaplacianSystem *sys)
{
	float v1[3], v2[3], v3[3], v4[3], no[3];
	float w2, w3, w4;
	int i, j, fi;
	bool has_4_vert;
	unsigned int idv1, idv2, idv3, idv4;

	for (fi = 0; fi < sys->total_faces; fi++) {
		const unsigned int *vidf = sys->faces[fi];

		idv1 = vidf[0];
		idv2 = vidf[1];
		idv3 = vidf[2];
		idv4 = vidf[3];

		has_4_vert = vidf[3] ? 1 : 0;
		if (has_4_vert) {
			normal_quad_v3(no, sys->co[idv1], sys->co[idv2], sys->co[idv3], sys->co[idv4]);
			add_v3_v3(sys->no[idv4], no);
			i = 4;
		}
		else {
			normal_tri_v3(no, sys->co[idv1], sys->co[idv2], sys->co[idv3]);
			i = 3;
		}
		add_v3_v3(sys->no[idv1], no);
		add_v3_v3(sys->no[idv2], no);
		add_v3_v3(sys->no[idv3], no);

		for (j = 0; j < i; j++) {
			idv1 = vidf[j];
			idv2 = vidf[(j + 1) % i];
			idv3 = vidf[(j + 2) % i];
			idv4 = has_4_vert ? vidf[(j + 3) % i] : 0;

			copy_v3_v3(v1, sys->co[idv1]);
			copy_v3_v3(v2, sys->co[idv2]);
			copy_v3_v3(v3, sys->co[idv3]);
			if (has_4_vert) {
				copy_v3_v3(v4, sys->co[idv4]);
			}

			if (has_4_vert) {

				w2 = (cotan_weight(v4, v1, v2) + cotan_weight(v3, v1, v2)) / 2.0f;
				w3 = (cotan_weight(v2, v3, v1) + cotan_weight(v4, v1, v3)) / 2.0f;
				w4 = (cotan_weight(v2, v4, v1) + cotan_weight(v3, v4, v1)) / 2.0f;

				sys->delta[idv1][0] -= v4[0] * w4;
				sys->delta[idv1][1] -= v4[1] * w4;
				sys->delta[idv1][2] -= v4[2] * w4;

				nlRightHandSideAdd(0, idv1, -v4[0] * w4);
				nlRightHandSideAdd(1, idv1, -v4[1] * w4);
				nlRightHandSideAdd(2, idv1, -v4[2] * w4);

				nlMatrixAdd(idv1, idv4, -w4);
			}
			else {
				w2 = cotan_weight(v3, v1, v2);
				w3 = cotan_weight(v2, v3, v1);
				w4 = 0.0f;
			}

			sys->delta[idv1][0] += v1[0] * (w2 + w3 + w4);
			sys->delta[idv1][1] += v1[1] * (w2 + w3 + w4);
			sys->delta[idv1][2] += v1[2] * (w2 + w3 + w4);

			sys->delta[idv1][0] -= v2[0] * w2;
			sys->delta[idv1][1] -= v2[1] * w2;
			sys->delta[idv1][2] -= v2[2] * w2;

			sys->delta[idv1][0] -= v3[0] * w3;
			sys->delta[idv1][1] -= v3[1] * w3;
			sys->delta[idv1][2] -= v3[2] * w3;

			nlMatrixAdd(idv1, idv2, -w2);
			nlMatrixAdd(idv1, idv3, -w3);
			nlMatrixAdd(idv1, idv1, w2 + w3 + w4);

		}
	}
}