[Bf-blender-cvs] [71e731ef1ee] hair_guides: Curve cache for main groom bundle curves.

Lukas Tönne noreply at git.blender.org
Sat Dec 30 09:09:32 CET 2017


Commit: 71e731ef1ee6391e55036820263ac71534eba48c
Author: Lukas Tönne
Date:   Sat Dec 30 08:08:11 2017 +0000
Branches: hair_guides
https://developer.blender.org/rB71e731ef1ee6391e55036820263ac71534eba48c

Curve cache for main groom bundle curves.

This stores interpolated cubic spline values for smooth curve rendering.
Local coordinate frames for sections are also computed alongside the cache.

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

M	source/blender/blenkernel/BKE_groom.h
M	source/blender/blenkernel/intern/groom.c
M	source/blender/blenkernel/intern/object_update.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
M	source/blender/draw/intern/draw_cache_impl_groom.c
M	source/blender/editors/groom/editgroom.c
M	source/blender/editors/groom/editgroom_region.c
M	source/blender/makesdna/DNA_groom_types.h
M	source/blender/makesrna/intern/rna_groom.c

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

diff --git a/source/blender/blenkernel/BKE_groom.h b/source/blender/blenkernel/BKE_groom.h
index 367b328635c..d119c5a2292 100644
--- a/source/blender/blenkernel/BKE_groom.h
+++ b/source/blender/blenkernel/BKE_groom.h
@@ -32,8 +32,11 @@
  *  \ingroup bke
  */
 
+struct EvaluationContext;
 struct Groom;
 struct Main;
+struct Object;
+struct Scene;
 
 void BKE_groom_init(struct Groom *groom);
 void *BKE_groom_add(struct Main *bmain, const char *name);
@@ -50,6 +53,13 @@ bool BKE_groom_minmax(struct Groom *groom, float min[3], float max[3]);
 void BKE_groom_boundbox_calc(struct Groom *groom, float r_loc[3], float r_size[3]);
 
 
+/* === Depsgraph evaluation === */
+
+void BKE_groom_eval_curve_cache(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
+void BKE_groom_clear_curve_cache(struct Object *ob);
+void BKE_groom_eval_geometry(const struct EvaluationContext *eval_ctx, struct Groom *groom);
+
+
 /* === Draw Cache === */
 
 enum {
diff --git a/source/blender/blenkernel/intern/groom.c b/source/blender/blenkernel/intern/groom.c
index 709af5926af..a6e2a6ec789 100644
--- a/source/blender/blenkernel/intern/groom.c
+++ b/source/blender/blenkernel/intern/groom.c
@@ -54,12 +54,16 @@
 #include "BKE_main.h"
 #include "BKE_object.h"
 
+#include "DEG_depsgraph.h"
+
 
 void BKE_groom_init(Groom *groom)
 {
 	BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(groom, id));
 	
 	groom->bb = BKE_boundbox_alloc_unit();
+	
+	groom->curve_res = 12;
 }
 
 void *BKE_groom_add(Main *bmain, const char *name)
@@ -75,6 +79,10 @@ static void groom_bundles_free(ListBase *bundles)
 {
 	for (GroomBundle *bundle = bundles->first; bundle; bundle = bundle->next)
 	{
+		if (bundle->curve_cache)
+		{
+			MEM_freeN(bundle->curve_cache);
+		}
 		if (bundle->sections)
 		{
 			MEM_freeN(bundle->sections);
@@ -124,6 +132,10 @@ void BKE_groom_copy_data(Main *UNUSED(bmain), Groom *groom_dst, const Groom *gro
 	BLI_duplicatelist(&groom_dst->bundles, &groom_src->bundles);
 	for (GroomBundle *bundle = groom_dst->bundles.first; bundle; bundle = bundle->next)
 	{
+		if (bundle->curve_cache)
+		{
+			bundle->curve_cache = MEM_dupallocN(bundle->curve_cache);
+		}
 		if (bundle->sections)
 		{
 			bundle->sections = MEM_dupallocN(bundle->sections);
@@ -191,6 +203,249 @@ void BKE_groom_boundbox_calc(Groom *groom, float r_loc[3], float r_size[3])
 	groom->bb->flag &= ~BOUNDBOX_DIRTY;
 }
 
+
+/* === Depsgraph evaluation === */
+
+/* linear bspline section eval */
+static void groom_eval_curve_cache_section_linear(
+        GroomBundle *bundle,
+        int isection,
+        int curve_res)
+{
+	BLI_assert(bundle->totsections > 1);
+	BLI_assert(isection < bundle->totsections - 1);
+	BLI_assert(curve_res >= 1);
+	
+	GroomSection *section = &bundle->sections[isection];
+	const float *co0 = section->center;
+	const float *co1 = (section+1)->center;
+	
+	float dx[3];
+	sub_v3_v3v3(dx, co1, co0);
+	mul_v3_fl(dx, 1.0f / curve_res);
+	
+	GroomCurveCache *cache = bundle->curve_cache + curve_res * isection;
+	float x[3];
+	copy_v3_v3(x, co0);
+	for (int i = 0; i <= curve_res; ++i, ++cache)
+	{
+		copy_v3_v3(cache->co, x);
+		add_v3_v3(x, dx);
+	}
+}
+
+/* forward differencing method for cubic polynomial eval */
+static void groom_forward_diff_cubic(float a, float b, float c, float d, float *p, int it, int stride)
+{
+	float f = (float)it;
+	a *= 1.0f / (f*f*f);
+	b *= 1.0f / (f*f);
+	c *= 1.0f / (f);
+	
+	float q0 = d;
+	float q1 = a + b + c;
+	float q2 = 6 * a + 2 * b;
+	float q3 = 6 * a;
+
+	for (int i = 0; i <= it; i++) {
+		*p = q0;
+		p = POINTER_OFFSET(p, stride);
+		q0 += q1;
+		q1 += q2;
+		q2 += q3;
+	}
+}
+
+/* cubic bspline section eval */
+static void groom_eval_curve_cache_section_cubic(
+        GroomBundle *bundle,
+        int isection,
+        int curve_res)
+{
+	BLI_assert(bundle->totsections > 2);
+	BLI_assert(isection < bundle->totsections - 1);
+	BLI_assert(curve_res >= 1);
+	
+	GroomSection *section = &bundle->sections[isection];
+	GroomCurveCache *cache = bundle->curve_cache + curve_res * isection;
+	
+	const float *co0 = (section-1)->center;
+	const float *co1 = section->center;
+	const float *co2 = (section+1)->center;
+	const float *co3 = (section+2)->center;
+	
+	float a, b, c, d;
+	for (int k = 0; k < 3; ++k)
+	{
+		/* define tangents from segment direction */
+		float n1, n2;
+		if (isection == 0)
+		{
+			n1 = co2[k] - co1[k];
+			n2 = 0.5f * (co3[k] - co1[k]);
+		}
+		else if (isection == bundle->totsections - 2)
+		{
+			n1 = 0.5f * (co2[k] - co0[k]);
+			n2 = co2[k] - co1[k];
+		}
+		else
+		{
+			n1 = 0.5f * (co2[k] - co0[k]);
+			n2 = 0.5f * (co3[k] - co1[k]);
+		}
+		
+		/* Hermite spline interpolation */
+		a = 2.0f * (co1[k] - co2[k]) + n1 + n2;
+		b = 3.0f * (co2[k] - co1[k]) - 2.0f * n1 - n2;
+		c = n1;
+		d = co1[k];
+		
+		groom_forward_diff_cubic(a, b, c, d, cache->co + k, curve_res, sizeof(GroomCurveCache));
+	}
+}
+
+static void groom_eval_curve_step(float mat[3][3], const float mat_prev[3][3], const float co0[3], const float co1[3])
+{
+	float dir[3];
+	sub_v3_v3v3(dir, co1, co0);
+	normalize_v3(dir);
+	
+	float dir_prev[3];
+	normalize_v3_v3(dir_prev, mat_prev[2]);
+	float rot[3][3];
+	rotation_between_vecs_to_mat3(rot, dir_prev, dir);
+	
+	mul_m3_m3m3(mat, rot, mat_prev);
+}
+
+static void groom_eval_curve_cache_mats(GroomCurveCache *cache, int totcache, float basemat[3][3])
+{
+	BLI_assert(totcache > 0);
+	
+	if (totcache == 1)
+	{
+		/* nothing to rotate, use basemat */
+		copy_m3_m3(cache->mat, basemat);
+		return;
+	}
+	
+	/* align to first segment */
+	groom_eval_curve_step(cache[0].mat, basemat, cache[1].co, cache[0].co);
+	++cache;
+	
+	/* align interior segments to average of prev and next segment */
+	for (int i = 1; i < totcache - 1; ++i)
+	{
+		groom_eval_curve_step(cache[0].mat, cache[-1].mat, cache[1].co, cache[-1].co);
+		++cache;
+	}
+	
+	/* align to last segment */
+	groom_eval_curve_step(cache[0].mat, cache[-1].mat, cache[0].co, cache[-1].co);
+}
+
+void BKE_groom_eval_curve_cache(const EvaluationContext *UNUSED(eval_ctx), Scene *UNUSED(scene), Object *ob)
+{
+	BLI_assert(ob->type == OB_GROOM);
+	Groom *groom = (Groom *)ob->data;
+	ListBase *bundles = (groom->editgroom ? &groom->editgroom->bundles : &groom->bundles);
+	
+	for (GroomBundle *bundle = bundles->first; bundle; bundle = bundle->next)
+	{
+		const int totsections = bundle->totsections;
+		if (totsections == 0)
+		{
+			/* clear cache */
+			if (bundle->curve_cache)
+			{
+				MEM_freeN(bundle->curve_cache);
+				bundle->curve_cache = NULL;
+				bundle->totcache = 0;
+			}
+			
+			/* nothing to do */
+			continue;
+		}
+		
+		bundle->totcache = (totsections-1) * groom->curve_res + 1;
+		bundle->curve_cache = MEM_reallocN_id(bundle->curve_cache, sizeof(GroomCurveCache) * bundle->totcache, "groom bundle curve cache");
+		
+		if (totsections == 1)
+		{
+			/* degenerate case */
+			copy_v3_v3(bundle->curve_cache[0].co, bundle->sections[0].center);
+		}
+		else if (totsections == 2)
+		{
+			/* single section, linear */
+			groom_eval_curve_cache_section_linear(bundle, 0, groom->curve_res);
+		}
+		else
+		{
+			/* cubic splines */
+			GroomSection *section = bundle->sections;
+			for (int i = 0; i < totsections-1; ++i, ++section)
+			{
+				groom_eval_curve_cache_section_cubic(bundle, i, groom->curve_res);
+			}
+		}
+		
+		float basemat[3][3];
+		unit_m3(basemat); // TODO
+		groom_eval_curve_cache_mats(bundle->curve_cache, bundle->totcache, basemat);
+		
+		/* Copy coordinate frame to sections */
+		{
+			GroomSection *section = bundle->sections;
+			GroomCurveCache *cache = bundle->curve_cache;
+			for (int i = 0; i < totsections; ++i, ++section, cache += groom->curve_res)
+			{
+				copy_m3_m3(section->mat, cache->mat);
+			}
+		}
+	}
+}
+
+static void groom_bundles_curve_cache_clear(ListBase *bundles)
+{
+	for (GroomBundle *bundle = bundles->first; bundle; bundle = bundle->next)
+	{
+		if (bundle->curve_cache)
+		{
+			MEM_freeN(bundle->curve_cache);
+			bundle->curve_cache = NULL;
+			bundle->totcache = 0;
+		}
+	}
+}
+
+void BKE_groom_clear_curve_cache(Object *ob)
+{
+	BLI_assert(ob->type == OB_GROOM);
+	Groom *groom = (Groom *)ob->data;
+	
+	groom_bundles_curve_cache_clear(&groom->bundles);
+	if (groom->editgroom)
+	{
+		groom_bundles_curve_cache_clear(&groom->editgroom->bundles);
+	}
+}
+
+void BKE_groom_eval_geometry(const EvaluationContext *UNUSED(eval_ctx), Groom *groom)
+{
+	if (G.debug & G_DEBUG_DEPSGRAPH) {
+		printf("%s on %s\n", __func__, groom->id.name);
+	}
+	
+	if (groom->bb == NULL || (groom->bb->flag & BOUNDBOX_DIRTY)) {
+		BKE_groom_boundbox_calc(groom, NULL, NULL);
+	}
+}
+
+
+/* === Draw Cache === */
+
 void (*BKE_groom_batch_cache_dirty_cb)(Groom* groom, int mode) = NULL;
 void (*BKE_groom_batch_cache_free_cb)(Groom* groom) = NULL;
 
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index d745e629453..cde54d87c15 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -216,6 +216,9 @@ void BKE_object_handle_data_update(
 			BKE_lattice_modifiers_calc(eval_ctx, scene, ob);
 			break;
 
+		case OB_GROOM:
+			BKE_groom_eval_curve_cache(eval_ctx, scene, ob);
+
 		case OB_EMPTY:
 			if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
 				if (BKE_image_is_animated(ob->data))
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 564143c8093..8bec2f47d12 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -8400,6 +8400,8 @@ static void direct_link_groom(FileData *fd, Groom *groom)
 	{
 		bundle->sections = newdataadr(fd, bundle->sections);
 		bundle->verts = newdataadr(fd, bundle->verts);
+		bundle->curve_cache = NULL;
+		bundle->totcache = 0;
 	}
 	
 	groom->bb = NULL;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 85a72a8be2c..68440bb4ff1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -51,6 +51,7 @@ extern "C" {
 #include 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list