Commit: 98f41066943d8b1cf9236d6b358d1e84c9e7cc4b
Author: Krzysztof Recko
Date:   Tue Apr 7 12:44:39 2015 +1000
Branches: master
https://developer.blender.org/rB98f41066943d8b1cf9236d6b358d1e84c9e7cc4b

Metaball tessellation optimization (Octree to BVH)

Speedup is non-linear, 2x-10x faster is quite normal.
Patch T43678.

- Switched from an Octree to BVH.
- Finding first points of surface no longer "wastes" density function 
evaluation: every result is cached.
- Use MemArena instead of using own memory management.
- Correct calculation of metaelem bounding box.
- Remove mball_count(): mballs are now counted "on the go".

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

M       source/blender/blenkernel/BKE_mball.h
M       source/blender/blenkernel/BKE_mball_tessellate.h
M       source/blender/blenkernel/intern/mball_tessellate.c
M       source/blender/windowmanager/intern/wm_init_exit.c

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

diff --git a/source/blender/blenkernel/BKE_mball.h 
b/source/blender/blenkernel/BKE_mball.h
index 70f932f..321cbbb 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -45,8 +45,6 @@ struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
 
 void BKE_mball_make_local(struct MetaBall *mb);
 
-void BKE_mball_cubeTable_free(void);
-
 bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
 bool BKE_mball_is_basis(struct Object *ob);
 struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h 
b/source/blender/blenkernel/BKE_mball_tessellate.h
index a3d3e19..361f31b 100644
--- a/source/blender/blenkernel/BKE_mball_tessellate.h
+++ b/source/blender/blenkernel/BKE_mball_tessellate.h
@@ -31,4 +31,6 @@ void BKE_mball_polygonize(
         struct EvaluationContext *eval_ctx, struct Scene *scene,
         struct Object *ob, struct ListBase *dispbase);
 
+void BKE_mball_cubeTable_free(void);
+
 #endif  /* __BKE_MBALL_TESSELLATE_H__ */
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c 
b/source/blender/blenkernel/intern/mball_tessellate.c
index 0402494..080a8ce 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -44,26 +44,21 @@
 #include "BLI_path_util.h"
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
+#include "BLI_memarena.h"
 
 #include "BKE_global.h"
 
 #include "BKE_depsgraph.h"
 #include "BKE_scene.h"
 #include "BKE_displist.h"
-#include "BKE_mball.h"
 #include "BKE_mball_tessellate.h"  /* own include */
 
-/* Data types */
+#include "BLI_strict_flags.h"
 
-typedef struct vertex {         /* surface vertex */
-       float co[3];  /* position and surface normal */
-       float no[3];
-} VERTEX;
+/* experimental (faster) normal calculation */
+// #define USE_ACCUM_NORMAL
 
-typedef struct vertices {       /* list of vertices in polygonization */
-       int count, max;             /* # vertices, max # allowed */
-       VERTEX *ptr;                /* dynamically allocated */
-} VERTICES;
+/* Data types */
 
 typedef struct corner {         /* corner of a cube */
        int i, j, k;                /* (i, j, k) is index within lattice */
@@ -102,74 +97,161 @@ typedef struct intlists {       /* list of list of 
integers */
        struct intlists *next;      /* remaining elements */
 } INTLISTS;
 
-/* dividing scene using octal tree makes polygonisation faster */
-typedef struct ml_pointer {
-       struct ml_pointer *next, *prev;
-       struct MetaElem *ml;
-} ml_pointer;
-
-typedef struct octal_node {
-       struct octal_node *nodes[8];/* children of current node */
-       struct octal_node *parent;  /* parent of current node */
-       struct ListBase elems;      /* ListBase of MetaElem pointers 
(ml_pointer) */
-       float x_min, y_min, z_min;  /* 1st border point */
-       float x_max, y_max, z_max;  /* 7th border point */
-       float x, y, z;              /* center of node */
-       int pos, neg;               /* number of positive and negative 
MetaElements in the node */
-       int count;                  /* number of MetaElems, which belongs to 
the node */
-} octal_node;
-
-typedef struct octal_tree {
-       struct octal_node *first;   /* first node */
-       int pos, neg;               /* number of positive and negative 
MetaElements in the scene */
-       short depth;                /* number of scene subdivision */
-} octal_tree;
-
-struct pgn_elements {
-       struct pgn_elements *next, *prev;
-       char *data;
-};
+typedef struct Box {                   /* an AABB with pointer to metalelem */
+       float min[3], max[3];
+       const MetaElem *ml;
+} Box;
+
+typedef struct MetaballBVHNode {       /* BVH node */
+       Box bb[2];                                              /* AABB of 
children */
+       struct MetaballBVHNode *child[2];
+} MetaballBVHNode;
+
+typedef struct process {        /* parameters, storage */
+       float thresh, size;                     /* mball threshold, single cube 
size */
+       float delta;                            /* small delta for calculating 
normals */
+       unsigned int converge_res;      /* converge procedure resolution (more 
= slower) */
+
+       MetaElem **mainb;                       /* array of all metaelems */
+       unsigned int totelem, mem;      /* number of metaelems */
+
+       MetaballBVHNode metaball_bvh; /* The simplest bvh */
+       Box allbb;                   /* Bounding box of all metaelems */
 
-typedef struct process {        /* parameters, function, storage */
-       /* ** old G_mb contents ** */
-       float thresh;
-       int totelem;
-       MetaElem **mainb;
-       octal_tree *metaball_tree;
-
-       /* ** old process contents ** */
-
-       /* what happens here? floats, I think. */
-       /*  float (*function)(void);     */     /* implicit surface function */
-       float (*function)(struct process *, float, float, float);
-       float size, delta;          /* cube size, normal delta */
-       int bounds;                 /* cube range within lattice */
-       CUBES *cubes;               /* active cubes */
-       VERTICES vertices;          /* surface vertices */
+       MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */
+       unsigned int bvh_queue_size;
+
+       CUBES *cubes;               /* stack of cubes waiting for 
polygonization */
        CENTERLIST **centers;       /* cube center hash table */
        CORNER **corners;           /* corner value hash table */
        EDGELIST **edges;           /* edge and vertex id hash table */
 
-       /* Runtime things */
-       int *indices;
-       int totindex, curindex;
+       int (*indices)[4];          /* output indices */
+       unsigned int totindex;          /* size of memory allocated for indices 
*/
+       unsigned int curindex;          /* number of currently added indices */
+
+       float (*co)[3], (*no)[3];   /* surface vertices - positions and normals 
*/
+       unsigned int totvertex;         /* memory size */
+       unsigned int curvertex;         /* currently added vertices */
 
-       int pgn_offset;
-       struct pgn_elements *pgn_current;
-       ListBase pgn_list;
+       /* memory allocation from common pool */
+       MemArena *pgn_elements;
 } PROCESS;
 
 /* Forward declarations */
-static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, 
MetaBall *mb);
-static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const 
int j, const int k);
-static CORNER *setcorner(PROCESS *process, int i, int j, int k);
-static void converge(PROCESS *process, const float p1[3], const float p2[3], 
float v1, float v2,
-                     float p[3], MetaBall *mb, int f);
+static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2);
+static void add_cube(PROCESS *process, int i, int j, int k);
+static void make_face(PROCESS *process, int i1, int i2, int i3, int i4);
+static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, 
float r_p[3]);
+
+/* ******************* SIMPLE BVH ********************* */
+
+static void make_box_union(const BoundBox *a, const Box *b, Box *r_out)
+{
+       r_out->min[0] = min_ff(a->vec[0][0], b->min[0]);
+       r_out->min[1] = min_ff(a->vec[0][1], b->min[1]);
+       r_out->min[2] = min_ff(a->vec[0][2], b->min[2]);
+
+       r_out->max[0] = max_ff(a->vec[6][0], b->max[0]);
+       r_out->max[1] = max_ff(a->vec[6][1], b->max[1]);
+       r_out->max[2] = max_ff(a->vec[6][2], b->max[2]);
+}
+
+static void make_box_from_metaelem(Box *r, const MetaElem *ml)
+{
+       copy_v3_v3(r->max, ml->bb->vec[6]);
+       copy_v3_v3(r->min, ml->bb->vec[0]);
+       r->ml = ml;
+}
+
+/**
+ * Partitions part of mainb array [start, end) along axis s. Returns i,
+ * where centroids of elements in the [start, i) segment lie "on the right 
side" of div,
+ * and elements in the [i, end) segment lie "on the left"
+ */
+static unsigned int partition_mainb(MetaElem **mainb, unsigned int start, 
unsigned int end, unsigned int s, float div)
+{
+       unsigned int i = start, j = end - 1;
+       div *= 2.0f;
+
+       while (1) {
+               while (i < j && div > (mainb[i]->bb->vec[6][s] + 
mainb[i]->bb->vec[0][s])) i++;
+               while (j > i && div < (mainb[j]->bb->vec[6][s] + 
mainb[j]->bb->vec[0][s])) j--;
+
+               if (i >= j)
+                       break;
+
+               SWAP(MetaElem *, mainb[i], mainb[j]);
+               i++;
+               j--;
+       }
+
+       if (i == start) {
+               i++;
+       }
+
+       return i;
+}
+
+/**
+ * Recursively builds a BVH, dividing elements along the middle of the longest 
axis of allbox.
+ */
+static void build_bvh_spatial(
+        PROCESS *process, MetaballBVHNode *node,
+        unsigned int start, unsigned int end, const Box *allbox)
+{
+       unsigned int part, j, s;
+       float dim[3], div;
+
+       /* Maximum bvh queue size is number of nodes which are made, equals 
calls to this function. */
+       process->bvh_queue_size++;
 
+       dim[0] = allbox->max[0] - allbox->min[0];
+       dim[1] = allbox->max[1] - allbox->min[1];
+       dim[2] = allbox->max[2] - allbox->min[2];
+
+       s = 0;
+       if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1;
+       else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2;
+
+       div = allbox->min[s] + (dim[s] / 2.0f);
+
+       part = partition_mainb(process->mainb, start, end, s, div);
+
+       make_box_from_metaelem(&node->bb[0], process->mainb[start]);
+       node->child[0] = NULL;
+
+       if (part > start + 1) {
+               for (j = start; j < part; j++) {
+                       make_box_union(process->mainb[j]->bb, &node->bb[0], 
&node->bb[0]);
+               }
+
+               node->child[0] = BLI_memarena_alloc(process->pgn_elements, 
sizeof(MetaballBVHNode));
+               build_bvh_spatial(process, node->child[0], start, part, 
&node->bb[0]);
+       }
+
+       node->child[1] = NULL;
+       if (part < end) {
+               make_box_from_metaelem(&node->bb[1], process->mainb[part]);
+
+               if (part < end - 1) {
+                       for (j = part; j < end; j++) {
+                               make_box_union(process->mainb[j]->bb, 
&node->bb[1], &node->bb[1]);
+                       }
+
+                       node->child[1] = 
BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+                       build_bvh_spatial(process, node->child[1], part, end, 
&node->bb[1]);
+               }
+       }
+       else {
+               INIT_MINMAX(node->bb[1].min, node->bb[1].max);
+       }
+}
 
 /* ******************** ARITH ************************* */
 
-/* BASED AT CODE (but mostly rewritten) :
+/**
+ * BASED AT CODE (but mostly rewritten) :
  * C code from the article
  * "An Implicit Surface Polygonizer"
  * by Jules Bloomenthal, jbl...@beauty.gmu.edu
@@ -178,9 +260,8 @@ static void converge(PROCESS *process, const float p1[3], 
const float p2[3], flo
  * Authored by Jules Bloomenthal, Xerox PARC.
  * Copyright (c) Xerox Corporation, 1991.  All rights reserved.
  * Permission is granted to reproduce, use and distribute this code for
- * any and all purposes, provided that this notice appears in all copies. */
-
-#de

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to