[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