[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