forked from bartvdbraak/blender
== 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)
This commit is contained in:
parent
4d884c0fbf
commit
400d77bbe2
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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, "");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user