Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/src/buttons_editing.c3
-rw-r--r--source/blender/src/editarmature.c247
2 files changed, 214 insertions, 36 deletions
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index f186ca476d3..873dd17b905 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -4485,7 +4485,8 @@ static void editing_panel_mesh_skgen(Object *ob, Mesh *me)
}
}
- uiDefButBitS(block, TOG, SKGEN_REPOSITION, B_DIFF, "Reposition", 1025, 30,250,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Reposition nodes based on embedding instead of original vertice positions");
+ uiDefButBitS(block, TOG, SKGEN_REPOSITION, B_DIFF, "Reposition", 1025, 30,125,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Reposition nodes based on embedding instead of original vertice positions");
+ uiDefButBitS(block, TOG, SKGEN_SYMMETRY, B_DIFF, "Symmetry", 1150, 30,125,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Restore symmetries based on topology");
uiDefButC(block, NUM, B_DIFF, "P:", 1025, 10, 62,19, &G.scene->toolsettings->skgen_postpro_passes, 0, 10, 10, 0, "Specify the number of processing passes on the embeddings");
uiDefButC(block, ROW, B_DIFF, "Smooth", 1087, 10, 63,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_SMOOTH, 0, 0, "Smooth embeddings");
uiDefButC(block, ROW, B_DIFF, "Average", 1150, 10, 62,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_AVERAGE, 0, 0, "Average embeddings");
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
index 593322ac0e1..489f84baf30 100644
--- a/source/blender/src/editarmature.c
+++ b/source/blender/src/editarmature.c
@@ -3147,31 +3147,195 @@ void transform_armature_mirror_update(void)
/*****************************************************************************************************/
+/*************************************** SKELETON GENERATOR ******************************************/
+/*****************************************************************************************************/
+
+/**************************************** SYMMETRY HANDLING ******************************************/
+
+void markdownSymmetryArc(ReebArc *arc, ReebNode *node, int level);
-void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level);
+void reestablishRadialSymmetry(ReebNode *node, int depth, float axis[3])
+{
+ printf("radial symmetry not done yet\n");
+}
-void reestablishSymetry(ReebNode *node, int depth, int level)
+void mirrorAlongAxis(float v[3], float center[3], float axis[3])
{
+ float dv[3], pv[3];
+
+ VecSubf(dv, v, center);
+ Projf(pv, dv, axis);
+ VecMulf(pv, -2);
+ VecAddf(v, v, pv);
+}
+
+void reestablishAxialSymmetry(ReebNode *node, int depth, float axis[3])
+{
+ ReebArcIterator iter1, iter2;
+ EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
+ ReebArc *arc1 = NULL;
+ ReebArc *arc2 = NULL;
+ ReebNode *node1, *node2;
+ float nor[3], vec[3], p[3];
int i;
- /* detect spatial symetry */
+ for(i = 0; node->arcs[i] != NULL; i++)
+ {
+ ReebArc *connectedArc = node->arcs[i];
+
+ /* depth is store as a negative in flag. symmetry level is positive */
+ if (connectedArc->flags == -depth)
+ {
+ if (arc1 == NULL)
+ {
+ arc1 = connectedArc;
+ node1 = OTHER_NODE(arc1, node);
+ }
+ else
+ {
+ arc2 = connectedArc;
+ node2 = OTHER_NODE(arc2, node);
+ break; /* Can stop now, the two arcs have been found */
+ }
+ }
+ }
+
+ VecSubf(p, node1->p, node->p);
+ Crossf(vec, p, axis);
+ Crossf(nor, vec, axis);
+
+ /* mirror node2 along axis */
+ mirrorAlongAxis(node2->p, node->p, nor);
+
+ /* average with node1 */
+ VecAddf(node1->p, node1->p, node2->p);
+ VecMulf(node1->p, 0.5f);
+
+ /* mirror back on node2 */
+ VECCOPY(node2->p, node1->p);
+ mirrorAlongAxis(node2->p, node->p, nor);
+
+ /* Merge buckets
+ * there shouldn't be any null arcs here, but just to be safe
+ * */
+ if (arc1->bcount > 0 && arc2->bcount > 0)
+ {
+
+ initArcIterator(&iter1, arc1, node);
+ initArcIterator(&iter2, arc2, node);
+
+ bucket1 = nextBucket(&iter1);
+ bucket2 = nextBucket(&iter2);
+
+ /* Make sure they both start at the same value */
+ while(bucket1 && bucket1->val < bucket2->val)
+ {
+ bucket1 = nextBucket(&iter1);
+ }
+
+ while(bucket2 && bucket2->val < bucket1->val)
+ {
+ bucket2 = nextBucket(&iter2);
+ }
+
+
+ for( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2))
+ {
+ bucket1->nv += bucket2->nv; /* add counts */
+
+ /* mirror on axis */
+ mirrorAlongAxis(bucket2->p, node->p, nor);
+ /* add bucket2 in bucket1 */
+ VecLerpf(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv));
+
+ /* copy and mirror back to bucket2 */
+ bucket2->nv = bucket1->nv;
+ VECCOPY(bucket2->p, bucket1->p);
+ mirrorAlongAxis(bucket2->p, node->p, nor);
+ }
+ }
+}
+
+void markdownSecondarySymmetry(ReebNode *node, int depth, int level)
+{
+ float SYMMETRY_THRESHOLD = 0.005f * G.scene->toolsettings->skgen_resolution;
+ float axis[3] = {0, 0, 0};
+ float avg_weight = 0;
+ int count = 0;
+ int symmetric = 1;
+ int i;
+ /* Only reestablish spatial symmetry if needed */
+ if (G.scene->toolsettings->skgen_options & SKGEN_SYMMETRY)
+ {
+ /* count the number of branches in this symmetry group
+ * and determinte the axis of symmetry
+ * */
+ for(i = 0; node->arcs[i] != NULL; i++)
+ {
+ ReebArc *connectedArc = node->arcs[i];
+
+ /* depth is store as a negative in flag. symmetry level is positive */
+ if (connectedArc->flags == -depth)
+ {
+ count++;
+
+ avg_weight += OTHER_NODE(connectedArc, node)->weight;
+ }
+ /* If arc is on the axis */
+ else if (connectedArc->flags == level)
+ {
+ VecAddf(axis, axis, connectedArc->v1->p);
+ VecSubf(axis, axis, connectedArc->v2->p);
+ }
+ }
+
+ Normalize(axis);
+ avg_weight /= count;
+
+ /* Check if all branches are within range of the average weight */
+ for(i = 0; node->arcs[i] != NULL; i++)
+ {
+ ReebArc *connectedArc = node->arcs[i];
+
+ if (connectedArc->flags == -depth)
+ {
+ if (fabs(OTHER_NODE(connectedArc, node)->weight - avg_weight) > SYMMETRY_THRESHOLD)
+ {
+ symmetric = 0;
+ break;
+ }
+ }
+ }
+
+ if (symmetric)
+ {
+ /* Split between axial and radial symmetry */
+ if (count == 2)
+ {
+ reestablishAxialSymmetry(node, depth, axis);
+ }
+ else
+ {
+ reestablishRadialSymmetry(node, depth, axis);
+ }
+ }
+ }
/* markdown secondary symetries */
for(i = 0; node->arcs[i] != NULL; i++)
{
ReebArc *connectedArc = node->arcs[i];
- /* depth is store as a negative in flag. symetry level is positive */
if (connectedArc->flags == -depth)
{
- /* markdown symetry for branches corresponding to the depth */
- markdownSymetryArc(connectedArc, node, level + 1);
+ /* markdown symmetry for branches corresponding to the depth */
+ markdownSymmetryArc(connectedArc, node, level + 1);
}
}
}
-void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level)
+void markdownSymmetryArc(ReebArc *arc, ReebNode *node, int level)
{
int i;
arc->flags = level;
@@ -3186,7 +3350,7 @@ void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level)
{
ReebNode *connectedNode = OTHER_NODE(connectedArc, node);
- /* symetry level is positive value, negative values is subtree depth */
+ /* symmetry level is positive value, negative values is subtree depth */
connectedArc->flags = -subtreeDepth(connectedNode);
}
}
@@ -3195,7 +3359,7 @@ void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level)
for(i = 0; node->arcs[i] != NULL; i++)
{
- int isSymetryAxis = 0;
+ int issymmetryAxis = 0;
ReebArc *connectedArc = node->arcs[i];
/* only arcs not already marked as symetric */
@@ -3204,23 +3368,23 @@ void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level)
int j;
/* true by default */
- isSymetryAxis = 1;
+ issymmetryAxis = 1;
- for(j = 0; node->arcs[j] != NULL && isSymetryAxis == 1; j++)
+ for(j = 0; node->arcs[j] != NULL && issymmetryAxis == 1; j++)
{
ReebArc *otherArc = node->arcs[j];
/* different arc, same depth */
if (otherArc != connectedArc && otherArc->flags == connectedArc->flags)
{
- /* not on the symetry axis */
- isSymetryAxis = 0;
+ /* not on the symmetry axis */
+ issymmetryAxis = 0;
}
}
}
- /* arc could be on the symetry axis */
- if (isSymetryAxis == 1)
+ /* arc could be on the symmetry axis */
+ if (issymmetryAxis == 1)
{
/* no arc as been marked previously, keep this one */
if (arc == NULL)
@@ -3229,34 +3393,34 @@ void markdownSymetryArc(ReebArc *arc, ReebNode *node, int level)
}
else
{
- /* there can't be more than one symetry arc */
+ /* there can't be more than one symmetry arc */
arc = NULL;
break;
}
}
}
- /* go down the arc continuing the symetry axis */
+ /* go down the arc continuing the symmetry axis */
if (arc)
{
- markdownSymetryArc(arc, node, level);
+ markdownSymmetryArc(arc, node, level);
}
- /* restore symetry */
+ /* restore symmetry */
for(i = 0; node->arcs[i] != NULL; i++)
{
ReebArc *connectedArc = node->arcs[i];
- /* only arcs not already marked as symetric and is not the next arc on the symetry axis */
+ /* only arcs not already marked as symetric and is not the next arc on the symmetry axis */
if (connectedArc->flags < 0)
{
/* subtree depth is store as a negative value in the flag */
- reestablishSymetry(node, -connectedArc->flags, level);
+ markdownSecondarySymmetry(node, -connectedArc->flags, level);
}
}
}
-void markdownSymetry(ReebGraph *rg)
+void markdownSymmetry(ReebGraph *rg)
{
ReebNode *node;
ReebArc *arc;
@@ -3267,7 +3431,7 @@ void markdownSymetry(ReebGraph *rg)
arc->flags = 0;
}
- /* mark down all nodes as not on the symetry axis */
+ /* mark down all nodes as not on the symmetry axis */
for(node = rg->nodes.first; node; node = node->next)
{
node->flags = 0;
@@ -3281,7 +3445,7 @@ void markdownSymetry(ReebGraph *rg)
{
arc = node->arcs[0];
- markdownSymetryArc(arc, node, 1);
+ markdownSymmetryArc(arc, node, 1);
}
/* mark down non-symetric arcs */
@@ -3293,7 +3457,7 @@ void markdownSymetry(ReebGraph *rg)
}
else
{
- /* mark down nodes with the lowest level symetry axis */
+ /* mark down nodes with the lowest level symmetry axis */
if (arc->v1->flags == 0 || arc->v1->flags > arc->flags)
{
arc->v1->flags = arc->flags;
@@ -3308,6 +3472,8 @@ void markdownSymetry(ReebGraph *rg)
}
+/**************************************** SUBDIVISION ALGOS ******************************************/
+
EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
{
EditBone *lastBone = NULL;
@@ -3326,7 +3492,9 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
root = parent;
- for(initArcIterator(&iter, arc, head), previous = nextBucket(&iter), current = nextBucket(&iter); current; previous = current, current = nextBucket(&iter))
+ for(initArcIterator(&iter, arc, head), previous = nextBucket(&iter), current = nextBucket(&iter);
+ current;
+ previous = current, current = nextBucket(&iter))
{
float vec1[3], vec2[3];
float len1, len2;
@@ -3379,7 +3547,9 @@ float calcCorrelation(ReebArc *arc, int start, int end, float v0[3], float n[3])
float s_xyz = 0.0f;
/* First pass, calculate average */
- for(initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter))
+ for(initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
+ bucket;
+ bucket = nextBucket(&iter))
{
float v[3];
@@ -3392,7 +3562,9 @@ float calcCorrelation(ReebArc *arc, int start, int end, float v0[3], float n[3])
avg_t /= len;
/* Second pass, calculate s_xyz and s_t */
- for(initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter))
+ for(initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
+ bucket;
+ bucket = nextBucket(&iter))
{
float v[3], d[3];
float dt;
@@ -3443,7 +3615,9 @@ EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
parent = add_editbone("Bone");
VECCOPY(parent->head, head->p);
- for(previous = nextBucket(&iter), bucket = nextBucket(&iter); bucket; previous = bucket, bucket = nextBucket(&iter))
+ for(previous = nextBucket(&iter), bucket = nextBucket(&iter);
+ bucket;
+ previous = bucket, bucket = nextBucket(&iter))
{
/* Calculate normal */
VecSubf(n, bucket->p, parent->head);
@@ -3511,12 +3685,13 @@ EditBone * subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
float lengthLimit = G.scene->toolsettings->skgen_length_limit;
int same = 0;
- initArcIterator(&iter, arc, head);
-
parent = add_editbone("Bone");
VECCOPY(parent->head, head->p);
+ initArcIterator(&iter, arc, head);
+
bucket = nextBucket(&iter);
+
while (bucket != NULL)
{
float *vec0 = NULL;
@@ -3601,6 +3776,8 @@ EditBone * subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
return lastBone;
}
+/***************************************** MAIN ALGORITHM ********************************************/
+
void generateSkeletonFromReebGraph(ReebGraph *rg)
{
GHash *arcBoneMap = NULL;
@@ -3633,7 +3810,7 @@ void generateSkeletonFromReebGraph(ReebGraph *rg)
arcBoneMap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
- markdownSymetry(rg);
+ markdownSymmetry(rg);
exportGraph(rg, -1);
@@ -3645,14 +3822,14 @@ void generateSkeletonFromReebGraph(ReebGraph *rg)
/* Find out the direction of the arc through simple heuristics (in order of priority) :
*
- * 1- Arcs on primary symetry axis (flags == 1) point up (head: high weight -> tail: low weight)
+ * 1- Arcs on primary symmetry axis (flags == 1) point up (head: high weight -> tail: low weight)
* 2- Arcs starting on a primary axis point away from it (head: node on primary axis)
* 3- Arcs point down (head: low weight -> tail: high weight)
*
* Finally, the arc direction is stored in its flags: 1 (low -> high), -1 (high -> low)
*/
- /* if arc is a symetry axis, internal bones go up the tree */
+ /* if arc is a symmetry axis, internal bones go up the tree */
if (arc->flags == 1 && arc->v2->degree != 1)
{
head = arc->v2;
@@ -3660,7 +3837,7 @@ void generateSkeletonFromReebGraph(ReebGraph *rg)
arc->flags = -1; /* mark arc direction */
}
- /* Bones point AWAY from the symetry axis */
+ /* Bones point AWAY from the symmetry axis */
else if (arc->v1->flags == 1)
{
head = arc->v1;