[Bf-blender-cvs] [9b4912b] alembic: New shrinkwrap modifier for cached hair data.

Lukas Tönne noreply at git.blender.org
Wed Apr 29 14:16:32 CEST 2015


Commit: 9b4912ba9eac21db6e3c91b567ac2127829342d9
Author: Lukas Tönne
Date:   Wed Apr 29 14:12:41 2015 +0200
Branches: alembic
https://developer.blender.org/rB9b4912ba9eac21db6e3c91b567ac2127829342d9

New shrinkwrap modifier for cached hair data.

This is experimental. It might work for simple collision-like features,
by keeping goal positions for hair above the mesh surface. However, the
nature of nearest-point lookup on meshes means that the goal position
can flip to the other side of a mesh rapidly, which would lead to
strong forces and unstable behavior.

This code should be seen as an experiment.

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

M	release/scripts/startup/bl_ui/properties_object.py
M	source/blender/blenkernel/BKE_cache_library.h
M	source/blender/blenkernel/intern/cache_library.c
M	source/blender/makesdna/DNA_cache_library_types.h
M	source/blender/makesrna/intern/rna_cache_library.c

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

diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index c3d25f7..64c5c08 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -457,7 +457,7 @@ class OBJECT_PT_cache_library(ObjectButtonsPanel, Panel):
     def HAIR_SIMULATION(self, context, layout, cachelib, md):
         params = md.parameters
 
-        col = layout.column()
+        col = layout.column(align=True)
         col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
         sub = col.column()
         if (md.object):
@@ -507,6 +507,21 @@ class OBJECT_PT_cache_library(ObjectButtonsPanel, Panel):
         
         layout.prop(md, "use_double_sided")
 
+    def SHRINK_WRAP(self, context, layout, cachelib, md):
+        col = layout.column(align=True)
+        col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+        sub = col.column()
+        if (md.object):
+            sub.prop_search(md, "hair_system", md.object, "particle_systems")
+        else:
+            sub.enabled = False
+            sub.prop(md, "hair_system")
+
+        layout.prop_search(md, "target", context.blend_data, "objects", icon='OBJECT_DATA')
+
+        layout = layout.column()
+        layout.active = md.hair_system is not None
+
 
 
 # Simple human-readable size (based on http://stackoverflow.com/a/1094933)
diff --git a/source/blender/blenkernel/BKE_cache_library.h b/source/blender/blenkernel/BKE_cache_library.h
index eb334f3..bc48b60 100644
--- a/source/blender/blenkernel/BKE_cache_library.h
+++ b/source/blender/blenkernel/BKE_cache_library.h
@@ -49,6 +49,7 @@ struct CacheModifier;
 struct ID;
 struct CacheProcessData;
 struct BVHTreeFromMesh;
+struct Strands;
 
 struct ClothModifierData;
 
@@ -170,6 +171,9 @@ struct CacheModifier *BKE_cache_modifier_copy(struct CacheLibrary *cachelib, str
 
 void BKE_cache_modifier_foreachIDLink(struct CacheLibrary *cachelib, struct CacheModifier *md, CacheModifier_IDWalkFunc walk, void *userdata);
 
+bool BKE_cache_modifier_find_object(struct DupliCache *dupcache, struct Object *ob, struct DupliObjectData **r_data);
+bool BKE_cache_modifier_find_strands(struct DupliCache *dupcache, struct Object *ob, int hair_system, struct DupliObjectData **r_data, struct Strands **r_strands);
+
 /* ========================================================================= */
 
 typedef struct CacheEffectorInstance {
diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c
index b3530ce..fd21635 100644
--- a/source/blender/blenkernel/intern/cache_library.c
+++ b/source/blender/blenkernel/intern/cache_library.c
@@ -825,7 +825,53 @@ int BKE_cache_effectors_eval(CacheEffector *effectors, int tot, CacheEffectorPoi
 	return applied;
 }
 
-/* ------------------------------------------------------------------------- */
+/* ========================================================================= */
+
+bool BKE_cache_modifier_find_object(DupliCache *dupcache, Object *ob, DupliObjectData **r_data)
+{
+	DupliObjectData *dobdata;
+	
+	if (!ob)
+		return false;
+	dobdata = BKE_dupli_cache_find_data(dupcache, ob);
+	if (!dobdata)
+		return false;
+	
+	if (r_data) *r_data = dobdata;
+	return true;
+}
+
+bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_system, DupliObjectData **r_data, Strands **r_strands)
+{
+	DupliObjectData *dobdata;
+	ParticleSystem *psys;
+	DupliObjectDataStrands *link;
+	Strands *strands;
+	
+	if (!ob)
+		return false;
+	dobdata = BKE_dupli_cache_find_data(dupcache, ob);
+	if (!dobdata)
+		return false;
+	
+	psys = BLI_findlink(&ob->particlesystem, hair_system);
+	if (!psys || !psys->part->type == PART_HAIR)
+		return false;
+	
+	strands = NULL;
+	for (link = dobdata->strands.first; link; link = link->next) {
+		if (link->strands && STREQ(link->name, psys->name)) {
+			strands = link->strands;
+			break;
+		}
+	}
+	if (!strands)
+		return false;
+	
+	if (r_data) *r_data = dobdata;
+	if (r_strands) *r_strands = strands;
+	return true;
+}
 
 static void hairsim_params_init(HairSimParams *params)
 {
@@ -882,43 +928,11 @@ static void hairsim_foreach_id_link(HairSimCacheModifier *hsmd, CacheLibrary *ca
 	walk(userdata, cachelib, &hsmd->modifier, (ID **)(&hsmd->object));
 }
 
-static bool hairsim_find_data(HairSimCacheModifier *hsmd, DupliCache *dupcache, Object **r_ob, Strands **r_strands)
-{
-	DupliObjectData *dobdata;
-	ParticleSystem *psys;
-	DupliObjectDataStrands *link;
-	Strands *strands;
-	
-	if (!hsmd->object)
-		return false;
-	dobdata = BKE_dupli_cache_find_data(dupcache, hsmd->object);
-	if (!dobdata)
-		return false;
-	
-	psys = BLI_findlink(&hsmd->object->particlesystem, hsmd->hair_system);
-	if (!psys || !psys->part->type == PART_HAIR)
-		return false;
-	
-	strands = NULL;
-	for (link = dobdata->strands.first; link; link = link->next) {
-		if (link->strands && STREQ(link->name, psys->name)) {
-			strands = link->strands;
-			break;
-		}
-	}
-	if (!strands)
-		return false;
-	
-	*r_ob = hsmd->object;
-	*r_strands = strands;
-	return true;
-}
-
 static void hairsim_process(HairSimCacheModifier *hsmd, CacheProcessContext *ctx, CacheProcessData *data, int frame, int frame_prev, eCacheLibrary_EvalMode UNUSED(eval_mode))
 {
 #define MAX_CACHE_EFFECTORS 64
 	
-	Object *ob;
+	Object *ob = hsmd->object;
 	Strands *strands;
 	float mat[4][4];
 	ListBase *effectors;
@@ -934,7 +948,7 @@ static void hairsim_process(HairSimCacheModifier *hsmd, CacheProcessContext *ctx
 	if (frame <= frame_prev)
 		return;
 	
-	if (!hairsim_find_data(hsmd, data->dupcache, &ob, &strands))
+	if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hsmd->hair_system, NULL, &strands))
 		return;
 	
 	if (hsmd->sim_params.flag & eHairSimParams_Flag_UseGoalStiffnessCurve)
@@ -971,6 +985,8 @@ CacheModifierTypeInfo cacheModifierType_HairSimulation = {
     /* free */              (CacheModifier_FreeFunc)hairsim_free,
 };
 
+/* ------------------------------------------------------------------------- */
+
 static void forcefield_init(ForceFieldCacheModifier *ffmd)
 {
 	ffmd->object = NULL;
@@ -1006,10 +1022,202 @@ CacheModifierTypeInfo cacheModifierType_ForceField = {
     /* free */              (CacheModifier_FreeFunc)forcefield_free,
 };
 
+/* ------------------------------------------------------------------------- */
+
+static void shrinkwrap_init(ShrinkWrapCacheModifier *smd)
+{
+	smd->object = NULL;
+	smd->hair_system = -1;
+}
+
+static void shrinkwrap_copy(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheModifier *UNUSED(tsmd))
+{
+}
+
+static void shrinkwrap_free(ShrinkWrapCacheModifier *UNUSED(smd))
+{
+}
+
+static void shrinkwrap_foreach_id_link(ShrinkWrapCacheModifier *smd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+	walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->object));
+	walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->target));
+}
+
+typedef struct ShrinkWrapCacheData {
+	DerivedMesh *dm;
+	BVHTreeFromMesh treedata;
+	
+	ListBase instances;
+} ShrinkWrapCacheData;
+
+typedef struct ShrinkWrapCacheInstance {
+	struct ShrinkWrapCacheInstance *next, *prev;
+	
+	float mat[4][4];
+	float imat[4][4];
+} ShrinkWrapCacheInstance;
+
+static void shrinkwrap_data_get_bvhtree(ShrinkWrapCacheData *data, DerivedMesh *dm, bool create_bvhtree)
+{
+	data->dm = CDDM_copy(dm);
+	if (!data->dm)
+		return;
+	
+	DM_ensure_tessface(data->dm);
+	CDDM_calc_normals(data->dm);
+	
+	if (create_bvhtree) {
+		bvhtree_from_mesh_faces(&data->treedata, data->dm, 0.0, 2, 6);
+	}
+}
+
+static void shrinkwrap_data_get_instances(ShrinkWrapCacheData *data, Object *ob, float obmat[4][4], ListBase *duplilist)
+{
+	DupliObject *dob;
+	
+	for (dob = duplilist->first; dob; dob = dob->next) {
+		ShrinkWrapCacheInstance *inst;
+		
+		if (dob->ob != ob)
+			continue;
+		
+		inst = MEM_callocN(sizeof(ShrinkWrapCacheInstance), "shrink wrap instance");
+		mul_m4_m4m4(inst->mat, obmat, dob->mat);
+		invert_m4_m4(inst->imat, inst->mat);
+		
+		BLI_addtail(&data->instances, inst);
+	}
+}
+
+static void shrinkwrap_data_free(ShrinkWrapCacheData *data)
+{
+	BLI_freelistN(&data->instances);
+	
+	free_bvhtree_from_mesh(&data->treedata);
+	
+	if (data->dm) {
+		data->dm->release(data->dm);
+	}
+}
+
+static void shrinkwrap_apply_vertex(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *data, ShrinkWrapCacheInstance *inst, StrandsVertex *vertex, StrandsMotionState *UNUSED(state))
+{
+//	const float *point = state->co;
+//	float *npoint = state->co;
+	const float *point = vertex->co;
+	float *npoint = vertex->co;
+	
+	BVHTreeNearest nearest = {0, };
+	float co[3];
+	
+	if (!data->treedata.tree)
+		return;
+	
+	nearest.index = -1;
+	nearest.dist_sq = FLT_MAX;
+	
+	/* lookup in target space */
+	mul_v3_m4v3(co, inst->imat, point);
+	
+	BLI_bvhtree_find_nearest(data->treedata.tree, co, &nearest, data->treedata.nearest_callback, &data->treedata);
+	if (nearest.index < 0)
+		return;
+	
+	/* convert back to world space */
+	mul_m4_v3(inst->mat, nearest.co);
+	mul_mat3_m4_v3(inst->mat, nearest.no);
+	
+	{
+		float vec[3];
+		
+		sub_v3_v3v3(vec, point, nearest.co);
+		
+		/* project along the distance vector */
+		if (dot_v3v3(vec, nearest.no) < 0.0f) {
+			sub_v3_v3v3(npoint, point, vec);
+		}
+	}
+}
+
+static void shrinkwrap_apply(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *data, Strands *strands)
+{
+	StrandIterator it_strand;
+	for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+		StrandVertexIterator it_vert;
+		for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+			ShrinkWrapCacheInstance *inst;
+			
+			/* XXX this is not great, the result depends on order of instances in the duplilist ...
+			 * but good enough for single instance use case.
+			 */
+			for (inst = data->instances.first; inst; inst = inst->next) {
+				shrinkwrap_apply_vertex(smd, data, inst, it_vert.vertex, it_vert.state);
+			}
+		}
+	}
+}
+
+static void shrinkwrap_process(ShrinkWrapCacheModifier *s

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list