diff options
author | Joshua Leung <aligorith@gmail.com> | 2007-08-17 15:23:48 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2007-08-17 15:23:48 +0400 |
commit | 400d77bbe29ddecaaa4530146f07435877f9a6aa (patch) | |
tree | dfb746811c78f111784679e2b1895669939f0a6b /source/blender | |
parent | 4d884c0fbfd8c7588f6e082adc8925a8df44be24 (diff) |
== Constraints - Geometry Targets ==
It is now possible to use the geometry of Meshes and/or Lattices as the target of a constraint. All you need to do, is to create a new Vertex-Group and assign all the points that you wish to use as the target, then type that name into the VG: field for the relevant constraints.
One of the cases where this is beneficial is when you need to copy the location of a vertex. Now you don't need to make extra vertex-parents for that.
Additional Notes:
* The code takes the average of the locations of the nominated vertices, and puts that in world-space for constraint solving (and regular space-conversion stuff).
* Currently, rotation and scaling of points is not taken into account. The rotation/scaling used is from the object's matrix. Hopefully, this will only be a temporary problem (will be fixed soon)
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_deform.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 148 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/deform.c | 26 | ||||
-rw-r--r-- | source/blender/src/buttons_object.c | 47 |
4 files changed, 205 insertions, 17 deletions
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index de0dddabfd3..67e2a8948d5 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -46,6 +46,7 @@ void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2); struct bDeformGroup *copy_defgroup (struct bDeformGroup *ingroup); struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name); int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg); +int get_named_vertexgroup_num (Object *ob, char *name); void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob); #endif diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 205feb15ab3..651b8a102e9 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -45,6 +45,8 @@ #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_lattice_types.h" #include "DNA_scene_types.h" #include "BKE_utildefines.h" @@ -54,12 +56,15 @@ #include "BKE_blender.h" #include "BKE_constraint.h" #include "BKE_displist.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" #include "BKE_object.h" #include "BKE_ipo.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_idprop.h" + #include "BPY_extern.h" #include "blendef.h" @@ -1106,9 +1111,111 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 /* ------------------------------- Target ---------------------------- */ +/* function that sets the given matrix based on given vertex group in mesh */ +static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) +{ + DerivedMesh *dm = (DerivedMesh *)ob->derivedFinal; + float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; + int dgroup; + + /* initialize target matrix using target matrix */ + Mat4CpyMat4(mat, ob->obmat); + + /* get index of vertex group */ + dgroup = get_named_vertexgroup_num(ob, substring); + if (dgroup < 0) return; + + /* only continue if there's a valid DerivedMesh */ + if (dm) { + MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); + int numVerts = dm->getNumVerts(dm); + int i, j, count = 0; + float co[3]; + + /* get the average of all verts with that are in the vertex-group */ + for (i = 0; i < numVerts; i++, index++) { + for (j = 0; j < dvert[i].totweight; j++) { + /* does this vertex belong to nominated vertex group? */ + if (dvert[i].dw[j].def_nr == dgroup) { + dm->getVertCo(dm, i, co); + VecAddf(vec, vec, co); + count++; + break; + } + + } + } + + /* calculate average, and apply as new location for matrix */ + if (count > 0) + VecMulf(vec, 1.0f / count); + VecMat4MulVecfl(tvec, ob->obmat, vec); + + /* copy new location to matrix */ + VECCOPY(mat[3], tvec); + } +} + +/* function that sets the given matrix based on given vertex group in lattice */ +static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][4]) +{ + Lattice *lt= (Lattice *)ob->data; + + DispList *dl = find_displist(&ob->disp, DL_VERTS); + float *co = dl?dl->verts:NULL; + BPoint *bp = lt->def; + + MDeformVert *dvert = lt->dvert; + int tot_verts= lt->pntsu*lt->pntsv*lt->pntsw; + float vec[3]= {0.0f, 0.0f, 0.0f}, tvec[3]; + int dgroup=0, grouped=0; + int i, n; + + /* initialize target matrix using target matrix */ + Mat4CpyMat4(mat, ob->obmat); + + /* get index of vertex group */ + dgroup = get_named_vertexgroup_num(ob, substring); + if (dgroup < 0) return; + + /* 1. Loop through control-points checking if in nominated vertex-group. + * 2. If it is, add it to vec to find the average point. + */ + for (i=0; i < tot_verts; i++, dvert++) { + for (n= 0; n < dvert->totweight; n++) { + /* found match - vert is in vgroup */ + if (dvert->dw[n].def_nr == dgroup) { + /* copy coordinates of point to temporary vector, then add to find average */ + if (co) + memcpy(tvec, co, 3*sizeof(float)); + else + memcpy(tvec, bp->vec, 3*sizeof(float)); + + VecAddf(vec, vec, tvec); + grouped++; + + break; + } + } + + /* advance pointer to coordinate data */ + if (co) co+= 3; + else bp++; + } + + /* find average location, then multiply by ob->obmat to find world-space location */ + if (grouped) + VecMulf(vec, 1.0f / grouped); + VecMat4MulVecfl(tvec, ob->obmat, vec); + + /* copy new location to matrix */ + VECCOPY(mat[3], tvec); +} + /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4 (Object *ob, const char *substring, float mat[][4], short from, short to) +static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to) { /* Case OBJECT */ if (!strlen(substring)) { @@ -1116,9 +1223,27 @@ static void constraint_target_to_mat4 (Object *ob, const char *substring, float constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case VERTEXGROUP */ - else if (ELEM(ob->type, OB_MESH, OB_LATTICE)) { - /* devise a matrix from the data in the vertexgroup */ - /* TODO: will be handled in other files */ + /* Current method just takes the average location of all the points in the + * VertexGroup, and uses that as the location value of the target's matrix + * instead. + * + * TODO: figure out a way to find 3-points to define a rotation plane based + * on the normal of the triangle formed by those three points. + * NOTE: editmode is not currently taken into consideration when doing this + */ + else if (ob->type == OB_MESH) { + /* devise a matrix from the vertices in the vertexgroup */ + contarget_get_mesh_mat(ob, substring, mat); + + /* make sure it's in the right space for evaluation */ + constraint_mat_convertspace(ob, NULL, mat, from, to); + } + else if (ob->type == OB_LATTICE) { + /* devise a matrix from the vertices in the vertexgroup */ + contarget_get_lattice_mat(ob, substring, mat); + + /* make sure it's in the right space for evaluation */ + constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case BONE */ else { @@ -1313,7 +1438,10 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void *own Object *ob= data->tar; if (data->tar) { - if (strlen(data->subtarget)) { + if (data->tar->type==OB_ARMATURE && strlen(data->subtarget)) { + /* Pose-Channels for the CopyLoc target are handled specially, so that + * we can support using the bone-tip as an option. + */ bPoseChannel *pchan; float tmat[4][4]; @@ -1334,10 +1462,8 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void *own constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); } else { - Mat4CpyMat4(mat, ob->obmat); - - /* convert matrix space as required */ - constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); + /* get target matrix as is done normally for other constraints */ + constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); } valid=1; } @@ -2664,10 +2790,10 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) /* value should have been set from IPO's/Constraint Channels already */ enf = con->enforce; - /* move target/owner into right spaces */ + /* move owner into right space */ constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); - /* Get the target matrix */ + /* Get the target matrix - in right space to be used */ ownerdata= ((cob->pchan)? (void *)cob->pchan : (void *)cob->ob); get_constraint_target_matrix(con, cob->type, ownerdata, tarmat, ctime); diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index aa6220e88bc..9356ba14071 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -113,14 +113,31 @@ bDeformGroup *get_named_vertexgroup (Object *ob, char *name) return NULL; } -int get_defgroup_num (Object *ob, bDeformGroup *dg) +int get_named_vertexgroup_num (Object *ob, char *name) +{ + /* Return the location of the named deform group within the list of + * deform groups. This function is a combination of get_defgroup_num and + * get_named_vertexgroup. The other two could be called instead, but that + * require looping over the vertexgroups twice. + */ + bDeformGroup *curdef; + int def_nr; + + for (curdef=ob->defbase.first, def_nr=0; curdef; curdef=curdef->next, def_nr++) { + if (!strcmp(curdef->name, name)) + return def_nr; + } + + return -1; +} + +int get_defgroup_num (Object *ob, bDeformGroup *dg) { /* Fetch the location of this deform group * within the linked list of deform groups. * (this number is stored in the deform * weights of the deform verts to link them - * to this deform group) deform deform - * deform blah blah deform + * to this deform group). */ bDeformGroup *eg; @@ -129,8 +146,7 @@ int get_defgroup_num (Object *ob, bDeformGroup *dg) eg = ob->defbase.first; def_nr = 0; - /* loop through all deform groups - */ + /* loop through all deform groups */ while (eg != NULL) { /* if the current deform group is diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index e59d39c41f5..684d4ceca51 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -540,12 +540,13 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiBut *but; char typestr[64], *subtarget; short height, width = 265; - short is_armature_target, is_armature_owner; + short is_armature_target, is_geom_target, is_armature_owner; int rb_col; target= get_constraint_target(con, &subtarget); is_armature_target= (target && target->type==OB_ARMATURE); is_armature_owner= ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE)); + is_geom_target= (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) ); /* unless button has own callback, it adds this callback to button */ uiBlockSetFunc(block, constraint_active_func, ob, con); @@ -639,6 +640,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -737,6 +742,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -791,6 +800,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -834,6 +847,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -872,6 +889,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -908,6 +929,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -944,6 +969,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -998,6 +1027,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -1035,6 +1068,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -1116,6 +1153,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy (data->subtarget, ""); } @@ -1403,6 +1444,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); } + else if (is_geom_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } else { strcpy(data->subtarget, ""); } |