[Bf-blender-cvs] [bd2bc66158b] hair_guides_grooming: Guide curve construction function using consistent distance between vertices.

Lukas Tönne noreply at git.blender.org
Tue Jun 26 22:08:05 CEST 2018


Commit: bd2bc66158b842c73d9ec90f809a63ccec77ce3d
Author: Lukas Tönne
Date:   Tue Jun 26 19:04:24 2018 +0100
Branches: hair_guides_grooming
https://developer.blender.org/rBbd2bc66158b842c73d9ec90f809a63ccec77ce3d

Guide curve construction function using consistent distance between vertices.

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

M	source/blender/blenkernel/BKE_groom.h
M	source/blender/blenkernel/intern/groom.c

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

diff --git a/source/blender/blenkernel/BKE_groom.h b/source/blender/blenkernel/BKE_groom.h
index fc45cdb23d0..fb6727d4cfa 100644
--- a/source/blender/blenkernel/BKE_groom.h
+++ b/source/blender/blenkernel/BKE_groom.h
@@ -42,6 +42,9 @@ struct Mesh;
 struct Object;
 struct Scene;
 
+
+/* === Groom Datablock === */
+
 void BKE_groom_init(struct Groom *groom);
 void *BKE_groom_add(struct Main *bmain, const char *name);
 
diff --git a/source/blender/blenkernel/intern/groom.c b/source/blender/blenkernel/intern/groom.c
index 704f2b25ad9..9fc302c69f6 100644
--- a/source/blender/blenkernel/intern/groom.c
+++ b/source/blender/blenkernel/intern/groom.c
@@ -68,6 +68,134 @@
 
 #include "bmesh.h"
 
+#include "PIL_time_utildefines.h"
+
+
+/* === Utility Spline Functions === */
+
+/* Calculate forward differencing increments for a cubic polynomial,
+ * based on input points a..d
+ */
+BLI_INLINE void groom_forward_diff_init(
+        const float a[3],
+        const float b[3],
+        const float c[3],
+        const float d[3],
+        double stepsize,
+        double r_q[4][3])
+{
+	double f = stepsize;
+	double ff = f * f;
+	double fff = f * ff;
+	
+	for (int k = 0; k < 3; ++k)
+	{
+		double na = (double)a[k] * fff;
+		double nb = (double)b[k] * ff;
+		double nc = (double)c[k] * f;
+		double nd = (double)d[k];
+		
+		r_q[0][k] = nd;
+		r_q[1][k] = na + nb + nc;
+		r_q[2][k] = 6 * na + 2 * nb;
+		r_q[3][k] = 6 * na;
+	}
+}
+
+/* Calculate forward differencing increments for a hermite spline,
+ * define tangents from segment direction.
+ * co0 and co3 may be NULL.
+ */
+BLI_INLINE void groom_forward_diff_init_hermite(
+        const float *co0,
+        const float *co1,
+        const float *co2,
+        const float *co3,
+        double stepsize,
+        double r_q[4][3])
+{
+	float a[3], b[3], c[3], d[3];
+	/* define tangents from segment direction */
+	float n1[3], n2[3];
+	
+	if (co0)
+	{
+		sub_v3_v3v3(n1, co2, co0);
+		mul_v3_fl(n1, 0.5f);
+	}
+	else
+	{
+		sub_v3_v3v3(n1, co2, co1);
+	}
+	
+	if (co3)
+	{
+		sub_v3_v3v3(n2, co3, co1);
+		mul_v3_fl(n2, 0.5f);
+	}
+	else
+	{
+		sub_v3_v3v3(n2, co2, co1);
+	}
+	
+	/* Hermite spline interpolation */
+	/* a = 2.0f * (co1 - co2) + n1 + n2 */
+	sub_v3_v3v3(a, co1, co2);
+	mul_v3_fl(a, 2.0f);
+	add_v3_v3(a, n1);
+	add_v3_v3(a, n2);
+	
+	/* b = 3.0f * (co2 - co1) - 2.0f * n1 - n2 */
+	sub_v3_v3v3(b, co2, co1);
+	mul_v3_fl(b, 3.0f);
+	madd_v3_v3fl(b, n1, -2.0f);
+	sub_v3_v3(b, n2);
+	
+	/* c = n1 */
+	copy_v3_v3(c, n1);
+	
+	/* d = co1 */
+	copy_v3_v3(d, co1);
+	
+	return groom_forward_diff_init(a, b, c, d, stepsize, r_q);
+}
+
+/* Calculate next cubic polynomial point using forward differencing */
+BLI_INLINE void groom_forward_diff_step(double q[4][3])
+{
+	for (int k = 0; k < 3; ++k)
+	{
+		q[0][k] += q[1][k];
+		q[1][k] += q[2][k];
+		q[2][k] += q[3][k];
+	}
+}
+
+/* Get the current point */
+BLI_INLINE void groom_forward_diff_get_point(const double q[4][3], float r_p[3])
+{
+	r_p[0] = (float)q[0][0];
+	r_p[1] = (float)q[0][1];
+	r_p[2] = (float)q[0][2];
+}
+
+/* Calculate full array of cubic polynomial points using forward differencing */
+static void groom_forward_diff_array(
+        double q[4][3],
+        float (*p)[3],
+        int it,
+        int stride)
+{
+	for (int i = 0; i <= it; i++) {
+		groom_forward_diff_get_point(q, *p);
+		
+		p = POINTER_OFFSET(p, stride);
+		groom_forward_diff_step(q);
+	}
+}
+
+
+/* === Groom Datablock === */
 
 void BKE_groom_init(Groom *groom)
 {
@@ -860,6 +988,28 @@ void BKE_groom_hair_distribute(const Depsgraph *depsgraph, Groom *groom, unsigne
 	}
 }
 
+static void groom_eval_shape_vertex(const GroomRegion *region, const Mesh *scalp, int vertex_idx, int section_idx, float r_co[3])
+{
+	if (section_idx == 0 && scalp && region->scalp_samples != NULL)
+	{
+		/* For bound regions use location on the scalp */
+		const MeshSample *bound_loc = &region->scalp_samples[vertex_idx];
+		float nor[3], tang[3];
+		BKE_mesh_sample_eval(scalp, bound_loc, r_co, nor, tang);
+	}
+	else
+	{
+		const GroomBundle *bundle = &region->bundle;
+		const GroomSection *section = &bundle->sections[section_idx];
+		const GroomSectionVertex *vertex = &bundle->verts[vertex_idx + section_idx * region->numverts];
+		
+		float tmp[3] = {0.0f, 0.0f, 0.0f};
+		copy_v2_v2(tmp, vertex->co);
+		mul_v3_m3v3(r_co, section->mat, tmp);
+		add_v3_v3(r_co, section->center);
+	}
+}
+
 typedef struct GroomGuideVertex
 {
 	int flag;
@@ -889,43 +1039,124 @@ static void groom_guide_buffer_reserve(int reserve, GroomGuideVertex **r_verts,
  */
 static void groom_guide_curve_discretize(
         const GroomRegion *region,
+        const Mesh *scalp,
         int guide_idx,
-        float stepsize,
+        float vertex_distance,
         int maxverts,
+        int numsteps,
         GroomGuideVertex **r_verts,
         int *r_totalloc,
         int *r_totverts)
 {
+	BLI_assert(*r_totverts <= maxverts);
+	if (*r_totverts == maxverts)
+	{
+		return;
+	}
+	
 	const GroomBundle *bundle = &region->bundle;
+	if (bundle->totsections < 2)
+	{
+		return;
+	}
 	const int shapesize = region->numverts;
-	const int curvesize = bundle->curvesize;
 	const float *weights = &bundle->guide_shape_weights[guide_idx * shapesize];
+	double stepsize = 1.0 / numsteps;
 
 	int totverts = *r_totverts;
-	for (int i = 0; i < curvesize; ++i)
-	{
-		if (*r_totverts < maxverts)
+	float co0[3], co1[3], co2[3], co3[3];
+	/* Compute barycentric guide location from shape */
+	zero_v3(co1);
+	zero_v3(co2);
+	for (int j = 0; j < shapesize; ++j)
+	{
+		float shape_co[3];
+		groom_eval_shape_vertex(region, scalp, j, 0, shape_co);
+		madd_v3_v3fl(co1, shape_co, weights[j]);
+		groom_eval_shape_vertex(region, scalp, j, 1, shape_co);
+		madd_v3_v3fl(co2, shape_co, weights[j]);
+	}
+	for (int i = 0; i < bundle->totsections-1; ++i)
+	{
+		BLI_assert(totverts <= maxverts);
+		if (totverts == maxverts)
+		{
+			break;
+		}
+		
+		if (i < bundle->totsections-2)
 		{
-			totverts += 1;
-			groom_guide_buffer_reserve(totverts, r_verts, r_totalloc);
-			
-			GroomGuideVertex *v = &((*r_verts)[totverts - 1]);
 			/* Compute barycentric guide location from shape */
-			zero_v3(v->co);
+			zero_v3(co3);
 			for (int j = 0; j < shapesize; ++j)
 			{
-				madd_v3_v3fl(v->co, bundle->curvecache[j * curvesize + i].co, weights[j]);
+				float shape_co[3];
+				groom_eval_shape_vertex(region, scalp, j, i + 2, shape_co);
+				madd_v3_v3fl(co3, shape_co, weights[j]);
 			}
-			v->flag = 0;
 		}
+		
+		double q[4][3];
+		groom_forward_diff_init_hermite(
+					i > 0 ? co0 : NULL,
+					co1,
+					co2,
+					i < bundle->totsections-2 ? co3 : NULL,
+					stepsize,
+					q);
+		
+		float a[3], b[3];
+		float *cur = a, *prev = b;
+		
+		groom_forward_diff_get_point(q, prev);
+		
+		double length = 0.0;
+		float *tmp;
+		for (int j = 0; j < numsteps; ++j)
+		{
+			groom_forward_diff_get_point(q, cur);
+			length += len_v3v3(a, b);
+			if (length > (double)vertex_distance)
+			{
+				totverts += 1;
+				groom_guide_buffer_reserve(totverts, r_verts, r_totalloc);
+				
+				GroomGuideVertex *v = &((*r_verts)[totverts - 1]);
+				copy_v3_v3(v->co, cur);
+				v->flag = 0;
+				
+				BLI_assert(totverts <= maxverts);
+				if (totverts == maxverts)
+				{
+					break;
+				}
+				
+				length = 0.0;
+			}
+			
+			groom_forward_diff_step(q);
+			SWAP_TVAL(tmp, cur, prev);
+		}
+		
+		copy_v3_v3(co0, co1);
+		copy_v3_v3(co1, co2);
+		copy_v3_v3(co2, co3);
 	}
+	
 	*r_totverts = totverts;
 }
 
 void BKE_groom_hair_update_guide_curves(const Depsgraph *depsgraph, Groom *groom)
 {
+//#define DEBUG_TIME
+	
 	struct HairSystem *hsys = groom->hair_system;
 	const ListBase *regions = groom->editgroom ? &groom->editgroom->regions : &groom->regions;
+	const Mesh *scalp = BKE_groom_get_scalp(depsgraph, groom);
+	
+#ifdef DEBUG_TIME
+	TIMEIT_START(BKE_groom_hair_update_guide_curves);
+#endif
 	
 	/* Count guides for all regions combined */
 	int totguides = 0;
@@ -941,10 +1172,15 @@ void BKE_groom_hair_update_guide_curves(const Depsgraph *depsgraph, Groom *groom
 	
 	int *numverts = MEM_callocN(sizeof(int) * totguides, __func__);
 	int totverts = 0;
+	int usedguides = totguides;
 	// TODO multithreading here
+#ifdef DEBUG_TIME
+	TIMEIT_START(groom_guide_curve_discretize);
+#endif
 	{
-		static const float stepsize = 0.01f;
-		static const int maxverts = 100000;
+		static const float vertex_distance = 0.05f;
+		static const int numsteps = 1000;
+		static const int maxverts = 1000000;
 		int guide_idx = 0;
 		for (const GroomRegion *region = regions->first; region; region = region->next)
 		{
@@ -952,16 +1188,36 @@ void BKE_groom_hair_update_guide_curves(const Depsgraph *depsgraph, Groom *groom
 			for (int i = 0; i < bundle->totguides; ++i)
 			{
 				const int prev_totverts = totverts;
-				groom_guide_curve_discretize(region, i, stepsize, maxverts, &verts, &totalloc, &totverts);
+				groom_guide_curve_discretize(
+				            region,
+				            scalp,
+				            i,
+				            vertex_distance,
+				            maxverts,
+				            numsteps,
+				            &verts,
+				            &totalloc,
+				            &totverts);
 				numverts[guide_idx] = totverts - prev_totverts;
 				
+				if (numverts[guide_idx] < 2)
+				{
+					--usedguides;
+				}
+				
 				++guide_idx;
 			}
 		}
 	}
+#ifdef DEBUG_TIME
+	TIMEIT_END(groom_guide_curve_discretize);
+#endif
 	
 	/* Declare all guide curves and lengths */
-	BKE_hair_guide_curves_begin(hsys, totguides);
+	BKE_hair_guide_curves_begin(hsys, usedguides);
+#ifdef DEBUG_TIME
+	TIMEIT_START(BKE_hair_set_guide_curve);
+#endif
 	{
 		int guide_idx = 0;
 		for (const GroomRegion *region = regions->first; region; region = region->next)
@@ -969,98 +1225,82 @@ void BKE_groom_hair_update_guide_curves(const Depsgraph *depsgraph, Groom *groom
 			const GroomBundle *bundle = &region->bundle;
 			for (int i = 0; i < bundle->totguides; ++i)
 			{
-				/* TODO implement optional factors using scalp textures/vgroups */
-				float taper_length = region->taper_length;
-				float taper_thickness = region->taper_thickness;
-				
-				BKE_hair_set_guide_curve(
-				            hsys,
-				            i,
-				            &bundle->guides[i].root,
-				    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list