From e492fad1308d5072a34abb3a90790a1106eea32b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 7 Sep 2013 12:59:16 +0000 Subject: [PATCH] shrink-wrap constraint, improve and remove some limitations. - ability to change the space the axis is projected in (so you can choose worldspace or -space, was always local-space before). - support projecting on a negative axis, without this some very simple clamping is not possible if the direction happened not to be positive. - add distance limit (same as modifier), without this single meshes surrounding an object would make the constraint impossible to use in some cases (it would snap to the wrong side). note: this removes the ability to project on multiple axes at once but this option only added up directions and didnt project on multiple axes as you might expect. --- .../startup/bl_ui/properties_constraint.py | 9 ++- source/blender/blenkernel/BKE_blender.h | 2 +- source/blender/blenkernel/BKE_shrinkwrap.h | 6 +- source/blender/blenkernel/intern/constraint.c | 68 +++++++++++++------ source/blender/blenkernel/intern/shrinkwrap.c | 32 ++++----- source/blender/blenloader/intern/readfile.c | 19 +++++- .../blender/makesdna/DNA_constraint_types.h | 6 +- .../blender/makesrna/intern/rna_constraint.c | 30 ++++---- 8 files changed, 111 insertions(+), 61 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 5bb9c151c2c..4ad178bc064 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -726,9 +726,12 @@ class ConstraintButtonsPanel(): if con.shrinkwrap_type == 'PROJECT': row = layout.row(align=True) - row.prop(con, "use_x") - row.prop(con, "use_y") - row.prop(con, "use_z") + row.prop(con, "project_axis", expand=True) + split = layout.split(percentage=0.4) + split.label(text="Axis Space:") + rowsub = split.row() + rowsub.prop(con, "project_axis_space", text="") + layout.prop(con, "project_limit") def DAMPED_TRACK(self, context, layout, con): self.target_template(layout, con) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 13fd4b2bab7..6507999e9db 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 268 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 61d82e6c604..323a926863c 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -134,9 +134,9 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object * Thus it provides an easy way to cast the same ray across several trees * (where each tree was built on its own coords space) */ -int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata); +int BKE_shrinkwrap_project_normal(char options, const float vert[3], const float dir[3], + const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata); /* * NULL initializers to local data diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7b7d20a54e0..1f892432d80 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3308,6 +3308,14 @@ static void shrinkwrap_id_looper(bConstraint *con, ConstraintIDFunc func, void * func(con, (ID **)&data->target, FALSE, userdata); } +static void shrinkwrap_new_data(void *cdata) +{ + bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata; + + data->projAxis = OB_POSZ; + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; +} + static int shrinkwrap_get_tars(bConstraint *con, ListBase *list) { if (con && list) { @@ -3339,24 +3347,14 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) { - int fail = FALSE; + bool fail = false; float co[3] = {0.0f, 0.0f, 0.0f}; - float no[3] = {0.0f, 0.0f, 0.0f}; - float dist; SpaceTransform transform; DerivedMesh *target = object_get_derived_final(ct->tar); - BVHTreeRayHit hit; - BVHTreeNearest nearest; BVHTreeFromMesh treeData = {NULL}; - nearest.index = -1; - nearest.dist = FLT_MAX; - - hit.index = -1; - hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it - unit_m4(ct->matrix); if (target != NULL) { @@ -3365,7 +3363,13 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: case MOD_SHRINKWRAP_NEAREST_VERTEX: - + { + BVHTreeNearest nearest; + float dist; + + nearest.index = -1; + nearest.dist = FLT_MAX; + if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); else @@ -3386,30 +3390,54 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra } space_transform_invert(&transform, co); break; - + } case MOD_SHRINKWRAP_PROJECT: - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; + { + BVHTreeRayHit hit; + + float mat[4][4]; + float no[3] = {0.0f, 0.0f, 0.0f}; + + /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */ + hit.index = -1; + hit.dist = (scon->projLimit == 0.0f) ? 100000.0f : scon->projLimit; + + switch (scon->projAxis) { + case OB_POSX: case OB_POSY: case OB_POSZ: + no[scon->projAxis - OB_POSX] = 1.0f; + break; + case OB_NEGX: case OB_NEGY: case OB_NEGZ: + no[scon->projAxis - OB_NEGX] = -1.0f; + break; + } + /* transform normal into requested space */ + unit_m4(mat); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace); + invert_m4(mat); + mul_mat3_m4_v3(mat, no); + if (normalize_v3(no) < FLT_EPSILON) { fail = TRUE; break; } - - + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); if (treeData.tree == NULL) { fail = TRUE; break; } + - if (normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) { + if (BKE_shrinkwrap_project_normal(0, co, no, &transform, treeData.tree, &hit, + treeData.raycast_callback, &treeData) == false) + { fail = TRUE; break; } copy_v3_v3(co, hit.co); break; + } } free_bvhtree_from_mesh(&treeData); @@ -3446,7 +3474,7 @@ static bConstraintTypeInfo CTI_SHRINKWRAP = { NULL, /* free data */ shrinkwrap_id_looper, /* id looper */ NULL, /* copy data */ - NULL, /* new data */ + shrinkwrap_new_data, /* new data */ shrinkwrap_get_tars, /* get constraint targets */ shrinkwrap_flush_tars, /* flush constraint targets */ shrinkwrap_get_tarmat, /* get a target matrix */ diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index b9843ad0619..9bc7f4b9e2b 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -198,10 +198,10 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) * MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored) * MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored) */ -int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, - BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata) +int BKE_shrinkwrap_project_normal(char options, const float vert[3], + const float dir[3], const SpaceTransform *transf, + BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata) { /* don't use this because this dist value could be incompatible * this value used by the callback for comparing prev/new dist values. @@ -368,14 +368,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if (use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { if (auxData.tree) { - normal_projection_project_vertex(0, tmp_co, tmp_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, + &local2aux, auxData.tree, &hit, + auxData.raycast_callback, &auxData); } - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no, + &calc->local2target, treeData.tree, &hit, + treeData.raycast_callback, &treeData); } /* Project over negative direction of axis */ @@ -384,14 +384,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) negate_v3_v3(inv_no, tmp_no); if (auxData.tree) { - normal_projection_project_vertex(0, tmp_co, inv_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, + &local2aux, auxData.tree, &hit, + auxData.raycast_callback, &auxData); } - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no, + &calc->local2target, treeData.tree, &hit, + treeData.raycast_callback, &treeData); } /* don't set the initial dist (which is more efficient), diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 0cd473fd74d..af2da2361d3 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9530,8 +9530,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - if (MAIN_VERSION_OLDER(main, 267, 1)) - { + if (MAIN_VERSION_OLDER(main, 267, 1)) { Object *ob; for (ob = main->object.first; ob; ob = ob->id.next) { @@ -9575,10 +9574,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main) #undef BRUSH_FIXED } - { + + if (!MAIN_VERSION_ATLEAST(main, 268, 4)) { bScreen *sc; Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + bConstraint *con; + for (con = ob->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { + bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)con->data; + if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) data->projAxis = OB_POSX; + else if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) data->projAxis = OB_POSY; + else data->projAxis = OB_POSZ; + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; + } + } + } + for (ob = main->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index f1b7a7c3cc3..29e49a970d8 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -407,8 +407,10 @@ typedef struct bShrinkwrapConstraint { struct Object *target; float dist; /* distance to kept from target */ short shrinkType; /* shrink type (look on MOD shrinkwrap for values) */ - char projAxis; /* axis to project over UP_X, UP_Y, UP_Z */ - char pad[9]; + char projAxis; /* axis to project/constrain */ + char projAxisSpace; /* space to project axis in */ + float projLimit; /* distance to search */ + char pad[4]; } bShrinkwrapConstraint; /* Follow Track constraints */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 6a1aa37d0cc..8c7857a3f0b 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -37,6 +37,7 @@ #include "DNA_scene_types.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -2025,20 +2026,23 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 100.f); RNA_def_property_ui_text(prop, "Distance", "Distance to Target"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS); - RNA_def_property_ui_text(prop, "Axis X", "Projection over X Axis"); + + prop = RNA_def_property(srna, "project_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "projAxis"); + RNA_def_property_enum_items(prop, object_axis_items); + RNA_def_property_ui_text(prop, "Project Axis", "Axis constrain to"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_y", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS); - RNA_def_property_ui_text(prop, "Axis Y", "Projection over Y Axis"); - RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_z", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS); - RNA_def_property_ui_text(prop, "Axis Z", "Projection over Z Axis"); + + prop = RNA_def_property(srna, "project_axis_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "projAxisSpace"); + RNA_def_property_enum_items(prop, owner_space_pchan_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Constraint_owner_space_itemf"); + RNA_def_property_ui_text(prop, "Axis Space", "Space for the projection axis"); + + prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "projLimit"); + RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_ui_text(prop, "Project Distance", "Limit the distance used for projection (zero disables)"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); }