[Bf-blender-cvs] [fff9ba9b955] hair_guides_grooming: Implement guide curve generation for groom bundles.

Lukas Tönne noreply at git.blender.org
Sat May 26 14:06:59 CEST 2018


Commit: fff9ba9b955452870c7b7b8f0796666e40c29e83
Author: Lukas Tönne
Date:   Sat May 26 13:06:29 2018 +0100
Branches: hair_guides_grooming
https://developer.blender.org/rBfff9ba9b955452870c7b7b8f0796666e40c29e83

Implement guide curve generation for groom bundles.

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

M	release/scripts/startup/bl_ui/properties_data_groom.py
M	source/blender/blenkernel/BKE_groom.h
M	source/blender/blenkernel/intern/groom.c
M	source/blender/blenkernel/intern/hair.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/blenloader/intern/writefile.c
M	source/blender/editors/groom/editgroom.c
M	source/blender/editors/groom/groom_hair.c
M	source/blender/makesdna/DNA_groom_types.h
M	source/blender/makesrna/intern/rna_groom.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_groom.py b/release/scripts/startup/bl_ui/properties_data_groom.py
index a7a43742217..ccb9b51497f 100644
--- a/release/scripts/startup/bl_ui/properties_data_groom.py
+++ b/release/scripts/startup/bl_ui/properties_data_groom.py
@@ -76,10 +76,17 @@ class DATA_PT_groom(DataButtonsPanel, Panel):
         layout = self.layout
 
         groom = context.groom
+        bundle = context.groom.bundles.active
 
         layout.template_list("GROOM_UL_bundles", "bundles",
                              groom, "bundles",
                              groom.bundles, "active_index")
+        if bundle:
+            col = layout.column()
+            col.label("Region:")
+            col.prop(bundle, "guides_count")
+
+            layout.separator()
 
         split = layout.split()
 
diff --git a/source/blender/blenkernel/BKE_groom.h b/source/blender/blenkernel/BKE_groom.h
index 49afef10786..a86d458e60b 100644
--- a/source/blender/blenkernel/BKE_groom.h
+++ b/source/blender/blenkernel/BKE_groom.h
@@ -72,8 +72,8 @@ void BKE_groom_bundle_unbind(struct GroomBundle *bundle);
 
 /* === Hair System === */
 
-/* Create follicles and guide curve origins on the scalp surface for hair fiber rendering */
-void BKE_groom_hair_distribute(struct Groom *groom, unsigned int seed, int hair_count, int guide_curve_count);
+/* Create follicles on the scalp surface for hair fiber rendering */
+void BKE_groom_hair_distribute(struct Groom *groom, unsigned int seed, int hair_count);
 
 /* Calculate guide curve shapes based on groom bundle deformation */
 void BKE_groom_hair_update_guide_curves(struct Groom *groom);
diff --git a/source/blender/blenkernel/intern/groom.c b/source/blender/blenkernel/intern/groom.c
index 10344564544..63ba4a2a9f6 100644
--- a/source/blender/blenkernel/intern/groom.c
+++ b/source/blender/blenkernel/intern/groom.c
@@ -117,6 +117,14 @@ static void groom_bundles_free(ListBase *bundles)
 		{
 			MEM_freeN(bundle->scalp_region);
 		}
+		if (bundle->guides)
+		{
+			MEM_freeN(bundle->guides);
+		}
+		if (bundle->guide_shape_weights)
+		{
+			MEM_freeN(bundle->guide_shape_weights);
+		}
 	}
 	BLI_freelistN(bundles);
 }
@@ -183,6 +191,14 @@ void BKE_groom_copy_data(Main *UNUSED(bmain), Groom *groom_dst, const Groom *gro
 		{
 			bundle->scalp_region = MEM_dupallocN(bundle->scalp_region);
 		}
+		if (bundle->guides)
+		{
+			bundle->guides = MEM_dupallocN(bundle->guides);
+		}
+		if (bundle->guide_shape_weights)
+		{
+			bundle->guide_shape_weights = MEM_dupallocN(bundle->guide_shape_weights);
+		}
 	}
 	
 	groom_dst->editgroom = NULL;
@@ -496,70 +512,7 @@ void BKE_groom_bundle_unbind(GroomBundle *bundle)
 
 /* === Hair System === */
 
-/* Distribute points on the scalp to use as guide curve origins,
- * then interpolate guide curves from bundles
- */
-static void groom_generate_guide_curves(
-        Groom *groom,
-        Mesh *scalp,
-        unsigned int seed,
-        int guide_curve_count,
-        const float *loop_weights)
-{
-	struct HairSystem *hsys = groom->hair_system;
-
-	MeshSample *guide_samples = MEM_mallocN(sizeof(*guide_samples) * guide_curve_count, "guide samples");
-	int num_guides;
-	{
-		/* Random distribution of points on the scalp mesh */
-		
-		float scalp_area = BKE_hair_calc_surface_area(scalp);
-		float density = BKE_hair_calc_density_from_count(scalp_area, guide_curve_count);
-		float min_distance = BKE_hair_calc_min_distance_from_density(density);
-		MeshSampleGenerator *gen = BKE_mesh_sample_gen_surface_poissondisk(
-		            seed,
-		            min_distance,
-		            guide_curve_count,
-		            loop_weights);
-		
-		BKE_mesh_sample_generator_bind(gen, scalp);
-		
-		static const bool use_threads = false;
-		num_guides = BKE_mesh_sample_generate_batch_ex(
-		                 gen,
-		                 guide_samples,
-		                 sizeof(MeshSample),
-		                 guide_curve_count,
-		                 use_threads);
-		
-		BKE_mesh_sample_free_generator(gen);
-	}
-	
-	const int numverts = 20;
-	BKE_hair_guide_curves_begin(hsys, num_guides);
-	for (int i = 0; i < num_guides; ++i)
-	{
-		BKE_hair_set_guide_curve(hsys, i, &guide_samples[i], numverts);
-	}
-	BKE_hair_guide_curves_end(hsys);
-
-	{
-		int idx = 0;
-		for (int i = 0; i < num_guides; ++i)
-		{
-			for (int j = 0; j < numverts; ++j)
-			{
-				float co[3];
-				zero_v3(co);
-				BKE_hair_set_guide_vertex(hsys, idx, 0, co);
-				++idx;
-			}
-		}
-	}
-	
-	MEM_freeN(guide_samples);
-}
-
+/* Set loop weights for all faces covered by the bundle region */
 static bool groom_add_bundle_loop_weights(const Groom *groom, const GroomBundle *bundle,
                                           float *loop_weights)
 {
@@ -601,6 +554,7 @@ static bool groom_add_bundle_loop_weights(const Groom *groom, const GroomBundle
 	return true;
 }
 
+/* Set loop weights for all faces covered */
 static void groom_add_all_loop_weights(const Groom *groom,
                                        float *loop_weights)
 {
@@ -610,30 +564,165 @@ static void groom_add_all_loop_weights(const Groom *groom,
 	}
 }
 
-void BKE_groom_hair_distribute(Groom *groom, unsigned int seed, int hair_count, int guide_curve_count)
+/* Distribute points on the scalp to use as guide curve origins */
+static void groom_generate_guides(
+        Groom *groom,
+        Mesh *scalp,
+        unsigned int seed)
+{
+	const size_t loop_weights_size = sizeof(float) * scalp->totloop;
+	float *loop_weights = MEM_mallocN(loop_weights_size, "groom scalp loop weights");
+	
+	int i = 0;
+	GroomBundle *bundle = groom->bundles.first;
+	for (; bundle; bundle = bundle->next, ++i)
+	{
+		bundle->guides = MEM_reallocN_id(bundle->guides, sizeof(GroomHairGuide) * bundle->guides_count, "groom bundle hair guides");
+		
+		/* Mask for the scalp region */
+		memset(loop_weights, 0, loop_weights_size);
+		groom_add_bundle_loop_weights(groom, bundle, loop_weights);
+		
+		{
+			const int count = bundle->guides_count;
+			unsigned int region_seed = BLI_ghashutil_combine_hash(seed, BLI_ghashutil_uinthash(i));
+			float scalp_area = BKE_hair_calc_surface_area(scalp);
+			float density = BKE_hair_calc_density_from_count(scalp_area, count);
+			float min_distance = BKE_hair_calc_min_distance_from_density(density);
+			MeshSampleGenerator *gen = BKE_mesh_sample_gen_surface_poissondisk(
+			                               region_seed,
+			                               min_distance,
+			                               count,
+			                               loop_weights);
+			
+			BKE_mesh_sample_generator_bind(gen, scalp);
+			
+			static const bool use_threads = false;
+			bundle->totguides = BKE_mesh_sample_generate_batch_ex(
+			                        gen,
+			                        &bundle->guides->root,
+			                        sizeof(GroomHairGuide),
+			                        count,
+			                        use_threads);
+			
+			BKE_mesh_sample_free_generator(gen);
+		}
+		
+		/* Calculate weights for interpolating the guide between shape vertices */
+		{
+			bundle->guide_shape_weights = MEM_reallocN_id(bundle->guide_shape_weights, sizeof(float) * bundle->totguides * bundle->numshapeverts, "groom guide shape weights");
+			
+			/* Use first section as shape for computing weights */
+			const int shapesize = bundle->numshapeverts;
+			float (*shape)[2] = MEM_mallocN(sizeof(float) * 2 * shapesize, "bundle shape verts");
+			/* Expecting at least one section */
+			BLI_assert(bundle->totsections >= 1 && bundle->totverts >= shapesize);
+			/* Need a dense array for the interp_weights_poly_v2 function */
+			for (int j = 0; j < shapesize; ++j)
+			{
+				copy_v2_v2(shape[j], bundle->verts[j].co);
+			}
+			
+			float *w = bundle->guide_shape_weights;
+			for (int j = 0; j < bundle->totguides; ++j)
+			{
+				/* Define interpolation point by projecting the guide root
+				 * onto the bundle base plane.
+				 */
+				float p[3], n[3], t[3];
+				BKE_mesh_sample_eval(scalp, &bundle->guides[j].root, p, n, t);
+				sub_v3_v3(p, bundle->sections[0].center);
+				mul_transposed_m3_v3(bundle->sections[0].mat, p);
+				
+				/* Calculate interpolation weights */
+				interp_weights_poly_v2(w, shape, shapesize, p);
+				
+				w += bundle->numshapeverts;
+			}
+			
+			MEM_freeN(shape);
+		}
+	}
+	
+	MEM_freeN(loop_weights);
+}
+
+void BKE_groom_hair_distribute(Groom *groom, unsigned int seed, int hair_count)
 {
 	struct HairSystem *hsys = groom->hair_system;
 	
 	BLI_assert(groom->scalp_object && groom->scalp_object->type == OB_MESH);
 	Mesh *scalp = groom->scalp_object->data;
 	
-	/* Per-loop weights for limiting follicles to covered faces */
-	float *loop_weights = MEM_callocN(sizeof(float) * scalp->totloop, "groom scalp loop weights");
-	groom_add_all_loop_weights(groom, loop_weights);
-	
-	BKE_hair_generate_follicles_ex(hsys, scalp, seed, hair_count, loop_weights);
-	
-	unsigned int guide_seed = BLI_ghashutil_combine_hash(seed, BLI_ghashutil_strhash("groom guide curves"));
-	groom_generate_guide_curves(groom, scalp, guide_seed, guide_curve_count, loop_weights);
-	
-	MEM_freeN(loop_weights);
+	{
+		/* Per-loop weights for limiting follicles to covered faces */
+		float *loop_weights = MEM_callocN(sizeof(float) * scalp->totloop, "groom scalp loop weights");
+		groom_add_all_loop_weights(groom, loop_weights);
+		
+		unsigned int hair_seed = BLI_ghashutil_combine_hash(seed, BLI_ghashutil_strhash("groom hair follicles"));
+		BKE_hair_generate_follicles_ex(hsys, scalp, hair_seed, hair_count, loop_weights);
+		
+		MEM_freeN(loop_weights);
+	}
 	
-	BKE_hair_bind_follicles(hsys, scalp);
+	{
+		unsigned int guides_seed = BLI_ghashutil_combine_hash(seed, BLI_ghashutil_strhash("groom guide curves"));
+		groom_generate_guides(groom, scalp, guides_seed);
+	}
 }
 
 void BKE_groom_hair_update_guide_curves(Groom *groom)
 {
-	UNUSED_VARS(groom);
+	struct HairSystem *hsys = groom->hair_system;
+	
+	/* Count guides for all regions combined */
+	int totguides = 0;
+	for (const GroomBundle *bundle = groom->bundles.first; bundle; bundle = bundle->next)
+	{
+		totguides += bundle->totguides;
+	}
+	
+	/* First declare all guide curves and lengths */
+	BKE_hair_guide_curves_begin(hsys, totguides);


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list