[Bf-blender-cvs] [123b64f] master: BMesh: improved smooth subdivision

Campbell Barton noreply at git.blender.org
Sun Oct 4 15:09:02 CEST 2015


Commit: 123b64f818da77dfaf3783d88f5c6be8bbd99a87
Author: Campbell Barton
Date:   Sun Oct 4 23:20:48 2015 +1100
Branches: master
https://developer.blender.org/rB123b64f818da77dfaf3783d88f5c6be8bbd99a87

BMesh: improved smooth subdivision

Instead of offsetting along normals, smooth positions are now
calculated on a sphere defined by the vertices and their normals.

This removes visible seams along original edges, which were common previously.

===================================================================

M	source/blender/bmesh/operators/bmo_subdivide.c
M	source/blender/editors/mesh/editmesh_loopcut.c
M	source/blender/editors/mesh/editmesh_tools.c

===================================================================

diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 45e3c8d..a6bdbaa 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -163,6 +163,85 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
 
 	return NULL;
 }
+
+/**
+ * Specialized slerp that uses a sphere defined by each points normal.
+ */
+static void interp_slerp_co_no_v3(
+        const float co_a[3], const float no_a[3],
+        const float co_b[3], const float no_b[3],
+        const float no_dir[3],  /* caller already knows, avoid normalize */
+        float fac,
+        float r_co[3])
+{
+	/* center of the sphere defined by both normals */
+	float center[3];
+
+	BLI_assert(len_squared_v3v3(no_a, no_b) != 0);
+
+	/* calculate sphere 'center' */
+	{
+		/* use point on plane to */
+		float plane_a[4], plane_b[4], plane_c[4];
+		float no_mid[3], no_ortho[3];
+		/* pass this as an arg instead */
+#if 0
+		float no_dir[3];
+#endif
+
+		float v_a_no_ortho[3], v_b_no_ortho[3];
+
+		add_v3_v3v3(no_mid, no_a, no_b);
+		normalize_v3(no_mid);
+
+#if 0
+		sub_v3_v3v3(no_dir, co_a, co_b);
+		normalize_v3(no_dir);
+#endif
+
+		/* axis of slerp */
+		cross_v3_v3v3(no_ortho, no_mid, no_dir);
+		normalize_v3(no_ortho);
+
+		/* creater planes */
+		cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
+		cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
+		project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
+		project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);
+
+		plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
+		plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
+		plane_from_point_normal_v3(plane_c, co_b, no_ortho);
+
+		/* find the sphere center from 3 planes */
+		if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
+			/* pass */
+		}
+		else {
+			mid_v3_v3v3(center, co_a, co_b);
+		}
+	}
+
+	/* calculate the final output 'r_co' */
+	{
+		float ofs_a[3], ofs_b[3], ofs_slerp[3];
+		float dist_a, dist_b;
+
+		sub_v3_v3v3(ofs_a, co_a, center);
+		sub_v3_v3v3(ofs_b, co_b, center);
+
+		dist_a = normalize_v3(ofs_a);
+		dist_b = normalize_v3(ofs_b);
+
+		if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
+			madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
+		}
+		else {
+			interp_v3_v3v3(r_co, co_a, co_b, fac);
+		}
+	}
+}
+
 /* calculates offset for co, based on fractal, sphere or smooth settings  */
 static void alter_co(
         BMVert *v, BMEdge *UNUSED(e_orig),
@@ -179,32 +258,72 @@ static void alter_co(
 		mul_v3_fl(co, params->smooth);
 	}
 	else if (params->use_smooth) {
-		/* we calculate an offset vector vec1[], to be added to *co */
-		float dir[3], tvec[3];
-		float fac, len, val;
+		/* calculating twice and blending gives smoother results,
+		 * removing visible seams. */
+#define USE_SPHERE_DUAL_BLEND
 
-		sub_v3_v3v3(dir, v_a->co, v_b->co);
-		len = (float)M_SQRT1_2 * normalize_v3(dir);
+		const float eps_unit_vec = 1e-5f;
+		float smooth;
+		float no_dir[3];
 
-		/* cosine angle */
-		fac = dot_v3v3(dir, v_a->no);
-		mul_v3_v3fl(tvec, v_a->no, fac);
+#ifdef USE_SPHERE_DUAL_BLEND
+		float no_reflect[3], co_a[3], co_b[3];
+#endif
 
-		/* cosine angle */
-		fac = -dot_v3v3(dir, v_b->no);
-		madd_v3_v3fl(tvec, v_b->no, fac);
+		sub_v3_v3v3(no_dir, v_a->co, v_b->co);
+		normalize_v3(no_dir);
 
-		/* falloff for multi subdivide */
-		val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
-		val = bmesh_subd_falloff_calc(params->smooth_falloff, val);
+#ifndef USE_SPHERE_DUAL_BLEND
+		if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
+			interp_v3_v3v3(co, v_a->co, v_b->co, perc);
+		}
+		else {
+			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
+		}
+#else
+		/* sphere-a */
+		reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
+		if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
+			interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
+		}
+		else {
+			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
+		}
+
+		/* sphere-b */
+		reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
+		if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
+			interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
+		}
+		else {
+			interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
+		}
+
+		/* blend both spheres */
+		interp_v3_v3v3(co, co_a, co_b, perc);
+#endif  /* USE_SPHERE_DUAL_BLEND */
+
+		/* apply falloff */
+		if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
+			smooth = 1.0f;
+		}
+		else {
+			smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
+			smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
+		}
 
 		if (params->use_smooth_even) {
-			val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
+			smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
 		}
 
-		mul_v3_fl(tvec, params->smooth * val * len);
+		smooth *= params->smooth;
+		if (smooth != 1.0f) {
+			float co_flat[3];
+			interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
+			interp_v3_v3v3(co, co_flat, co, smooth);
+		}
 
-		add_v3_v3(co, tvec);
+#undef USE_SPHERE_DUAL_BLEND
 	}
 
 	if (params->use_fractal) {
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index c612ebf..593e27f 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -401,7 +401,7 @@ static void ringsel_finish(bContext *C, wmOperator *op)
 {
 	RingSelOpData *lcd = op->customdata;
 	const int cuts = RNA_int_get(op->ptr, "number_cuts");
-	const float smoothness = 0.292f * RNA_float_get(op->ptr, "smoothness");
+	const float smoothness = RNA_float_get(op->ptr, "smoothness");
 	const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
 #ifdef BMW_EDGERING_NGON
 	const bool use_only_quads = false;
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index d393718..67c23a9 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -85,7 +85,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 	const int cuts = RNA_int_get(op->ptr, "number_cuts");
-	float smooth = 0.292f * RNA_float_get(op->ptr, "smoothness");
+	float smooth = RNA_float_get(op->ptr, "smoothness");
 	const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
 	const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
 
@@ -96,7 +96,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
 	}
 	
 	BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
-	                   smooth, SUBD_FALLOFF_INVSQUARE, false,
+	                   smooth, SUBD_FALLOFF_LIN, false,
 	                   fractal, along_normal,
 	                   cuts,
 	                   SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),




More information about the Bf-blender-cvs mailing list