Patch #8613 - Vertex groups in the mirror modifier.
This patch re-assigns the mirrored data to use vertex groups with "mirrored" names (e.g. L_arm -> R_arm, Leg.R -> Leg.L etc.). Vertex groups with the "mirrored" names must already exist in the base mesh. This means that it is no longer necessary to apply the mirror modifier in order to rig the mirrored data independently. Thanks to Michael Fox for the patch!
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
#include "stdarg.h"
|
||||
#include "math.h"
|
||||
#include "float.h"
|
||||
#include "ctype.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
@@ -1269,7 +1270,7 @@ static void mirrorModifier_initData(ModifierData *md)
|
||||
{
|
||||
MirrorModifierData *mmd = (MirrorModifierData*) md;
|
||||
|
||||
mmd->flag |= MOD_MIR_AXIS_X;
|
||||
mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP);
|
||||
mmd->tolerance = 0.001;
|
||||
mmd->mirror_ob = NULL;
|
||||
}
|
||||
@@ -1308,6 +1309,118 @@ static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest,
|
||||
}
|
||||
}
|
||||
|
||||
/* finds the best possible flipped name. For renaming; check for unique names afterwards */
|
||||
/* if strip_number: removes number extensions */
|
||||
void vertgroup_flip_name (char *name, int strip_number)
|
||||
{
|
||||
int len;
|
||||
char prefix[128]={""}; /* The part before the facing */
|
||||
char suffix[128]={""}; /* The part after the facing */
|
||||
char replace[128]={""}; /* The replacement string */
|
||||
char number[128]={""}; /* The number extension string */
|
||||
char *index=NULL;
|
||||
|
||||
len= strlen(name);
|
||||
if(len<3) return; // we don't do names like .R or .L
|
||||
|
||||
/* We first check the case with a .### extension, let's find the last period */
|
||||
if(isdigit(name[len-1])) {
|
||||
index= strrchr(name, '.'); // last occurrance
|
||||
if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
|
||||
if(strip_number==0)
|
||||
strcpy(number, index);
|
||||
*index= 0;
|
||||
len= strlen(name);
|
||||
}
|
||||
}
|
||||
|
||||
strcpy (prefix, name);
|
||||
|
||||
#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
|
||||
|
||||
/* first case; separator . - _ with extensions r R l L */
|
||||
if( IS_SEPARATOR(name[len-2]) ) {
|
||||
switch(name[len-1]) {
|
||||
case 'l':
|
||||
prefix[len-1]= 0;
|
||||
strcpy(replace, "r");
|
||||
break;
|
||||
case 'r':
|
||||
prefix[len-1]= 0;
|
||||
strcpy(replace, "l");
|
||||
break;
|
||||
case 'L':
|
||||
prefix[len-1]= 0;
|
||||
strcpy(replace, "R");
|
||||
break;
|
||||
case 'R':
|
||||
prefix[len-1]= 0;
|
||||
strcpy(replace, "L");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* case; beginning with r R l L , with separator after it */
|
||||
else if( IS_SEPARATOR(name[1]) ) {
|
||||
switch(name[0]) {
|
||||
case 'l':
|
||||
strcpy(replace, "r");
|
||||
strcpy(suffix, name+1);
|
||||
prefix[0]= 0;
|
||||
break;
|
||||
case 'r':
|
||||
strcpy(replace, "l");
|
||||
strcpy(suffix, name+1);
|
||||
prefix[0]= 0;
|
||||
break;
|
||||
case 'L':
|
||||
strcpy(replace, "R");
|
||||
strcpy(suffix, name+1);
|
||||
prefix[0]= 0;
|
||||
break;
|
||||
case 'R':
|
||||
strcpy(replace, "L");
|
||||
strcpy(suffix, name+1);
|
||||
prefix[0]= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(len > 5) {
|
||||
/* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
|
||||
index = BLI_strcasestr(prefix, "right");
|
||||
if (index==prefix || index==prefix+len-5) {
|
||||
if(index[0]=='r')
|
||||
strcpy (replace, "left");
|
||||
else {
|
||||
if(index[1]=='I')
|
||||
strcpy (replace, "LEFT");
|
||||
else
|
||||
strcpy (replace, "Left");
|
||||
}
|
||||
*index= 0;
|
||||
strcpy (suffix, index+5);
|
||||
}
|
||||
else {
|
||||
index = BLI_strcasestr(prefix, "left");
|
||||
if (index==prefix || index==prefix+len-4) {
|
||||
if(index[0]=='l')
|
||||
strcpy (replace, "right");
|
||||
else {
|
||||
if(index[1]=='E')
|
||||
strcpy (replace, "RIGHT");
|
||||
else
|
||||
strcpy (replace, "Right");
|
||||
}
|
||||
*index= 0;
|
||||
strcpy (suffix, index+4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef IS_SEPARATOR
|
||||
|
||||
sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
|
||||
}
|
||||
|
||||
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|
||||
Object *ob,
|
||||
DerivedMesh *dm,
|
||||
@@ -1321,6 +1434,9 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|
||||
int maxVerts = dm->getNumVerts(dm);
|
||||
int maxEdges = dm->getNumEdges(dm);
|
||||
int maxFaces = dm->getNumFaces(dm);
|
||||
int vector_size, j, a, b;
|
||||
bDeformGroup *def, *defb;
|
||||
bDeformGroup **vector_def = NULL;
|
||||
int (*indexMap)[2];
|
||||
float mtx[4][4], imtx[4][4];
|
||||
|
||||
@@ -1330,6 +1446,21 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|
||||
|
||||
result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
|
||||
|
||||
|
||||
if (mmd->flag & MOD_MIR_VGROUP) {
|
||||
/* calculate the number of deformedGroups */
|
||||
for(vector_size = 0, def = ob->defbase.first; def;
|
||||
def = def->next, vector_size++);
|
||||
|
||||
/* load the deformedGroups for fast access */
|
||||
vector_def =
|
||||
(bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
|
||||
"group_index");
|
||||
for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
|
||||
vector_def[a] = def;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmd->mirror_ob) {
|
||||
float obinv[4][4];
|
||||
|
||||
@@ -1374,16 +1505,48 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|
||||
mv->flag |= ME_VERT_MERGED;
|
||||
} else {
|
||||
MVert *mv2 = CDDM_get_vert(result, numVerts);
|
||||
MDeformVert *dvert = NULL;
|
||||
|
||||
DM_copy_vert_data(dm, result, i, numVerts, 1);
|
||||
*mv2 = *mv;
|
||||
numVerts++;
|
||||
|
||||
co[axis] = -co[axis];
|
||||
if (mmd->mirror_ob) {
|
||||
VecMat4MulVecfl(co, imtx, co);
|
||||
}
|
||||
VecCopyf(mv2->co, co);
|
||||
|
||||
if (mmd->flag & MOD_MIR_VGROUP){
|
||||
dvert = DM_get_vert_data(result, numVerts, CD_MDEFORMVERT);
|
||||
|
||||
if (dvert)
|
||||
{
|
||||
for(j = 0; j < dvert[0].totweight; ++j)
|
||||
{
|
||||
char tmpname[32];
|
||||
|
||||
if(dvert->dw[j].def_nr < 0 ||
|
||||
dvert->dw[j].def_nr >= vector_size)
|
||||
continue;
|
||||
|
||||
def = vector_def[dvert->dw[j].def_nr];
|
||||
strcpy(tmpname, def->name);
|
||||
vertgroup_flip_name(tmpname,0);
|
||||
|
||||
for(b = 0, defb = ob->defbase.first; defb;
|
||||
defb = defb->next, b++)
|
||||
{
|
||||
if(!strcmp(defb->name, tmpname))
|
||||
{
|
||||
dvert->dw[j].def_nr = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numVerts++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1467,6 +1630,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (vector_def) MEM_freeN(vector_def);
|
||||
|
||||
MEM_freeN(indexMap);
|
||||
|
||||
CDDM_lower_num_verts(result, numVerts);
|
||||
|
||||
@@ -176,6 +176,7 @@ typedef struct MirrorModifierData {
|
||||
#define MOD_MIR_AXIS_X 1<<3
|
||||
#define MOD_MIR_AXIS_Y 1<<4
|
||||
#define MOD_MIR_AXIS_Z 1<<5
|
||||
#define MOD_MIR_VGROUP 1<<6
|
||||
|
||||
typedef struct EdgeSplitModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
@@ -1767,7 +1767,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
|
||||
} else if (md->type==eModifierType_Build) {
|
||||
height = 86;
|
||||
} else if (md->type==eModifierType_Mirror) {
|
||||
height = 86;
|
||||
height = 105;
|
||||
} else if (md->type==eModifierType_Bevel) {
|
||||
BevelModifierData *bmd = (BevelModifierData*) md;
|
||||
height = 105; /* height = 124; */
|
||||
@@ -1899,6 +1899,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
|
||||
uiDefButBitS(block, TOG, MOD_MIR_AXIS_Y, B_MODIFIER_RECALC, "Y", lx+20,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Y axis mirror");
|
||||
uiDefButBitS(block, TOG, MOD_MIR_AXIS_Z, B_MODIFIER_RECALC, "Z", lx+40,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Z axis mirror");
|
||||
uiDefButBitS(block, TOG, MOD_MIR_CLIPPING, B_MODIFIER_RECALC, "Do Clipping", lx+60, cy, buttonWidth-60,19, &mmd->flag, 1, 2, 0, 0, "Prevents during Transform vertices to go through Mirror");
|
||||
uiDefButBitS(block, TOG, MOD_MIR_VGROUP, B_MODIFIER_RECALC, "Mirror Vgroups", lx, (cy-=19), buttonWidth,19, &mmd->flag, 1, 2, 0, 0, "Mirror vertex groups (e.g. .R->.L)");
|
||||
uiDefButBitS(block, TOG, MOD_MIR_MIRROR_U, B_MODIFIER_RECALC,
|
||||
"Mirror U",
|
||||
lx, (cy-=19), buttonWidth/2, 19,
|
||||
|
||||
Reference in New Issue
Block a user