[Bf-blender-cvs] [f600b4bc676] blender2.8: Shrinkwrap: new mode that projects along the target normal.

Alexander Gavrilov noreply at git.blender.org
Tue Nov 6 19:23:03 CET 2018


Commit: f600b4bc67667b867899cac3725ac7ed44bfbfe3
Author: Alexander Gavrilov
Date:   Tue Nov 6 21:04:53 2018 +0300
Branches: blender2.8
https://developer.blender.org/rBf600b4bc67667b867899cac3725ac7ed44bfbfe3

Shrinkwrap: new mode that projects along the target normal.

The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.

This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.

Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.

Reviewers: mont29

Differential Revision: https://developer.blender.org/D3836

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

M	release/scripts/startup/bl_ui/properties_constraint.py
M	release/scripts/startup/bl_ui/properties_data_modifier.py
M	source/blender/blenkernel/BKE_shrinkwrap.h
M	source/blender/blenkernel/intern/DerivedMesh.c
M	source/blender/blenkernel/intern/constraint.c
M	source/blender/blenkernel/intern/mesh.c
M	source/blender/blenkernel/intern/mesh_runtime.c
M	source/blender/blenkernel/intern/shrinkwrap.c
M	source/blender/blenlib/BLI_math_solvers.h
M	source/blender/blenlib/intern/math_solvers.c
M	source/blender/depsgraph/DEG_depsgraph.h
M	source/blender/depsgraph/intern/builder/deg_builder_relations.cc
M	source/blender/makesdna/DNA_mesh_types.h
M	source/blender/makesdna/DNA_modifier_types.h
M	source/blender/makesrna/intern/rna_constraint.c
M	source/blender/makesrna/intern/rna_modifier.c
M	source/blender/modifiers/intern/MOD_shrinkwrap.c

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

diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index b1c0217f9c9..dcd84d105ad 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -748,7 +748,7 @@ class ConstraintButtonsPanel:
         layout.prop(con, "distance")
         layout.prop(con, "shrinkwrap_type")
 
-        if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE'}:
+        if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
             layout.prop(con, 'wrap_mode', text="Snap Mode")
 
         if con.shrinkwrap_type == 'PROJECT':
@@ -769,7 +769,7 @@ class ConstraintButtonsPanel:
             rowsub.prop(con, "use_invert_cull")
             layout.prop(con, "project_limit")
 
-        if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE'}:
+        if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
             layout.prop(con, "use_track_normal")
 
             row = layout.row(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 2633168e2fa..34f277269fe 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -828,7 +828,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.label(text="Mode:")
         col.prop(md, "wrap_method", text="")
 
-        if md.wrap_method in {'PROJECT', 'NEAREST_SURFACEPOINT'}:
+        if md.wrap_method in {'PROJECT', 'NEAREST_SURFACEPOINT', 'TARGET_PROJECT'}:
             col.prop(md, "wrap_mode", text="")
 
         if md.wrap_method == 'PROJECT':
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index d1a14003b04..04c0f1c5d9a 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -33,6 +33,7 @@
 
 /* Shrinkwrap stuff */
 #include "BKE_bvhutils.h"
+#include "BLI_bitmap.h"
 
 /*
  * Shrinkwrap is composed by a set of functions and options that define the type of shrink.
@@ -55,6 +56,34 @@ struct ShrinkwrapModifierData;
 struct BVHTree;
 struct SpaceTransform;
 
+/* Information about boundary edges in the mesh. */
+typedef struct ShrinkwrapBoundaryVertData {
+	/* Average direction of edges that meet here. */
+	float direction[3];
+
+	/* Closest vector to direction that is orthogonal to vertex normal. */
+	float normal_plane[3];
+} ShrinkwrapBoundaryVertData;
+
+typedef struct ShrinkwrapBoundaryData {
+	/* True if the edge belongs to exactly one face. */
+	const BLI_bitmap *edge_is_boundary;
+	/* True if the looptri has any boundary edges. */
+	const BLI_bitmap *looptri_has_boundary;
+
+	/* Mapping from vertex index to boundary vertex index, or -1.
+	 * Used for compact storage of data about boundary vertices. */
+	const int *vert_boundary_id;
+	unsigned int num_boundary_verts;
+
+	/* Direction data about boundary vertices. */
+	const ShrinkwrapBoundaryVertData *boundary_verts;
+} ShrinkwrapBoundaryData;
+
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
+void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
+
+/* Information about a mesh and BVH tree. */
 typedef struct ShrinkwrapTreeData {
 	Mesh *mesh;
 
@@ -62,6 +91,7 @@ typedef struct ShrinkwrapTreeData {
 	BVHTreeFromMesh treeData;
 
 	float (*clnors)[3];
+	ShrinkwrapBoundaryData *boundary;
 } ShrinkwrapTreeData;
 
 /* Checks if the modifier needs target normals with these settings. */
@@ -91,6 +121,10 @@ bool BKE_shrinkwrap_project_normal(
         char options, const float vert[3], const float dir[3], const float ray_radius,
         const struct SpaceTransform *transf, struct ShrinkwrapTreeData *tree, BVHTreeRayHit *hit);
 
+/* Maps the point to the nearest surface, either by simple nearest, or by target normal projection. */
+void BKE_shrinkwrap_find_nearest_surface(
+        struct ShrinkwrapTreeData *tree, struct BVHTreeNearest *nearest, float co[3], int type);
+
 /* Computes a smooth normal of the target (if applicable) at the hit location. */
 void BKE_shrinkwrap_compute_smooth_normal(
         const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index c84bd378b04..1d787388774 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -75,6 +75,7 @@
 
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_query.h"
+#include "BKE_shrinkwrap.h"
 
 #ifdef WITH_OPENSUBDIV
 #  include "DNA_userdef_types.h"
@@ -1980,6 +1981,15 @@ static void mesh_finalize_eval(Object *object)
 	}
 }
 
+static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob)
+{
+	uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
+
+	if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
+		BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval);
+	}
+}
+
 static void mesh_build_data(
         struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask,
         const bool build_shapekey_layers, const bool need_mapping)
@@ -2016,6 +2026,8 @@ static void mesh_build_data(
 	}
 
 	BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS));
+
+	mesh_build_extra_data(depsgraph, ob);
 }
 
 static void editbmesh_build_data(
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 41b07d73dc9..cc94e87c747 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -3636,6 +3636,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstrai
 			switch (scon->shrinkType) {
 				case MOD_SHRINKWRAP_NEAREST_SURFACE:
 				case MOD_SHRINKWRAP_NEAREST_VERTEX:
+				case MOD_SHRINKWRAP_TARGET_PROJECT:
 				{
 					BVHTreeNearest nearest;
 
@@ -3644,15 +3645,14 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstrai
 
 					BLI_space_transform_apply(&transform, co);
 
-					BVHTreeFromMesh *treeData = &tree.treeData;
-					BLI_bvhtree_find_nearest(treeData->tree, co, &nearest, treeData->nearest_callback, treeData);
+					BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType);
 
 					if (nearest.index < 0) {
 						fail = true;
 						break;
 					}
 
-					if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) {
+					if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
 						if (do_track_normal) {
 							track_normal = true;
 							BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no);
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index ed01889d200..6a00aaf576b 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -563,6 +563,7 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
 	me_dst->runtime.batch_cache = NULL;
 	me_dst->runtime.looptris.array = NULL;
 	me_dst->runtime.bvh_cache = NULL;
+	me_dst->runtime.shrinkwrap_data = NULL;
 
 	if (me_src->id.tag & LIB_TAG_NO_MAIN) {
 		me_dst->runtime.deformed_only = me_src->runtime.deformed_only;
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 68880cacfb9..0931318f17a 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -44,6 +44,7 @@
 #include "BKE_mesh.h"
 #include "BKE_mesh_runtime.h"
 #include "BKE_subdiv_ccg.h"
+#include "BKE_shrinkwrap.h"
 
 /* -------------------------------------------------------------------- */
 /** \name Mesh Runtime Struct Utils
@@ -202,6 +203,7 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
 		BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
 		mesh->runtime.subdiv_ccg = NULL;
 	}
+	BKE_shrinkwrap_discard_boundary_data(mesh);
 }
 
 /** \} */
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 6942c8f1da3..78045e5fd56 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -45,6 +45,7 @@
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 #include "BLI_task.h"
+#include "BLI_math_solvers.h"
 
 #include "BKE_shrinkwrap.h"
 #include "BKE_cdderivedmesh.h"
@@ -57,6 +58,9 @@
 #include "BKE_editmesh.h"
 #include "BKE_mesh.h"  /* for OMP limits. */
 #include "BKE_subsurf.h"
+#include "BKE_mesh_runtime.h"
+
+#include "MEM_guardedalloc.h"
 
 #include "BLI_strict_flags.h"
 
@@ -70,7 +74,6 @@
 /* Util macros */
 #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
 
-
 typedef struct ShrinkwrapCalcData {
 	ShrinkwrapModifierData *smd;    //shrinkwrap modifier data
 
@@ -106,7 +109,8 @@ typedef struct ShrinkwrapCalcCBData {
 /* Checks if the modifier needs target normals with these settings. */
 bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
 {
-	return shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE;
+	return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
+	       (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
 }
 
 /* Initializes the mesh data structure from the given mesh and settings. */
@@ -142,6 +146,10 @@ bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkTy
 			}
 		}
 
+		if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+			data->boundary = mesh->runtime.shrinkwrap_data;
+		}
+
 		return true;
 	}
 }
@@ -152,6 +160,176 @@ void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
 	free_bvhtree_from_mesh(&data->treeData);
 }
 
+/* Free boundary data for target project */
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
+{
+	struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+
+	if (data != NULL) {
+		MEM_freeN((void*)data->edge_is_boundary);
+		MEM_freeN((void*)data->looptri_has_boundary);
+		MEM_freeN((void*)data->vert

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list